Sum up columns between two tables in MySQL - mysql

I have an application where students do three choices 1st, 2nd and 3rd from a list.
Table1 is the list they can choose from:
id
day
1
Monday
2
Thusday
3
Wednesday
Table2 is they fill in their choices:
id
first_choice
second_choice
third_choice
12345
1
3
2
23456
3
2
1
34567
2
1
3
45678
1
2
3
What I'm struggling with is that I want to count choices per day and priority to get a list like this:
id
first_choice
second_choice
third_choice
Monday
2
1
1
Thusday
1
2
1
Wednesday
1
1
2
SELECT a.day, count(b.first_choice), count(c.second_choice), count(d.third_choice) FROM table1 a LEFT JOIN table2 b ON a.id = b.first_choice LEFT JOIN table2 c ON a.id = c.second_choice LEFT JOIN table2 d ON a.id = d.third_choice GROUP BY a.day
But, by doing so I end up with this
id
first_choice
second_choice
third_choice
Monday
2
2
2
Thusday
2
2
2
Wednesday
2
2
2
Could anyone help me with the query?
Thanks in advance

In those table structures, I normally use subquery instead of join.
SELECT
a.day,
(SELECT COUNT(*) FROM Table2 WHERE first_choice = a.id) AS first_choice,
(SELECT COUNT(*) FROM Table2 WHERE second_choice = a.id) AS second_choice,
(SELECT COUNT(*) FROM Table2 WHERE third_choice = a.id) AS third_choice
FROM Table1 a

You can use a single INNER JOIN and work it out with conditional IF statements:
SELECT
Table1.id,
Table1.day,
COUNT(IF(Table2.first_choice=Table1.id, Table2.first_choice, NULL)) AS first_choice,
COUNT(IF(Table2.second_choice=Table1.id, Table2.second_choice, NULL)) AS second_choice,
COUNT(IF(Table2.third_choice=Table1.id, Table2.third_choice, NULL)) AS third_choice
FROM
Table1
INNER JOIN
Table2
ON
Table1.id = Table2.first_choice
OR
Table1.id = Table2.second_choice
OR
Table1.id = Table2.third_choice
GROUP BY
Table1.id,
Table1.day
Refer to this fiddle: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=eea27fe9364c0fe4b96a846c9441f723

Related

MySQL Select first entry of GROUP after custom ORDER BY

I'm trying to fetch the first entry of each group after the custom ORDER BY but don't know how to select that first entry of each group. The groups should be ordered by the #team if exist, otherwise other team else NULL.
SELECT t1.*
FROM tbl t1
INNER JOIN tbl2 t2 ON t2.group_id = t1.group
WHERE t2.region = #region
ORDER BY
CASE
WHEN team=#team THEN 1
WHEN team is NOT NULL THEN 2
WHEN team is NULL THEN 3
END
Content of tbl
id group team
1 1 AA
2 1 BB
3 2 AA
4 2 CC
5 3 BB
6 3 NULL
7 4 NULL
Expected result when #team=AA
id group team
1 1 AA
3 2 AA
5 3 BB
7 4 NULL
Expected result when #team=BB
id group team
2 1 BB
3 2 AA
5 3 BB
7 4 NULL
Use your custom ordering logic with ROW_NUMBER:
WITH cte AS (
SELECT t1.*, ROW_NUMBER() OVER (PARTITION BY t1.`group`
ORDER BY CASE WHEN team = #team THEN 1
WHEN team IS NOT NULL THEN 2
ELSE 3 END) rn
FROM tbl t1
INNER JOIN tbl2 t2 ON t2.group_id = t1.`group`
WHERE t2.region = #region
)
SELECT id, `group`, team
FROM cte
WHERE rn = 1;
Side note: Avoid naming your table columns GROUP, as this is a reserved MySQL keyword, and therefore must always be escaped in backticks.

Sql query select sum of table1 and sum of table2 and subtract them

Select idn, sum(tblppmp.total_item) as a_total
sum(tblRequest.Quantity) as b_total
sum(a_total- b_total) as itemsleft
FROM PPMP.dbo.tblppmp, ppmp.dbo.tblrequest
Group by idn
i have my problem how to sum individual items from table1 and table2 and the result will be subtracted to get the answer.
like this
table1
id item
1 2
2 3
3 4
table2
id item
1 1
2 2
3 3
the result i want is like this..
table 3
sum(table.item) - sum(table2.item)
table1.id 1 = 2
table2.id 1 = 1
so (2-1) = 1
id item_left
1 1
2 1
3 1
id item
You could caculate sum for each table first and then subtract them.
select idn,
a_total - ISNULL(r_total,0) as itemsleft
FROM
(
select idn, sum(p.total_item) as p_total
from PPMP.dbo.tblppmp p
group by idn
) p
LEFT JOIN
(
select idn, sum(r.Quantity) as r_total
from ppmp.dbo.tblrequest r
group by idn
) r on p.idn = r.idn
You can not use sum(a_total- b_total). You have to use sum(tblppmp.total_item) - sum(tblRequest.Quantity).
Select tblppmp.idn
, tblppmp.total_item as a_total
,tblRequest.Quantity as b_total
,tblppmp.total_item - tblRequest.Quantity as itemsleft
FROM dbo.tblppmp
INNER JOIN
(SELECT
tblrequest.idn
,sum(tblRequest.Quantity) AS Quantity
FROM tblrequest
WHERE tblrequest.dr_year = 2015
GROUP BY tblrequest.idn) tblrequest ON tblppmp.idn = tblrequest.idn

