SQL Count occurrences of multiple columns - mysql

I want to count occurrences of Number 3 from multiple columns with group by Primary Key.
I have a table like this.
And I have tried with this.
But my output is
But expected output is something like this

With this:
select id,
(s1 = 3) + (s2 = 3) + (s3 = 3) + (s4 = 3) + (s5 = 3) valcount
from tablename
Each of the boolean expressions:
s? = 3
evaluates to 0 or 1.

Your query only counts rows with multiple threes one time.
You could use a union:
select id
, sum(case when val = 3 then 1 else 0 end)
from (
select id, s1 as val from t1
union all select id, s2 from t1
union all select id, s3 from t1
union all select id, s4 from t1
union all select id, s5 from t1
) sub
group by
id
Example at db-fiddle.com

Try Below Query..
select id,(count(s1)+count(s2)+count(s3)+count(s4)+count(s5))valcount from(
select id, case when s1=3 then 1 end as s1,
case when s2=3 then 1 end as s2,
case when s3=3 then 1 end as s3,
case when s4=3 then 1 end as s4,
case when s5=3 then 1 end as s5
from test) group by id
and Try another way
select id,
count(decode(s1,3,1))+
count(decode(s2,3,1))+
count(decode(s3,3,1))+
count(decode(s4,3,1))+
count(decode(s5,3,1))valcount
from test
group by id

SELECT id, ( SUM(CASE WHEN s1 =3 THEN 1 ELSE 0 END ) + SUM(CASE WHEN s2 =3 THEN 1 ELSE 0 END ) +
SUM(CASE WHEN s3 =3 THEN 1 ELSE 0 END ) +
SUM(CASE WHEN s4 =3 THEN 1 ELSE 0 END ) +
SUM(CASE WHEN s5 =3 THEN 1 ELSE 0 END ) ) AS val FROM t1 GROUP BY id
I think it will be helpful for you

Related

MySql GROUP BY Max Date

I have a table called votes with 4 columns: id, name, choice, date.
****id****name****vote******date***
****1*****sam*******A******01-01-17
****2*****sam*******B******01-05-30
****3*****jon*******A******01-01-19
My ultimate goal is to count up all the votes, but I only want to count 1 vote per person, and specifically each person's most recent vote.
In the example above, the result should be 1 vote for A, and 1 vote for B.
Here is what I currently have:
select name,
sum(case when uniques.choice = A then 1 else 0 end) votesA,
sum(case when uniques.choice = B then 1 else 0 end) votesB
FROM (
SELECT id, name, choice, max(date)
FROM votes
GROUP BY name
) uniques;
However, this doesn't work because the subquery is indeed selecting the max date, but it's not including the correct choice that is associated with that max date.
Don't think "group by" to get the most recent vote. Think of join or some other option. Here is one way:
SELECT v.name,
SUM(v.choice = 'A') as votesA,
SUM(v.choice = 'B') as votesB
FROM votes v
WHERE v.date = (SELECT MAX(v2.date) FROM votes v2 WHERE v2.name = v.name)
GROUP BY v.name;
Here is a SQL Fiddle.
Your answer are close but need to JOIN self
Subquery get Max date by name then JOIN self.
select
sum(case when T.vote = 'A' then 1 else 0 end) votesA,
sum(case when T.vote = 'B' then 1 else 0 end) votesB
FROM (
SELECT name,Max(date) as date
FROM T
GROUP BY name
) AS T1 INNER JOIN T ON T1.date = T.date
SQLFiddle
Try this
SELECT
choice,
COUNT(1)
FROM
votes v
INNER JOIN
(
SELECT
id,
max(date)
FROM
votes
GROUP BY
name
) tmp ON
v.id = tmp.id
GROUP BY
choice;
Something like this (if you really need count only last vote of person)
SELECT
sum(case when vote='A' then cnt else 0 end) voteA,
sum(case when vote='B' then cnt else 0 end) voteB
FROM
(SELECT vote,count(distinct name) cnt
FROM (
SELECT name,vote,date,max(date) over (partition by name) maxd
FROM votes
)
WHERE date=maxd
GROUP BY vote
)
PS. MySQL v 8
select
name,
sum( case when choice = 'A' then 1 else 0 end) voteA,
sum( case when choice = 'B' then 1 else 0 end) voteB
from
(
select id, name, choice
from votes
where date = (select max(date) from votes t2
where t2.name = votes.name )
) t
group by name
Or output just one row for the total counts of VoteA and VoteB:
select
sum( case when choice = 'A' then 1 else 0 end) voteA,
sum( case when choice = 'B' then 1 else 0 end) voteB
from
(
select id, name, choice
from votes
where date = (select max(date) from votes t2
where t2.name = votes.name )
) t
Based on #d-shish solution, and since introduction (in MySQL 5.7) of ONLY_FULL_GROUP_BY, the GROUP BY statement must be placed in subquery like this :
SELECT v.`name`,
SUM(v.`choice` = 'A') as `votesA`,
SUM(v.`choice` = 'B') as `votesB`
FROM `votes` v
WHERE (
SELECT MAX(v2.`date`)
FROM `votes` v2
WHERE v2.`name` = v.`name`
GROUP BY v.`name` # << after
) = v.`date`
# GROUP BY v.`name` << before
Otherwise, it won't work anymore !

