I have a table like this
NAME FLAG
---------------------------
abc 1
abc 0
abc 2
def 1
def 2
xyz 0
xyz 0
xyz 1
efg 1
I need query that list the name (group the result) which flag not included 0 and included 1.The result simply like below:-
NAME FLAG
------------------
def 1
efg 1
I have tried the query but not results the same.
select * mytable where FLAG NOT IN (0) GROUP BY NAME;
This is the simplest solution I can come up with. I believe there are more elegant answers possible.
SELECT *
FROM mytable
WHERE name NOT IN (SELECT name FROM mytable WHERE flag = 0)
AND flag = 1;
You can use NOT EXISTS clause in this way.
select a.*
from tbl a
where not exists
(select *
from tbl b
where b.name=a.name
and b.flag=0)
and a.flag=1;
We can use aggregation. The trick is to run a condition on each row, and then use an aggregate function to pick out the net result of the condition from all of the rows...
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX(t.flag=0) <> 1
AND MAX(t.flag=1) = 1
The expressions in the HAVING clause are MySQL shorthand.
A more ANSI standards compliant equivalent would be:
SELECT t.name
FROM a_table_like_this t
GROUP BY t.name
HAVING MAX( CASE WHEN t.flag=0 THEN 1 ELSE 0 END) <> 1
AND MAX( CASE WHEN t.flag=1 THEN 1 ELSE 0 END) = 1
To get a better handle on what this is doing, take a look at how those expressions are evaluated on each row. Remove the GROUP BY clause, and move those expressions into the SELECT list...
SELECT t.name
, t.flag
, CASE WHEN t.flag=0 THEN 1 ELSE 0 END AS `fl=0`
, CASE WHEN t.flag=1 THEN 1 ELSE 0 END AS `fl=1`
FROM a_table_like_this t
ORDER
BY t.name
, t.flag
We get something like
name flag fl=0 fl=1
------ ---- ---- ----
abc 1 0 1
abc 0 1 0
abc 2 0 0
def 1 0 1
def 2 0 0
xyz 0 1 0
xyz 0 1 0
xyz 1 0 1
efg 1 0 1
If we now aggregate these rows by name (GROUP BY name), we can use MAX() aggregate to pick out a 1 (if there's one in the group. Otherwise, we'll get back a 0.)
And we can do conditional tests on the results of aggregates functions in the HAVING clause.
Related
I have a table which links users to groups which is set up as below:
I would like to know if there is a method to select all groupIDs (column names) where a certain condition is met.
E.g. if I want to find all groups where user 2 has a level greater than 0 it would return (1,2,4)
It is also worth noting it cannot be done manually as there is roughly 5000 rows and 120 columns
Thanks for any help!
You can unpivot and search with union all. Assuming that the columns of your table are called grp1 to grp5:
select 1 as grp from t where userid = 2 and grp1 > 0
union all select 2 from t where userid = 2 and grp2 > 0
union all select 3 from t where userid = 2 and grp3 > 0
union all select 4 from t where userid = 2 and grp4 > 0
union all select 5 from t where userid = 2 and grp5 > 0
You should consider fixing your data model. Each user/group tuple should be stored in a separate row in a bridge table, like so:
user_groups:
userid grp val
1 1 3
1 2 2
1 3 2
1 4 2
1 5 0
...
Then, the query is as simple as:
select grp from user_groups where userid = 2 and val > 0
something like this
select distinct group from (
select group1 group from t where level > 0
union
select group2 from t where level > 0
union
select group3 from t where level > 0
union
select group4 from t where level > 0
union
select group5 from t where level > 0
)
You can use concat_ws() with case expressions:
select concat_ws(',',
case when `1` > 0 then 1 end,
case when `2` > 0 then 2 end,
case when `3` > 0 then 3 end,
case when `4` > 0 then 4 end,
case when `5` > 0 then 5 end
)
from t
where userid = 2;
Note that you have a problem with our data model. If you stored this data properly, then the solution would be simpler. The proper way to store this would be one row per "group" and "level" for each user.
Let's say I have this table:
name| value
----|------
A | 0
B | 0
A | 1
C | 1
A | 1
The select I want is to give the result like this:
A | 2
B | 0
C | 1
In first phase I tried with:
SELECT name, count(0)
FROM table
WHERE value > 0
GROUP BY name;
Which result
A | 2
C | 1
I also want to include B with count(0) = 0. How I can do this?
You want to aggregate your rows and get one result row per name. This translates to GROUP BY name in SQL. For counting use COUNT and inside use CASE WHEN to decide what to count.
select name, count(case when value > 0 then 1 end)
from mytable
group by name
order by name;
This works because COUNT only counts non-null occurences. We could just as well use SUM for counting: sum(case when value > 0 then 1 else 0 end).
In your example there is only 0 and 1. If these are the only possible values, you can just add them up:
select name, sum(value)
from mytable
group by name
order by name;
Do you just want aggregation? The following query would actually produce the correct results for your sample data:
select name, sum(value) sum_value
from mytable
group by name
Try this:
SELECT a.name, count(*)*(case when sum(a.value) >= 1 then 1 else 0 end)
FROM table a
GROUP BY name;
For a better solution, give more details about the nature of the value column
I have a table:
id flag
1 Y
1 Y
1 Y
1 N
1 N
2 Y
2 N
2 N
3 Y
3 N
i want to do as select statement which will give me the following output.
id count_flag_Y count_flag_N
1 3 2
2 1 2
3 1 1
I was trying using the select case method but getting syntax error.
SELECT id,SUM(CASE WHEN flag= 'Y') as count_flag_Y,
SUM(CASE WHEN flag= 'N') as count_flag_N
from tablename
GROUP BY id
Is there any way to do it?
Your query was not far off, you only have a slight problem with the CASE expressions. Try this:
SELECT id,
SUM(CASE WHEN flag= 'Y' THEN 1 ELSE 0 END) AS count_flag_Y,
SUM(CASE WHEN flag= 'N' THEN 1 ELSE 0 END) AS count_flag_N
FROM tablename
GROUP BY id
You are very close, but in MySQL the CASE is not needed:
SELECT id, SUM(flag = 'Y') as count_flag_Y,
SUM(flag = 'N') as count_flag_N
FROM tablename
GROUP BY id;
MySQL treats boolean expressions like integers in a numeric context, with "1" for true and "0" for false.
I am new to sql and i have this problem in hand.
I have a table temp which has id and flag as its columns.
ID FLAG
-- ----
A 1
A 1
A 0
B 1
B 0
B 0
C 0
C 0
C 0
I need the 1's and 0's count with respect to each ID.
The desired output is
ID OnesCount ZerosCount
--- --------- ----------
A 2 1
B 1 2
C 0 3
I tried a lot i can get them individually by
select id,count(*) ZerosCount from temp where flag = 0 group by id
select id,count(*) OnesCount from temp where flag = 1 group by id
But do not understand how to join and get the desired output.
Can some one please help
In this specific case you can do like this:
select customer_id ID,
sum(pwr_flag) OnesCount,
sum(1-pwr_flag) ZerosCount
from temp_pwr
group by customer_id
In a more generic case you can use case when:
select customer_id ID,
sum(case pwr_flag when 1 then 1 else 0 end) OnesCount,
sum(case pwr_flag when 0 then 1 else 0 end) ZerosCount
sum(case pwr_flag when 17 then 1 else 0 end) SeventeensCount
from temp_pwr
group by customer_id
select customer_id,
count(case when pwr_flag = 0 then 1 end) ZerosCount,
count(case when pwr_flag = 1 then 1 end) OnessCount
from temp_pwr
group by customer_id
I have a table like
ID Name
1 ABC
1 DEF
1 VVV
1 BBB
1 BCD
2 ZZZ
2 BAA
3 AAA
3 BBB
3 BBC
I want to get the ratio of all the names that start with A to All the names that start with B group by ID.
So the output should be
ID Ratio
1 0.5
2 0
3 0.33
.
SELECT (ID, (SELECT COUNT(*) FROM `table` WHERE name LIKE 'A%') /
(SELECT COUNT(*) FROM `table` WHERE name LIKE 'B%')) AS `ratio` from table Group by ID
does not give me the right answer. It takes the total ratio of A/B across all ID's into account and writes that number for all the ID's.
I'd try:
SELECT ID, CASE WHEN B = 0 THEN 0 ELSE A/B END AS Ratio FROM
( SELECT ID,
SUM(CASE WHEN Name LIKE 'A%' THEN 1 ELSE 0 END) AS A,
SUM(CASE WHEN Name LIKE 'B%' THEN 1 ELSE 0 END) AS B
FROM my_table GROUP BY ID ) AS grouped;
The inner SELECT gets the group IDs, and for every ID, the number of items beginning with A and those beginning with B.
The outer SELECT (you can omit it if you're sure that there'll always be at least one B-row) checks that the ratio makes sense before attempting to calculate it.
Or else:
SELECT ID, COALESCE(SUM(CASE WHEN Name LIKE 'A%' THEN 1 ELSE 0 END)
/ SUM(CASE WHEN Name LIKE 'B%' THEN 1 ELSE 0 END), 0)
FROM my_table GROUP BY ID;
This takes advantage of the fact that, if the number of B-rows is zero, the division will yield NULL. The COALESCE transforms that NULL in a 0.
This will do it:
SELECT
id,
SUM(IF(name LIKE 'A%',1,0))/SUM(IF(name like 'B%',1,0))
FROM `table`
GROUP BY ID