Grab top row from GROUP BY

Going off of my last question: Complex Grouping in SQL Query…
In each grouping, I'd like to grab only the row with the highest 'step' value.
This is the query we came up with in the last question:
SELECT a.*, b.*
FROM (
SELECT request_id
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
) AS sumQ
INNER JOIN tableA AS a ON sumQ.request_id = a.request_id
INNER JOIN tableB AS b ON a.request_id = b.id
That returns:
id request_id page_views step name phone
----------------------------------------------------------------
8 3 0 0 Jacob Clark 434-343-434
9 3 0 1 Jacob Clark 434-343-434
10 4 0 0 Alex Smith 222-112-2112
11 4 0 1 Alex Smith 222-112-2112
12 4 0 2 Alex Smith 222-112-2112
Which is what I wanted, however, I realized that in each group (group by request_id) I only need the row with the highest 'step' value. How can I modify my existing query to return only:
id request_id page_views step name phone
----------------------------------------------------------------
9 3 0 1 Jacob Clark 434-343-434
12 4 0 2 Alex Smith 222-112-2112
?
Then include step in the logic:
SELECT a.*, b.*
FROM (SELECT request_id, MAX(step) as maxstep
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
) sumQ INNER JOIN
tableA a
ON sumQ.request_id = a.request_id AND
sumQ.maxstep = a.step INNER JOIN
tableB b
ON a.request_id = b.id;
Have you tried setting an ORDER BY on the step field and then take the TOP record?
SELECT a.*, b.*
FROM (
SELECT TOP 1 request_id
FROM tableA
GROUP BY request_id
HAVING MAX(page_views) <= 0 AND MAX(step) <= 2
ORDER BY step DESC
) AS sumQ
INNER JOIN tableA AS a ON sumQ.request_id = a.request_id
INNER JOIN tableB AS b ON a.request_id = b.id

Joining two tables on interval basis

In SQL, suppose that I have table A
ID
--
1
3
5
and table B
ID2
---
1
2
3
4
5
6
To get the result similar to:
ID | ID2
----------
1 | 1
1 | 2
3 | 3
3 | 4
5 | 5
5 | 6
For an explanation, an element in column ID2 will be mapped to the highest value in the column ID that is less than or equal to the said element in ID2.
For example, 4 in column ID2 is mapped to 3 from column ID, because 3 is the largest value in column ID which is less than or equal to 4.
Is it possible at all to do this in sql?
What I would do is start by joining the two tables on the condition that the id in the first table is less than or equal to that in the second table, like this:
SELECT t1.id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id;
Once you have that, you can select the maximum id from the first table, and group by the id from the second table to get the largest pairs:
SELECT MAX(t1.id) AS id, t2.id AS id2
FROM t1
JOIN t2 ON t2.id >= t1.id
GROUP BY t2.id;
SQL Fiddle seems to be down but I will update with a link as soon as I can.
SELECT MAX(A.ID) ID, B.ID2
FROM A
INNER JOIN B ON B.ID2 >= A.ID
GROUP BY B.ID2
If you only need the matching ID column:
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
If you need more columns:
select *
from a
join
(
select b.*,
(select max(ID) from a where a.ID <= b.ID2) as a_Id
from b
) as b
on a.Id = b.a_Id

select id from table with max date and max id if dates are the same

For an example I have MySQL table like:
id category date value
1 a 2013-01-02 7
2 a 2013-01-01 2
3 a 2013-01-01 3
4 b 2013-01-01 1
5 b 2013-01-02 4
6 b 2013-01-03 5
7 c 2013-01-03 4
8 c 2013-01-03 8
I need select records with MAX(date) for each category, but if date is the same, with MAX(id).
So, expected result must be:
id category date value
1 a 2013-01-02 7
6 b 2013-01-03 5
8 c 2013-01-03 8
As you can see, dates for same category can be not sorted (like id=4,5).
I tried query like:
SELECT * FROM mytable t1
INNER JOIN
(
SELECT category, MAX(date) AS MAXDATE
FROM mytable
GROUP BY category
) t2
ON t1.category = t2.category
AND t1.date = t2.MAXDATE
It works fine, when we have no same dates in table. But for my case, it will return records with lowest ids:
id category date value
1 a 2013-01-01 7
6 b 2013-01-03 5
7 c 2013-01-03 4
You are on the right track but you need to change your join.
I think what you want is the following:
SELECT * FROM mytable t1
INNER JOIN
(
SELECT MAX(id) AS ID, MAX(date) AS MAXDATE
FROM mytable
GROUP BY category
) t2
ON t1.id = t2.ID
AND t1.date = t2.MAXDATE
As mentioned, the previous wont work for every use case. The following might.
SELECT a.*
FROM mytable AS a,
(
SELECT category, date, MAX(id) AS ID
FROM mytable
GROUP BY category, date
) AS b,
(
SELECT category, MAX(date) AS date
FROM mytable
GROUP BY category
) AS c
WHERE b.category = c.category
AND b.date = c.date
AND a.id = b.id