How to check if a certain value is existent or if it exists twice?

So i have a table that looks something like this:
ID CUR_Valid
1 N
1 N
1 N
1 N
1 N
1 Y
2 N
2 N
2 Y
3 Y
So as you can see one ID can only be allowed to have one y. I want to write a statment that shows me the IDs that have no Y or more then one Y.
My code so far looks like this:
Select [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
,COUNT(CUR_VALID)
FROM DB.dbo.table
WHERE CUR_VALID = 'Y'
GROUP BY [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
Having COUNT(CUR_VALID) > 1 OR COUNT(CUR_VALID) <1
I'm not sure whats wrong. Can someone point me into the right direction?
Try this answer. Hope this helps you:
Select [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
,COUNT(CUR_VALID)
FROM DB.dbo.table
--WHERE CUR_VALID = 'Y'
GROUP BY [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
Having COUNT(CASE WHEN CUR_VALID = 'Y' THEN 1 END) > 1 OR COUNT(CASE WHEN CUR_VALID = 'Y' THEN 1 END) <1
When you put WHERE CUR_VALID = 'Y' condition, it remove the records which don't have the the Y.
Try this update for, number of IDs.
Select COUNT(1)[No of Ids]
FROM DB.dbo.table
GROUP BY [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
Having COUNT(CASE WHEN CUR_VALID = 'Y' THEN 1 END) > 1 OR COUNT(CASE WHEN CUR_VALID = 'Y' THEN 1 END) <1
It returns the Number of Ids.
use
SQL Aliases
Count as totalValid
Select [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
,COUNT(CUR_VALID) as totalValid
FROM DB.dbo.table
WHERE CUR_VALID = 'Y'
GROUP BY [BILL_ID]
,[Bill_MONTH]
,[CUR_VALID]
Having totalValid > 1 OR totalValid <1
here is a sample query that demonstrates the identification of one with no Y or one with two or more Y's
with dat
as
(
select 1 id,'N' cur_valid union all
select 1,'N' union all
select 1,'N' union all
select 1,'N' union all
select 1,'N' union all
select 1,'Y' union all
select 2,'N' union all
select 2,'N' union all
select 2,'Y' union all
select 3,'Y' union all
select 4,'Y' union all /* two Ys */
select 4,'Y' union all
select 5,'N' /* no Y */)
select id
from
(
select id,sum(case when cur_valid='Y' then 1 else 0 end) x
from dat
group by id
) ilv
where x<>1
this can be condensed to
with dat
as
(
select 1 id,'N' cur_valid union all
select 1,'N' union all
select 1,'N' union all
select 1,'N' union all
select 1,'N' union all
select 1,'Y' union all
select 2,'N' union all
select 2,'N' union all
select 2,'Y' union all
select 3,'Y' union all
select 4,'Y' union all /* two Ys */
select 4,'Y' union all
select 5,'N' /* no Y */)
select id
from dat
group by id
having sum(case when cur_valid='Y' then 1 else 0 end)<>1
It is possible to use self join like this
select d1.id, count(d2.id)
from (select id from dat group by id) d1
left join dat d2 on d1.id = d2.id and d2.cur_valid = 'Y'
group by d1.id
having count(d2.id) <> 1
demo - thanks #Abbennett for the data

How can I check sub query returns nothing?

Here is my query:
SELECT
CASE WHEN if_this_matches_nothing(SELECT 1 FROM mytable WHERE id = :id) THEN 0
ELSE 1 END
Is there such if_this_matches_nothing function in MySQL ?
You are looking for NOT EXISTS:
SELECT (CASE WHEN NOT EXISTS (SELECT 1 FROM mytable WHERE id = :id)
THEN 0 ELSE 1
END) as flag
You can actually shorten this. The CASE is not needed in MySQL:
SELECT (NOT EXISTS (SELECT 1 FROM mytable WHERE id = :id) ) as flag

Subquery in MySql group by

I have a query:
SELECT round(addTime/qty, 0) AS col1,
sum(qty) AS col2,
cId AS Id
FROM MyTable
WHERE qty > 0
GROUP BY round(addTime/qty, 0), cId
ORDER BY round(addTime/qty, 0)
But I have to replace addTime with a
SUM(CASE WHEN qty = 1 THEN 1 ELSE DATEDIFF(second,startTime,endTime) END)/qty, 0)
And when I do this:
SELECT round(SUM(case when qty = 1 then 1 else DATEDIFF(second,startTime,endTime) end)/qty, 0) AS col1,
sum(qty) AS col2,
cId
FROM MyTable
WHERE qty > 0
GROUP BY round(SUM(case when qty = 1 then 1 else
DATEDIFF(second,startTime,endTime) end)/qty, 0)/qty, 0), cId
ORDER BY round(SUM(case when qty = 1 then 1 else DATEDIFF(second,startTime,endTime) end)/qty, 0)/qty, 0)
I get
Cannot use an aggregate or a subquery in an expression used for the group by list of a GROUP BY clause.
My idea was that I can use that new query as variable and then use it where I need but then I ran into trouble with MySql syntax.
Big thanks in advance!
SELECT *
FROM (
SELECT
round(SUM(case when qty = 1 then 1 else DATEDIFF(second, startTime,endTime) end)/qty, 0) AS col1,
sum(qty) AS col2,
cId
FROM MyTable
WHERE qty > 0
) AS t
GROUP BY t.col1, t.cId
ORDER BY t.col1
Also I'm not sure, but your DIFFTIME function if different from MySQL DIFFTIME.
Try it with a sub query in the from clause:
Select * from (select round(...) as col1 from MyTable) as tmp where ... Group By tmp.col1
Subqueries in from clause

Is it possible for a mysql query to return true/false instead of values?

I have a table:
custID orderID orderComponent
=====================================
1 123 pizza
1 123 wings
1 234 breadsticks
1 239 salad
2 456 pizza
2 890 salad
I have a list of values - pizza, wings, breadsticks, and salad. I need a way to just get a true/false value if a customer has at least one record containing each of these. Is that possible with a mysql query, or do I just have to do a select distinct(orderComponent) for each user and use php to check the results?
If you are just looking to see if the customer has ordered all items, then you can use:
select t1.custid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
See SQL Fiddle with Demo
If you want to expand this out, to see if the custid has ordered all items in a single order, then you can use:
select t1.custid,
t1.orderid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, orderid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid, orderID
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
and t1.orderId = t2.orderid
See SQL Fiddle with Demo
If you only want the custid and the true/false value, then you can add distinct to the query.
select distinct t1.custid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
See SQL Fiddle with Demo
Or by custid and orderid:
select distinct
t1.custid,
t1.orderid,
case when t2.total is not null
then 'true'
else 'false'
end OrderedAll
from yourtable t1
left join
(
select custid, orderid, count(distinct orderComponent) Total
from yourtable
where orderComponent in ('pizza', 'wings', 'breadsticks', 'salad')
group by custid, orderID
having count(distinct orderComponent) = 4
) t2
on t1.custid = t2.custid
and t1.orderId = t2.orderid
See SQL Fiddle with Demo
select case when
count(distinct orderComponent) = 4
then 'true'
else 'false'
end as bool
from tbl
where custID=1
Here's one approach. This approach does not require an inline view (derived table), and can be effective if you want to include flags for multiple conditions:
EDIT:
This returns custID that has a row for all four items:
SELECT t.custID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
FROM mytable t
GROUP BY t.custID
HAVING has_all_four = 4
ORIGINAL ANSWER:
(This checked for a customer "order" that had all four items, rather than just a "custID".)
SELECT t.custID
, t.orderID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
-- , MAX(IF(t.orderComponent='breadsticks',1,0)) AS has_breadsticks
-- , MAX(IF(t.orderComponent='pizza',1,0)) AS has_pizza
-- , MAX(IF(t.orderComponent='salad',1,0)) AS has_salad
-- , MAX(IF(t.orderComponent='wings',1,0)) AS has_wings
FROM mytable t
GROUP BY t.custID, t.orderID
HAVING has_all_four = 4
That will get the "orders" that have all four items. If you want to return just values for custID, then use the query above as an inline view (wrap it in another query)
SELECT s.custID
FROM (
SELECT t.custID
, t.orderID
, MAX(IF(t.orderComponent='breadsticks',1,0))
+ MAX(IF(t.orderComponent='pizza',1,0))
+ MAX(IF(t.orderComponent='salad',1,0))
+ MAX(IF(t.orderComponent='wings',1,0)) AS has_all_four
FROM mytable t
GROUP BY t.custID, t.orderID
HAVING has_all_four = 4
) s
GROUP BY s.custID
#EmmyS: you can do it both ways.
If you want to check using MySql use:
SELECT #rowcount:=COUNT(*) FROM orderComponent Where (Your Conditions);
IF (#rowcount > 0) THEN
'True'
ELSE
'False'
END IF