what is the difference in these queries? - mysql

I was trying to improve on a previously written query . here's that query-
select tq.feature as Feature, tq.Total, pq.Passed
from (
select feature, count(distinct id) as Total
from X.results
where ver = '4.2'
group by feature
) as tq
LEFT JOIN (
select feature, count(distinct id) as Passed
from X.results
where ver = '4.2' and result = 'pass'
group by feature
) as pq USING (feature);
This is the query i wrote.But the result seems to be different .Am is missing something here ?
select feature,count(distinct id) as totalcases,
sum(case when result = 'PASS' then 1 else 0 end) as passed
from X.results
where ver='4.2'
group by feature
order by feature;
I'm a real noob in sql so forgive me if it's something silly ..

One way is to group based on both a results and feature and then do another aggregate again on just feature. Something like this.
SELECT
feature,
SUM(id_count) totalcases,
SUM(CASE WHEN result = 'PASS' THEN id_count ELSE 0 END) passed
FROM
(
SELECT
feature,
CASE WHEN result = 'PASS' THEN 'PASS' ELSE 'OTHER' END result,
COUNT(distinct id) id_count
FROM x.results
WHERE ver='4.2'
GROUP BY feature,CASE WHEN result = 'PASS' THEN 'PASS' ELSE 'OTHER' END
) x
GROUP BY feature
ORDER BY feature

SELECT feature, count(distinct id) AS Total,
count(distinct if (result='pass', id, null)) AS passed
FROM X.results
WHERE ver = '4.2'
GROUP BY 1 ORDER BY 1;
This SQL is different from yours, please see the result as below:

Related

How to use group by function for more columns

I have used following query to get below output from my exisiting database.
select date(RaisedTime) as date, object,User,Count(*) as total from table1 where object like '%Object%' and User in ('User1','User2','User3','User4','User5','User6') group by date(RaisedTime),Object,User;
The result is what I needed but not the way I need it. I need to show this with much analyzed way such as below,
Can someone help me to do what I need?
SELECT DATE(RaisedTime) AS `date`,
Object,
SUM(User = 'User1') AS User1,
-- ...
SUM(User = 'User6') AS User6
FROM table1
WHERE Object LIKE '%Object%'
AND User IN ('User1','User2','User3','User4','User5','User6')
GROUP BY DATE(RaisedTime), Object;
select `date`,users,revenue, max(case when seq = 1 then object end) objA, max(case when seq = 2 then object end) objB, max(case when seq = 3 then object end) objC from (select `date`, object, users,revenue, row_number() over(partition by `date` order by `date`) seqfrom UserAnalysis ) d group by `date`;
You can use row_number() to analyze the result in a proper way. Please refer to this image for the result output. SQL Result

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 !

Union two SQL Queries with one same column ( using Eloquent )

i have two queries which should be union (with laravel eloquent) but there is a duplicate column called group_date in both query and I should show one of them
SELECT
to_char(CREATE_UTC_DATETIME, 'yyyy-mm-dd') AS group_date,
COUNT(*) AS successful_transaction
FROM "REPORT_EVENTS"
WHERE "RESULT_CODE" = '0' AND "EVENT_TYPE" = 'BILL'
GROUP BY to_char(CREATE_UTC_DATETIME, 'yyyy-mm-dd')
ORDER BY "GROUP_DATE" DESC
SELECT
to_char(CREATE_UTC_DATETIME, 'yyyy-mm-dd') AS group_date,
COUNT(*) AS unsuccessful_transaction
FROM "REPORT_EVENTS"
WHERE "RESULT_CODE" = '1' AND "EVENT_TYPE" = 'BILL'
GROUP BY to_char(CREATE_UTC_DATETIME, 'yyyy-mm-dd')
ORDER BY "GROUP_DATE" DESC
You don't want a UNION here, but rather a single query which uses conditional aggregation:
SELECT
TO_CHAR(CREATE_UTC_DATETIME, 'yyyy-mm-dd') AS group_date,
SUM(CASE WHEN RESULT_CODE = '0' THEN 1 ELSE 0 END) AS successful_transaction,
SUM(CASE WHEN RESULT_CODE = '1' THEN 1 ELSE 0 END) AS unsuccessful_transaction
FROM "REPORT_EVENTS"
WHERE "EVENT_TYPE" = 'BILL'
GROUP BY TO_CHAR(CREATE_UTC_DATETIME, 'yyyy-mm-dd')
ORDER BY "GROUP_DATE" DESC
I am not giving any Eloquent/Laravel code here, but I am fairly certain that you would need a custom raw query to handle this. So, your actual PHP code would more or less just have the above query in its raw form.

