Subquery in MySql group by - mysql

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

Related

SQL Count occurrences of multiple columns

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

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 !

Sql distinct and group by boolean field

I want to count the distinct occurrences of some column grouped and non-grouped by two boolean columns
select count(Distinct some_column) as Uniques, sum(some_other_col)
from myTable T
where T.created_at>'2016-09-15'
group by T.col1, T.col2
This query gives four values
uniques when col1=true and col2=true
uniques when col1=true and col2=false
uniques when col1=false and col2=true
uniques when col1=false and col2=false
Is it possible to change the same query and to get these three values?
I can't get that info combining the first 4 values
uniques (all)
uniques when col1=true
uniques when col2=true
UPDATE
Actually I want to keep the group by because there are some other values that I get the sum.
Use conditional aggregation:
select count(Distinct some_column) as Uniques,
count(distinct case when t.col1 then some_column end) as Uniques_col1_true,
count(distinct case when t.col2 then some_column end) as Uniques_col2_true
from myTable t
where t.created_at > '2016-09-15';
Try this
SELECT SUM(CASE WHEN col1 = TRUE
AND col2 = TRUE THEN 1 ELSE 0 END) AS opt1,
SUM(CASE WHEN col1 = TRUE
AND col2 = FALSE THEN 1 ELSE 0 END) AS opt2,
FROM
(SELECT DISTINCT col1,
col2,
somecolumn
FROM TABLE T
WHERE ...) AS TB

get value of columns in previous row and add to the next columns of the next row

I will create a graph of population by gender every year, and the graph looks like the image below.
But I'm having a hard time with the query.
Query
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
Result
In the result, 2016 male count is 4 and female count is 8. In 2017, I want the male count of 2016 to be added on the male count on 2017, meaning 2017 male count will be 5, same with female count and total count. I provided an image below of what the result should look like. Can you help me how to do this for me to proceed on doing the graph? Or is there any other way to achieve this?
Try this:
SELECT
year_added,
#malecount_v := #malecount_v + malecount as malecount,
#femalecount_v := #femalecount_v + femalecount as femalecount,
#totalcount_v := #totalcount_v + totalcount as totalcount
FROM (
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
ORDER BY year_added
) t1
CROSS JOIN (SELECT #malecount_v := 0, #femalecount_v := 0, #totalcount_v := 0) t2
In Mysql you can do it with variables, like:
SELECT
year_added,
(#iMalecount := (COUNT(CASE WHEN gender = 'Male' THEN 1 END) + #iMalecount)) AS malecount,
(#iFemalecount := (COUNT(CASE WHEN gender = 'Female' THEN 1 END) + #iFemalecount)) AS femalecount,
(#iTotalcount := (COUNT(gender) + #iTotalcount)) AS totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
but is not 100% fiable as you can read in the documentation.
In other SQL flavour probably you need a stored procedure.
you can simply use
WITH TableCount AS
(
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
)
And after that use following query
SELECT
SUM(malecount) as 'malecount',
SUM(femalecount) as 'femalecount',
SUM(totalcount) as 'totalcount'
FROM TableCount
If you are using MySql you can use temporary table to do something like CTE
CREATE TEMPORARY TABLE IF NOT EXISTS TableCount AS (
SELECT
year_added,
COUNT(case when gender='Male' then 1 end) as malecount,
COUNT(case when gender='Female' then 1 end) as femalecount,
COUNT(*) as totalcount
FROM tbl
WHERE status = 1
GROUP BY year_added
)
And then you can use above query
SELECT
SUM(malecount) as 'malecount',
SUM(femalecount) as 'femalecount',
SUM(totalcount) as 'totalcount'
FROM TableCount
You can use the TEMPORARY keyword when creating a table. A TEMPORARY
table is visible only to the current session, and is dropped
automatically when the session is closed. This means that two
different sessions can use the same temporary table name without
conflicting with each other or with an existing non-TEMPORARY table of
the same name. (The existing table is hidden until the temporary table
is dropped.) To create temporary tables, you must have the CREATE
TEMPORARY TABLES privilege.
By using temporary table concept you can achieve common table expression kind of functionality in MySql

temporary table has a count for each other table

I'm trying to make a statistics page in my php script. in order to select the count from each table I need more than 30 Queries like this
SELECT COUNT(order_id) as `uncompleted_orders` FROM `orders` WHERE `order_status` != 0
and then I need to run another query like this:
SELECT COUNT(order_id) as `completed_orders` FROM `orders` WHERE `order_status` = 1
I've tried this approach, but it didn't work:
SELECT COUNT(order_id) as `uncompleted_orders` FROM `sd_orders` WHERE `order_status` != 4;
SELECT COUNT(order_id) as `completed_orders` FROM `sd_orders` WHERE `order_status` = 4;
Is there any way to creat a new temp table in MySQL contains the count for other tables?
You could try something like this:
SELECT
(
SELECT COUNT(order_id) FROM `sd_orders` WHERE `order_status` != 4
) as `uncompleted_orders`,
(
SELECT COUNT(order_id) FROM `sd_orders` WHERE `order_status` = 4
) as `completed_orders`
You will have a result set with one row and a field for each count.
Without more information it's impossible to generalise, but there are many constructs that can help you here.
First, your example is actually from one table, and not two. This means that you can do the following...
SELECT
COUNT(CASE WHEN order_status = 4 THEN order_id END) AS complete_orders,
COUNT(CASE WHEN order_status <> 4 THEN order_id END) AS incomplete_orders
FROM
sd_orders
This works because COUNT(<something>) doesn't include an NULLs in the results. And by not including an ELSE clause, anything that doesn't match returns NULL. Another way people accomplish the same result is SUM(CASE WHEN ? THEN 1 ELSE 0 END).
Second, where you do actually have multiple tables, you can combine the results in several different ways...
-- Where you want one value from each table...
--------------------------------------------------------------------------------
SELECT
(SELECT COUNT(*) FROM table1 WHERE fieldx = ?) AS value1,
(SELECT COUNT(*) FROM table2 WHERE fieldy = ?) AS value2
-- Where you want one row of values from each table...
--------------------------------------------------------------------------------
SELECT
table1_summary.value1 AS table1_value1,
table1_summary.value2 AS table1_value2,
table2_summary.value1 AS table2_value1,
table2_summary.value2 AS table2_value2
FROM
(
SELECT
COUNT(CASE WHEN fieldx = ? THEN id END) AS value1,
COUNT(CASE WHEN fieldx <> ? THEN id END) AS value2
FROM
table1
)
AS table1_summary
CROSS JOIN
(
SELECT
COUNT(CASE WHEN fieldy = ? THEN id END) AS value1,
COUNT(CASE WHEN fieldy <> ? THEN id END) AS value2
FROM
table2
)
AS table2_summary
-- Where you want many rows, but of the same fields, from each table...
--------------------------------------------------------------------------------
SELECT
*
FROM
(
SELECT
'Table1' AS source_table,
fielda AS some_grouping,
COUNT(CASE WHEN fieldx = ? THEN id END) AS value1,
COUNT(CASE WHEN fieldx <> ? THEN id END) AS value2
FROM
table1
GROUP BY
fielda
UNION ALL
SELECT
'Table2' AS source_table,
fieldb AS some_grouping,
COUNT(CASE WHEN fieldy = ? THEN id END) AS value1,
COUNT(CASE WHEN fieldy <> ? THEN id END) AS value2
FROM
table2
GROUP BY
fieldb
)
AS summary
ORDER BY
source_table,
some_grouping,
value1,
value2
As you can see, there are a lot of ways to do this. How you approach it totally depends on your data and your needs.