I have a column with complex user id. I want to replace the text within my select query.
This creates a new column as updated_by for every single value. I want them to be replaced in a single column. How can I achieve this?
select replace(updated_by, '5eaf5d368141560012161636', 'A'),
replace(updated_by, '5e79d03e9abae00012ffdbb3', 'B'),
replace(updated_by, '5e7b501e9abae00012ffdbd6', 'C'),
replace(updated_by, '5e7b5b199abae00012ffdbde', 'D'),
replace(updated_by, '5e7c817c9ca5540012ea6cba', 'E'),
updated_by
from my_table
GROUP BY updated_by;
In Postgres I would use a VALUES expression to form a derived table:
To just select:
SELECT *
FROM my_table m
JOIN (
VALUES
('5eaf5d368141560012161636', 'A')
, ('5e79d03e9abae00012ffdbb3', 'B')
, ('5e7b501e9abae00012ffdbd6', 'C')
, ('5e7b5b199abae00012ffdbde', 'D')
, ('5e7c817c9ca5540012ea6cba', 'E')
) u(updated_by, new_value) USING (updated_by);
Or LEFT JOIN to include rows without replacement.
You may need explicit type casts with non-default data types. See:
Casting NULL type when updating multiple rows
For repeated use, create a persisted translation table.
CREATE TABLE updated_by_translation (updated_by text PRIMARY KEY, new_value text);
INSERT INTO my_table
VALUES
('5eaf5d368141560012161636', 'A')
, ('5e79d03e9abae00012ffdbb3', 'B')
, ('5e7b501e9abae00012ffdbd6', 'C')
, ('5e7b5b199abae00012ffdbde', 'D')
, ('5e7c817c9ca5540012ea6cba', 'E')
;
Data types and constraints according to your actual use case.
SELECT *
FROM my_table m
LEFT JOIN updated_by_translation u USING (updated_by);
MySQL recently added a VALUES statement, too. The manual:
VALUES is a DML statement introduced in MySQL 8.0.19
But it requires the keyword ROW for every row. So:
...
VALUES
ROW('5eaf5d368141560012161636', 'A')
, ROW('5e79d03e9abae00012ffdbb3', 'B')
, ROW('5e7b501e9abae00012ffdbd6', 'C')
, ROW('5e7b5b199abae00012ffdbde', 'D')
, ROW('5e7c817c9ca5540012ea6cba', 'E')
...
Use case:
select case updated_by
when '5eaf5d368141560012161636' then 'A'
when '5e79d03e9abae00012ffdbb3' then 'B'
when '5e7b501e9abae00012ffdbd6' then 'C'
when '5e7b5b199abae00012ffdbde' then 'D'
when '5e7c817c9ca5540012ea6cba' then 'E'
end as updated_by
from my_table
This has to be nested liek this
SELECT
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(updated_by,
'5e7c817c9ca5540012ea6cba',
'E'),
'5e7b5b199abae00012ffdbde',
'D'),
'5e7b501e9abae00012ffdbd6',
'C'),
'5e79d03e9abae00012ffdbb3',
'B'),
'5eaf5d368141560012161636',
'A'),
updated_by
FROM
my_table
GROUP BY updated_by
This will replace all occurring, patterns, if they are not foung nothing happens
You can use a recursive CTE if you need to handle multiple values within a single row:
with replacements as (
select '5eaf5d368141560012161636' as oldval, 'A' as newval union all
select '5e79d03e9abae00012ffdbb3' as oldval, 'B' union all
select '5e7b501e9abae00012ffdbd6' as oldval, 'C' union all
select '5e7b5b199abae00012ffdbde' as oldval, 'D' union all
select '5e7c817c9ca5540012ea6cba' as oldval, 'E'
),
r as (
select r.*, row_number() over (order by oldval) as seqnum
from replacements r
),
recursive cte (
select r.seqnum, replace(t.updated_by, r.oldval, r.newval) as updated_by
from my_table t join
r
on r.seqnum = 1
union all
select r.seqnum, replace(cte.updated_by, r.oldval, r.newval) as updated_by
from cte t join
r
on r.seqnum = cte.seqnum + 1
)
select cte.*
from cte
where seqnum = (select count(*) from replacements);
Related
I need to make a query that selects a grouped collection of rows from a table based on user input conditions, and then in the select i will sum data from a subset of the rows.
The setup is rather expansive to describe in a post, so here is a demostration of the problem in the simplest way i can make it:
We have this table: DemoTable
ID
StaticKey
GroupKey
Value
1
A
A
2
2
A
A
2
3
A
B
2
4
A
B
2
5
A
C
2
6
A
C
2
I make a select and groups on "StaticKey".
What i would then like to do, is to, in the select clause, to select the sum of a subset of the values from the groupped data:
select
DT.GroupKey,
(select sum(D.Value) from DemoTable D where D.ID in (DT.ID) and D.GroupKey = 'A') as 'Sum of A''s',
(select COUNT(D.ID) from DemoTable D where D.ID in (DT.ID) and D.GroupKey = 'A') as 'Count of A''s'
from DemoTable DT
group by DT.StaticKey;
I hoped that the sum would result in a sum of 4 and a count of 2, but i get 2 and 1. So the input to the "select sum" seems to be just one id and not the collected ids.
GroupKey
Sum of A's
Count of A's
A
2
1
If i add a group_concat of DT.ID i get them comma separated - but is it posible to get them as a collection i can use as input to the selects?
Heres sql to create the table and queries:
CREATE TABLE DemoTable
(
ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
GroupKey varchar(200) null default null,
StaticKey varchar(200) not null default 'A',
Value varchar(200) null default null,
PRIMARY KEY (ID)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
insert into DemoTable (GroupKey, Value) values ('A', 2);
insert into DemoTable (GroupKey, Value) values ('A', 2);
insert into DemoTable (GroupKey, Value) values ('B', 2);
insert into DemoTable (GroupKey, Value) values ('B', 2);
insert into DemoTable (GroupKey, Value) values ('C', 2);
insert into DemoTable (GroupKey, Value) values ('C', 2);
select DT.GroupKey,
(select sum(D.Value) from DemoTable D where D.ID in (DT.ID) and D.GroupKey = 'A') as 'Sum of A''s',
(select COUNT(D.ID) from DemoTable D where D.ID in (DT.ID) and D.GroupKey = 'A') as 'Count of A''s'
from DemoTable DT
group by DT.StaticKey;
DROP TABLE DemoTable;
More simple:
select GroupKey,
sum(Value) as sum_of_A,
sum(GroupKey='A') as count_of_A
from DemoTable
where GroupKey='A'
group by GroupKey;
https://dbfiddle.uk/sdYlTw57
Isn't it always D.ID in (DT.ID)?
select
DT.GroupKey,
(select sum(D.Value) from DemoTable D where D.GroupKey = 'A') as 'Sum of A''s',
(select COUNT(D.ID) from DemoTable D where D.GroupKey = 'A') as 'Count of A''s'
from DemoTable DT
group by DT.StaticKey;
It does the job but perhaps it's too simple...
You can also try this.
SELECT DT.GroupKey,
SUM(DT.Value) AS 'Sum of A''s',
COUNT(DT.ID) AS 'Count of A''s'
FROM DemoTable DT
WHERE DT.GroupKey = 'A'
GROUP BY DT.StaticKey;
I want to get the average number (Attendee NPS) from a SQL table I've already put together.
I've encased the initial table in a new select statement so I can take the average of distinct values. Is there something in my Join clause that is preventing this from working?
Im getting the following error:
ERROR: missing FROM-clause entry for table "gizmo" Position: 12
SELECT
avg(bigtable.gizmo.attendee_nps)
FROM
(
SELECT DISTINCT
attendee_survey_results.swoop_event_id AS "Swoop ID",
attendee_survey_results.startup_weekend_city AS "SW City",
swooptable.start_date AS "Date",
gizmo.attendee_nps AS "Attendee NPS"
FROM attendee_survey_results
JOIN
(
SELECT
swoop_event_id,
(
100 * count(CASE WHEN attendee_nps >= 9 THEN 1 END)
/ count(attendee_nps)
- 100 * count(CASE WHEN attendee_nps <= 6 THEN 1 END)
/ count(attendee_nps)
) AS "attendee_nps"
FROM attendee_survey_results
GROUP BY swoop_event_id
) AS "gizmo"
ON gizmo.swoop_event_id = attendee_survey_results.swoop_event_id
JOIN
(
SELECT eid,start_date,manager_email
FROM events
) AS "swooptable"
ON gizmo.swoop_event_id = swooptable.eid
) AS bigtable
[edit, ok you don't have a single problem, but the request at the bottom should work]
3 part notation bigtable.gizmo.attendee_nps
You can't use this bigtable.gizmo.attendee_nps, this is the "with DB" specific syntax : db_name.tbl_name.col_name.
You should use a table_or_alias.col_name_or_alias notation
In sub query you loose the deep table name of every deep-1 :
-- with the deep explicite
SELECT `d0`.`new_field`
FROM (
-- implicite `d1` table
SELECT `new_field`
FROM (
-- with the deep `d2` explicite and alias of field
SELECT `d2`.`field` AS `new_field`
FROM (
-- without the explicite `d3` table and `field` field
SELECT *
FROM (
-- output a `field` => 12
SELECT 12 as `field`
) AS `d3`
) AS `d2`
) AS `d1`
) AS `d0`
-- print `new_field` => 12
Access deep-1 aliased field
SELECT `attendee_nps`
FROM
(
SELECT `attendee_nps` AS `new_alias_field`
FROM attendee_survey_results
) AS bigtable
Unknown column 'attendee_nps' in 'field list'
When you make a field alias in deep-1 query, deep-0 can only access the alias new_alias_field, the original field no longer exist.
Double quote " table alias
FROM (
-- ...
) AS "bigtable"
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"bigtable"' at line N
MySql don't allow the use of " to make table alias (it's technically ok for field alias).
You should use the mysql back quote to escape table alias name, like AS `My Table Alias`
Correct query :
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE events
(`eid` int, `start_date` varchar(10), `manager_email` varchar(15))
;
INSERT INTO events
(`eid`, `start_date`, `manager_email`)
VALUES
(1, '2016-11-11', 'mail_1#mail.com'),
(2, '2016-11-12', 'mail_2#mail.com'),
(3, '2016-11-13', 'mail_3#mail.com'),
(4, '2016-11-14', 'mail_4#mail.com'),
(5, '2016-11-15', 'mail_5#mail.com'),
(6, '2016-11-16', 'mail_6#mail.com'),
(7, '2016-11-17', 'mail_7#mail.com')
;
CREATE TABLE attendee_survey_results
(`id` int, `swoop_event_id` int, `startup_weekend_city` varchar(6), `attendee_nps` int)
;
INSERT INTO attendee_survey_results
(`id`, `swoop_event_id`, `startup_weekend_city`, `attendee_nps`)
VALUES
(1, 1, 'city_1', 1),
(2, 2, 'city_2', 22),
(3, 3, 'city_3', 3),
(4, 1, 'city_4', 4),
(5, 2, 'city_5', 5),
(6, 3, 'city_6', 9),
(7, 7, 'city_7', 17)
;
Query 1:
SELECT
AVG(`bigtable`.`attendee_nps`)
FROM
(
SELECT DISTINCT
`asr`.`swoop_event_id` AS `Swoop ID`,
`asr`.`startup_weekend_city` AS `SW City`,
`swooptable`.`start_date` AS `date`,
`gizmo`.`attendee_nps` AS `attendee_nps`
FROM `attendee_survey_results` AS `asr`
JOIN
(
SELECT
`swoop_event_id`,
(
100 * count(CASE WHEN `attendee_nps` >= 9 THEN 1 END)
/ count(`attendee_nps`)
- 100 * count(CASE WHEN `attendee_nps` <= 6 THEN 1 END)
/ count(`attendee_nps`)
) AS `attendee_nps`
FROM `attendee_survey_results`
GROUP BY `swoop_event_id`
) AS `gizmo`
ON `gizmo`.`swoop_event_id` = `asr`.`swoop_event_id`
JOIN
(
SELECT `eid`, `start_date`, `manager_email`
FROM `events`
) AS `swooptable`
ON `gizmo`.`swoop_event_id` = `swooptable`.`eid`
) AS `bigtable`
Results:
| AVG(`bigtable`.`attendee_nps`) |
|--------------------------------|
| -14.28571429 |
Why this does not give any records in sql server 2008?
;with pricedCategories as
(
select * from Product.Category where CategoryID not in
(select Parent_CategoryID from Product.Category)
)
select * from pricedCategories
It seems that your query doesn't return values when there are NULL values in subquery inside CTE (if I replace NULL in insert (1, NULL) with let's say (1, 0) your query will work). If you want to get the categories that are not any other category's parents even with NULL values, you can do it like this:
DECLARE #Category TABLE (CategoryID INT, Parent_CategoryID INT)
INSERT #Category VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 2)
;WITH pricedCategories AS
(
SELECT * FROM #Category y WHERE NOT EXISTS
(SELECT Parent_CategoryID FROM #Category x
WHERE x.Parent_CategoryID = y.CategoryID)
)
SELECT * FROM pricedCategories
It is interesting to see that the following approach works the same as the approach described in your question:
;WITH pricedCategories AS
(
SELECT * FROM #Category y
WHERE y.CategoryID <> ALL(SELECT DISTINCT Parent_CategoryID FROM #Category)
)
SELECT * FROM pricedCategories
You could change your query to use the ISNULL function to replace NULL with some numeric value that is never used as CategoryID, like this:
;WITH pricedCategories AS
(
SELECT * FROM #Category WHERE CategoryID NOT IN
(SELECT ISNULL(Parent_CategoryID, -1) FROM #Category)
)
SELECT * FROM pricedCategories
But then the NULL value which means "nothing" would be changed to actual value of -1 which is not true and you shouldn't use it.
If you will look at the image above. I need to update this table for the null values of the TID which is column third in the table, with the values in between two rows that actually has value.
So in the above example, I need to have rows 44-57 as 040, row 60-87 as 077 etc. One pattern that could be used is that column 2 has INS in the string, which denotes that the value in column 3 is to be changed. So I was thinking about using DATA LIKE 'INS%' in some way.
Please let me know what you think of the problem and any possible solutions.
thanks!
DECLARE #x TABLE
(Column1 INT, Column2 VARCHAR(64), TID VARCHAR(10));
INSERT #x VALUES
(42, 'INS{whatever}', '040'),
(43, 'somethingelse', '040'),
(44, 'somethingelse', NULL),
(45, 'somethingelse', NULL),
(46, 'somethingelse', NULL),
(47, 'somethingelse', NULL),
(48, 'somethingelse', NULL),
(49, 'INS{whatever}', '077'),
(50, 'somethingelse', '077'),
(51, 'somethingelse', NULL),
(52, 'somethingelse', NULL);
;WITH x AS (SELECT i = Column1, TID, rn = ROW_NUMBER() OVER (ORDER BY Column1)
FROM #x WHERE Column2 LIKE 'INS%'
),
y AS (SELECT x.TID, s = x.i, e = COALESCE(x2.i, 2000000000)
FROM x LEFT OUTER JOIN x AS x2 ON x.rn = x2.rn -1
)
UPDATE src SET TID = y.TID
FROM #x AS src
INNER JOIN y ON src.Column1 > y.s AND src.Column1 < y.e;
SELECT * FROM #x;
This assumes that:
The first two columns in your sample were duplicated (I ignore the first listed)
Col1 is a primary key
Values are to be assigned as you described based on ascending values in Col1
Performance might be bad to very bad on large tables
Performance would improve with suitable indexing (on Col1 and Col3)
Substitute in your table and column names, and check for minor typos.
UPDATE MyTable
set Col3 = mt2.Col3
from MyTable mt
inner join (-- Get the "earlier" Col3 value for each row that has no value
select t1.Col1, max(t2.Col1) EarlierValueHere
from MyTable t1
inner join MyTable t2
on t2.Col1 < t1.Col1
and t2.Col3 is not null
group by t1.Col1
where t1.Col3 is null) earlier
on earlier.Col1 = mt.Col1
inner join MyTable mt2
on mt2.Col1 = earlier.EarlierValueHere
Another query you might use:
update t set TID = X.NonNullTID
from [YourTable] t
join
(select
t1.Column1, t1.Column2, t1.TID,
(select top 1 tid from [YourTable]
where TID is not null and Column1 <= t1.Column1
order by Column1 desc) as NonNullTID
from [YourTable] t1) X
on X.Column1 = t.Column1
What is wrong with this query?
SELECT *, (SELECT COUNT(*)
FROM
(
SELECT NULL
FROM words
WHERE project=projects.id
GROUP BY word
HAVING COUNT(*) > 1
) T1) FROM projects
MySQL returns 1054 Unknown column 'projects.id' in 'where clause'
Thanks
Does this work?
SELECT *, (SELECT COUNT(*)
FROM words
WHERE words.project=projects.id) as pCount
FROM projects
Your inner subquery knows nothing about the outer query, so the projects table is not available.
It looks like you are trying to count for each project the number of words which occur more than once.
You can run your subquery for all projects and then use a JOIN to get the rest of the data from the projects table:
SELECT projects.*, COUNT(word) AS cnt
FROM projects
LEFT JOIN (
SELECT project, word
FROM words
GROUP BY project, word
HAVING COUNT(*) > 1
) T1
ON T1.project = projects.id
GROUP BY projects.id
Result:
id cnt
1 0
2 1
3 2
Test data:
CREATE TABLE projects (id INT NOT NULL);
INSERT INTO projects (id) VALUES (1), (2), (3);
CREATE TABLE words (project INT NOT NULL, word VARCHAR(100) NOT NULL);
INSERT INTO words (project, word) VALUES
(1, 'a'),
(2, 'a'),
(2, 'b'),
(2, 'b'),
(3, 'b'),
(3, 'b'),
(3, 'c'),
(3, 'c');