multiple GROUP BY + COUNT display 0 values on the same table

I have this query with 2 group by, and I tried to display 0 values.
SELECT plan, locale, COUNT( * ) AS res
FROM domain
WHERE status LIKE "active"
AND plan IS NOT NULL
GROUP BY plan, locale
I know that I have to do a left join on the same table, but I can't make it works
SELECT d1.plan, d1.locale, IFNULL(COUNT(d2.id), 0) AS res
FROM domain AS d1
LEFT JOIN domain AS d2 ON d1.id = d2.id
WHERE d1.plan IS NOT NULL
GROUP BY d1.plan, d1.locale
What am I doing wrong?
Thanks for your help guys.
Don't use a where clause. Use conditional aggregation:
SELECT plan, locale,
sum(case when status LIKE 'active' AND plan IS NOT NULL then 1 else 0 end) as res
FROM domain
GROUP BY plan, locale;
EDIT:
SELECT plan, locale,
sum(case when status LIKE 'active' then 1 else 0 end) as res
FROM domain
WHERE plan is not null
GROUP BY plan, locale;

Display the results in 1 row and different columns

Assume a simple case e.g. a table bug that has a column status that can be open,fixed etc.
If I want to know how many bugs are open I simply do:
select count(*) as open_bugs from bugs where status = 'open';
If I want to know how many bugs are open I simply do:
select count(*) as closed_bugs from bugs where status = 'closed';
If what want to know how many open and how many closed there are in a query that returns the results in 2 columns i.e.
Open | Closed|
60 180
What is the best way to do it? UNION concatenates the results so it is not what I want
This can be done by using a CASE expression with your aggregate function. This will convert the rows into columns:
select
sum(case when status = 'open' then 1 else 0 end) open_bugs,
sum(case when status = 'closed' then 1 else 0 end) closed_bugs
from bugs
This could also be written using your original queries:
select
max(case when status = 'open' then total end) open_bugs,
max(case when status = 'closed' then total end) closed_bugs
from
(
select status, count(*) as total from bugs where status = 'open' group by status
union all
select status, count(*) as total from bugs where status = 'closed' group by status
) d
Besides the CASE variants that aggregate over the whole table, there is another way. To use the queries you have and put them inside another SELECT:
SELECT
( SELECT COUNT(*) FROM bugs WHERE status = 'open') AS open_bugs,
( SELECT COUNT(*) FROM bugs WHERE status = 'closed') AS closed_bugs
FROM dual -- this line is optional
;
It has the advantage that you can wrap counts from different tables or joins in a single query.
There may also be differences in efficiency (worse or better). Test with your tables and indexes.
You can also use GROUP BY to get all the counts in separate rows (like the UNION you mention) and then use another aggregation to pivot the results in one row:
SELECT
MIN(CASE WHEN status = 'open' THEN cnt END) AS open_bugs,
MIN(CASE WHEN status = 'closed' THEN cnt END) AS closed_bugs
FROM
( SELECT status, COUNT(*) AS cnt
FROM bugs
WHERE status IN ('open', 'closed')
GROUP BY status
) AS g
Try this
select count(case when status = 'open' then 1 end) open_bugs,
count(case when status = 'closed' then 1 end) closed_bugs
from bugs