I have three tables as :
ab, a, and b
Table a and b should have multiple occurrences for the same touid.
SELECT * FROM ab
tourid tourname
------ ------------
100 hundred
110 one ten
120 one twenty
select * from a;
imageid tourid filesize
------- ------ ----------
1 100 10
2 100 20
SELECT * FROM b
uid tourid filesize
------ ------ ----------
5 100 5
sql query :
SELECT
a.tourid,
SUM(a.filesize) AS a_sum,
SUM(b.filesize) AS b_sum
FROM ab
LEFT JOIN a ON a.tourid=ab.tourid
LEFT JOIN b ON b.tourid=ab.tourid
WHERE ab.tourid=100
gives the result as:
tourid a_sum b_sum
------ ------ --------
100 30 10
But result should be as :
tourid a_sum b_sum
------ ------ --------
100 30 5
result of b_sum column is wrong
In the first table, you have one row :
tourid tourname
100 hundred
Joining the a table will produce 2 rows :
tourid tourname imaageid filesize
100 hundred 1 10
100 hundred 2 20
Joining the b table will keep 2 rows :
tourid tourname imaageid filesize uid filesize
100 hundred 1 10 5 5
100 hundred 2 20 5 5
the good query is :
select tourid, sum_a, sum_b
from ab
left join (select tourid, sum(filesize) as sum_a from a group by tourid) a on ab.tourid = a.tourid
left join (select tourid, sum(filesize) as sum_b from b group by tourid) b on ab.tourid = b.tourid
You need to add GROUP BY ab.tourid to overcome duplicates, there are repeated results therefore you are getting the sum as twice
SELECT
a.tourid,
SUM(a.filesize) AS a_sum,
SUM(b.filesize) AS b_sum
FROM ab
LEFT JOIN a ON a.tourid=ab.tourid
LEFT JOIN b ON b.tourid=ab.tourid
WHERE ab.tourid=100
GROUP BY ab.tourid
The counts are correct: since you are joining to both tables at once, the results before aggregation will look like this:
tourid a.filesize b.filesize
------ ---------- ----------
100 10 5
100 20 5
You get the same row of b for each joined row in a.
When you total up a.filesize, you get 30; when you total up b.filesize, you get 10, explaining the results.
You can get the results that you wish without joins or aggregations - simple subqueries would be sufficient:
SELECT
100
, (SELECT SUM(filesize) FROM a WHERE tourid=100) as sum_a
, (SELECT SUM(filesize) FROM b WHERE tourid=100) as sum_a
Related
I have two tables that I need to merge.
Table 1 is :
ID
Product code
Spend
1
101
100
1
102
200
1
103
300
2
201
400
3
301
500
3
302
600
Table 2 has
ID
Product code
Spend
Product tenure
1
101
100
20
1
102
200
30
3
302
600
40
I want to merge these such that only ID's present in table 2 are retained from table 1. Table 2 does not contain all the product codes for each ID, but I want my final table to have it.
Output must have
ID
Product code
Spend
Product tenure
1
101
100
20
1
102
200
30
1
103
300
3
301
500
3
302
600
40
Any help on this would be appreciated. I tried left join on ID, but it produces many duplicates.
SELECT *,
(
SELECT `product_tenure`
FROM `second_table`
WHERE `second_table`.`id` = `first_table`.`id`
AND `first_table`.`product_code` = `second_table`.`product_code`
) product_tenure
FROM `first_table`
WHERE `id` IN (SELECT DISTINCT `id` FROM `second_table`)
Explaination:
Select id from second table, which wanted to keep from first table.
Because the product_tenure only in second_table select them with combined id and product_code
Result:
Test this:
SELECT *
FROM t1
LEFT JOIN t2 AS t21 USING (ID, `Product code`)
WHERE EXISTS ( SELECT NULL
FROM t2 AS t22
WHERE t1.ID = t22.ID )
PS. The query will return 2 Spent columns (they're present in each table, and nothing prevents their values to be not equal...) - so replace an asterisk with definite columns list.
We have a table of our sold items, it looks like this : ( Table A )
id
sell_id
item
amount
11
5
A
3000
12
5
B
2000
13
6
A
5120
14
7
C
5000
and a table where shipped items are placed that looks like this : ( Table B )
id
sub_id
item
amount
1
11
A
2850
2
11
A
150
3
12
B
2100
( Table B is matched to Table A by referencing TableA.id in Table B as sub_id ).
I want to find rows that sum of amount per TableA.id is not equivalent of sum of TableB.amount per TableB.sub_id.
In other words I want to know which sold items are not shipped exactly as the amount which is sold.
I've tried left joining tableA to tableB but i cannot get it to work.
Any help would be appreciated. Thanks!
For example:
SELECT a.*
FROM a
WHERE NOT EXISTS ( SELECT NULL
FROM b
WHERE a.id = b.sub_id
GROUP BY b.sub_id
HAVING a.amount = SUM(b.amount) )
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1b13c67b6e622a5da72f63074d53d423
I have a log of points that I want to import somewhere else as (email - total points).
I'm trying to figure out a query that does the following:
Calculate points for EACH user_id, and merging those user_ids so they won't be duplicated.
After that, I need to replace the USER_IDs with corresponding emails in another table:
Source Table
USER_ID Points
------- ------
1 10
2 30
3 50
1 -5
2 5
3 -40
Desired result
USER_ID Points
------- ------
1 5
2 35
3 10
STEP 2
Another Source Table
USER_ID Email
------- ------
1 one#one.com
2 two#two.com
3 three#three.com
Final Desired result:
USER_ID Total Points
------- -----------
one#one.com 5
two#two.com 35
three#three.com 10
To pretify your query you can write like that :
select oc_customer.email,
sum(oc_customer_reward.points) as Total_points
from oc_customer_reward
inner join oc_customer using(customer_id)
group by customer_id
I have a table with the columns : id, status, value.
id status value
-- ------ -----
1 10 100
2 10 100
3 10 60
4 11 20
5 11 15
6 12 100
7 12 50
8 12 50
I would like to get the id and value of the first and second highest valued rows, from each status group. My table should have the following columns:
status, id of the first highest value, first highest value, id of second highest value, second highest value.
I should get:
status 1stID 1stValue 2ndID 2ndValue
------ ----- -------- ----- --------
10 1/2 100 2/1 100
11 4 20 5 15
12 6 100 7/8 50
I tried all kinds of solutions, but I couldn't find a solution for same-value 1st s (two rows with the same value, which happened to be the highest in that status group) or same-value seconds.
For example, in case of two rows sharing the highest value in their status group, this not-so-elegant query will return two rows with the same status, different 1sts and same 2nd:
SELECT 2nds.status, 1sts.id AS "1stID",1sts.value AS "1stValue",
2nds.id AS "2ndID",2nds.value AS "2ndValue"
FROM
(SELECT v.* FROM
(SELECT status, MAX(value) AS "SecMaxValue" FROM table o
WHERE value < (SELECT MAX(value) FROM table
WHERE status = o.status
GROUP BY status) AS m
INNER JOIN table v
ON v.status = m.status AND v.value = m.SecMaxValue) AS 2nds
INNER JOIN
(SELECT v.* FROM
(SELECT status, MAX(value) AS maxValue FROM table
GROUP BY status) AS m
INNER JOIN table v
ON v.status = m.status AND v.value = m.MaxValue) AS 1sts
ON 1sts.status = 2nds.status ;
This query will give me:
status 1stID 1stValue 2ndID 2ndValue
------ ----- -------- ----- --------
10 1 100 3 60
10 2 100 3 60
11 4 20 5 15
12 6 100 7 50
12 6 100 8 50
To conclude, I would like to find a solution in which:
a. if there are two rows with the highest value the query puts the details one of them in the column of the 1st and the details of other in 2nd (no mather which)
b. if there are two rows with the second highst value it puts the highest in its place and one of the seconds in the second place.
Is there a way to change the query above? someone has a nicer solution?
I came across several 1st and 2nd queries but they had the same problem - for example this solution: Finding the highest n values of each group in MySQL. it does not deliver 1st and 2nd in the same row, but the main problem it provides only one of the firsts.
Thanks
After spent a lot of time, finally I found a solution for above problem. Please try it out:
select 1st.status as Status,
SUBSTRING_INDEX(1st.id,'/',1) as 1stID,
1st.value as 1stValue,
(case when locate('/',1st.id) > 0 then SUBSTRING_INDEX(1st.id,'/',-1)
else 2nd.id
end) as 2ndID,
(case when locate('/',1st.id) > 0 then 1st.value
else 2nd.value
end) as 2ndValue
from
(
(select status, SUBSTRING_INDEX(Group_concat(id separator '/'),'/',2) as id,value
from t1
where (status,value) in (select status,value
from t1
group by status
having max(value))
group by status) 1st
inner join
(select status,id,value
from t1
where (status,value) not in (select status,value
from t1
group by status
having max(value))
group by status,value
order by status,value desc) 2nd
on 1st.status = 2nd.status)
group by 1st.status;
Just replace t1 with your tablename and it should work like a charm.
Click here for Updated Demo
If you have any doubt(s), feel free to ask.
Hope it helps!
I have 3 tables a, b, and c.
Table a contains the ids of the stores, their earning date, and count of sale (flight tickets).
Table b contains the id, sale date, and count of clothing orders.
Table c contains the id, date and total count.
SQL> select * from a;
STOREID EARNINGDATE COUNT_FLIGHT_TICKETS
-------------------- ----------- ----------------
store01 14980000 10
store01 14980001 32
store02 14980000 134
SQL> select * from b;
STOREID EARNINGDATE CLOTHES_SALE_COUNT
-------------------- ----------- ---------------
store01 14980000 6
store02 14980000 6
SQL> select * from c;
STOREID EARNINGDATE TOTAL_SALE_COUNT
-------------------- ----------- -------------
store01 14980001 32
store01 14980000 16
store02 14980000 134
Given above the tables, I have to print all the stores ids, with their date of earning for total sale, flight sale, and clothing sale.
|StoreId | EarningDate | FlightCount | ClothingCount | TotalCount |
I have used below query, but failing to get the above.
select b.storeId , sum(a.COUNT_FLIGHT_TICKETS),
sum(b.CLOTHES_SALE_COUNT), sum (c.TOTAL_SALE_COUNT)
from a
full outer join b on a.storeId = b.storeId
and a.EarningDate = b.earningdate
full outer join c on a.storeId = c.storeId
and a.earningDate = b.earningDate group by a.storeId;
This query does not give all the rows and having some bug.
STOREID flight clothing total
------ --------- --------- --------------------
store02 134 6 134
store01 52 12 48
Can someone help me to correct this query to get the expected output?
One option would be to take the UNION of the thee tables and then aggregate by store:
SELECT
t.STOREID,
t.EARNINGDATE,
SUM(t.COUNT_FLIGHT_TICKETS) AS FlightCount,
SUM(t.CLOTHES_SALE_COUNT) AS ClothingCount,
SUM(t.TOTAL_SALE_COUNT) AS TotalCount
FROM
(
SELECT
STOREID,
EARNINGDATE,
COUNT_FLIGHT_TICKETS,
0 AS CLOTHES_SALE_COUNT,
0 AS TOTAL_SALE_COUNT
FROM a
UNION ALL
SELECT STOREID, EARNINGDATE, 0, CLOTHES_SALE_COUNT, 0
FROM b
UNION ALL
SELECT STOREID, EARNINGDATE, 0, 0, TOTAL_SALE_COUNT
FROM c
) t
GROUP BY
t.STOREID,
t.EARNINGDATE
This gets around the join problem you correctly pointed out, which might require a full outer join. Full outer join in MySQL is a hassle, and in any case it usually should not be necessary with good design.
Demo here:
Rextester
Assuming that for each table, (storeId, earningdate) is unique or compound keys, group by will be unnecessary.
You can try this query.
select
IF(isnull(a.STOREID), IF(isnull(b.STOREID), c.STOREID, b.STOREID),a.STOREID) as StoreId,
IF(isnull(a.EARNINGDATE), IF(isnull(b.EARNINGDATE), c.EARNINGDATE, b.EARNINGDATE),a.EARNINGDATE) as EarningDate,
IF(isnull(COUNT_FLIGHT_TICKETS),0,COUNT_FLIGHT_TICKETS) as FlightCount,
IF(isnull(CLOTHES_SALE_COUNT),0,CLOTHES_SALE_COUNT) as ClothingCount,
IF(isnull(TOTAL_SALE_COUNT),0,TOTAL_SALE_COUNT) as TotalCount
from a full outer join b
on a.storeId = b.storeId and a.EarningDate = b.earningdate
full outer join c
on a.storeId = c.storeId and a.earningDate = c.earningDate;
Result was:
STOREID EarningDate flight clothing total
------ ------------- --------- --------- --------------------
store01 14980000 10 6 16
store02 14980000 134 6 134
store01 14980001 32 0 32
Is this your expected result?
I think you forgot the earning date.
Given above the tables, I have to print all the stores ids, with their
date of earning for total sale, flight sale, and clothing sale.
|StoreId | EarningDate | FlightCount | ClothingCount | TotalCount |