Data
name 'chan' value 'a'
name 'chan' value 'b'
name 'max' value 'a'
name 'max' value 'b'
name 'tony' value 'a'
name 'tony' value 'c'
I need to find out user who both have value a and b, this is my solution:
SELECT * FROM `table`
GROUP BY `name`
HAVING SUM(IF(`value` = 'a', 1, 0)) >= 1 AND SUM(IF(`value` = 'b', 1, 0)) >= 1
Any better way?
Your solution is ok, but it would be better written as:
SELECT name
FROM `table`
GROUP BY `name`
HAVING SUM(`value` = 'a') >= 1 AND SUM(`value` = 'b') >= 1;
A possibly more efficient form is:
SELECT name
FROM `table`
WHERE value in ('a', 'b')
GROUP BY `name`
HAVING COUNT(DISTINCT value) = 2;
And, depending on your data structure and indexes and size, this could also be efficient:
select ta.name
from table ta join
table tb
on ta.name = tb.name and ta.value = 'a' and tb.value = 'b';
I prefer the methods using group by and having because they generalize to a more diverse set of conditions.
Try this out. a DISTINCT is required if name per value in not unique.
eg (COUNT(DISTINCT value) = 2)
SELECT name
FROM tableName
WHERE value IN ('a', 'b')
GROUP BY name
HAVING COUNT(*) = 2
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;
now i have a table test_table with some data like this:
(id-type is a unique index)
id
type
value
1
x
a
1
y
b
2
x
aa
and with the sql:
SELECT id,
group_concat(IF(type = 'x', value, NULL) SEPARATOR '') AS 'x',
group_concat(IF(type = 'y', value, NULL) SEPARATOR '') AS 'y'
FROM test_table
GROUP BY id;
i get the result like this:
id
x
y
1
a
b
2
aa
null
it makes the 'type' to be a colume.
so this is a better way to get the same result?
a better sql to implements my question~
Use conditional aggregation:
SELECT
id,
MAX(CASE WHEN type = 'x' THEN value END) AS x,
MAX(CASE WHEN type = 'y' THEN value END) AS y
FROM test_table
GROUP BY id
ORDER BY id;
I have below table and SQL query written, this query should not return any result but its returning ID = 1 , what is wrong with the SQL query? Can anyone please help?
** Note balance data type is decimal rest are varchar
ID code balance level
1 C 150.00
1 P 40027.42 F
1 P 40027.42 F
select distinct ID from table
(
(code = 'P' and balance = 40027.42 and level = 'F') or
(code = 'C' and balance = 151.00 )
)
group by ID
having count(ID) >=2
If you do not want to count the same code twice, you can use count(distinct code):
select ID
from t
where (code = 'P' and balance = 40027.42 and level = 'F')
or (code = 'C' and balance = 151.00 )
group by ID
having count(distinct code) >=2
If you want to only count a distinct set of values once, you can use a derived table/subquery to select distinct rows:
select ID
from (
select distinct id, code, balance, level
from t
) as s
where (code = 'P' and balance = 40027.42 and level = 'F')
or (code = 'C' and balance = 151.00 )
group by ID
having count(ID) >=2
rextester demo for both: http://rextester.com/LBKO57534
I need to select some columns from a table and also some other columns depending on a value from one column. For example:
SELECT
col_a, col_b, col_c
FROM user_table
INNER JOIN col_d, col_e, col_f ON col_type = 1
INNER JOIN col_g, col_h, col_i ON col_type = 2
WHERE id = :id
AND active = 1
Since I'm new to mysql, I don't how how i should do this. I tried using CASE WHEN but was able to select a single column and I need to select multiple columns.
I think you misunterstood INNER JOIN and you want something like that
SELECT
col_a, col_b, col_c,
IF( col_type = 1, col_d, NULL ) AS col_d,
IF( col_type = 1, col_e, NULL ) AS col_e,
IF( col_type = 2, col_g, NULL ) AS col_g,
IF( col_type = 2, col_h, NULL ) AS col_h
FROM user_table
WHERE id = :id
AND active = 1
But i prefere to load all cols and handle it with your other language (PHP?).
I'm trying to insert a record if a sum of 3 user columns from 2 tables exceeds a constant.
I've searched all over, found you can't put user variables in IFs, WHERE's etc. Found you can't put SUMs in IFs, WHERE's etc. I'm at a total loss. Here's an example of my earlier bad code before unsuccessfully trying to use SUMs in WHEREs, if it helps:
SELECT SUM(num1) INTO #mun1 FROM table1 WHERE user = '0';
SELECT SUM(num2) INTO #mun2 FROM table1 WHERE user = '0';
SELECT SUM(num3) INTO #mun3 FROM table2 WHERE column1 = 'd' AND user = '0';
SET #mun4 = #mun1 - #mun2 - #mun3;
INSERT INTO table2 (user, column1, column2) VALUES ('0', 'd', '100') WHERE #mun4 >= 100;
Try this:
INSERT INTO table2 (user, column1, column2)
select '0', 'd', '100'
from dual
where (SELECT SUM(num1 + num2) FROM table1 WHERE user = '0') +
(SELECT SUM(num3) FROM table2 WHERE column1 = 'd' AND user = '0') > 100;
This is a case of the general solution for a "insert if condition" problem:
insert into ... select ... where condition
The select will only return rows if the condition is true, and importantly, will return no rows if false - meaning the insert only happens if the condition is true, otherwise nothing happens.
This is same as #Bohemian's answer, but you got to add a LIMIT clause to stop inserting multiple records, since select clause may return multiple records
INSERT INTO table2 (user, column1, column2)
SELECT '0', 'd', '100'
FROM dual
WHERE
(SELECT SUM(num1 - num2) FROM table1 WHERE user = '0')
(SELECT SUM(num3) FROM table2 WHERE column1 = 'd' AND user = '0') >
100
LIMIT 1