MYSQL - Multiple table join and SUM - mysql

I'm facing problem with joining three tables and getting sum of its value I have three types of table Tax Types, Purchase Order and Purchase Items
currently I'm facing to get result of tax report kindly check below.
Tax Types
id name
1 No Tax
2 VAT #10%
3 GST #6%
4 VAT #20%
Purchase Order
id total order_tax_id order_tax total_tax grand_total
1 10.0000 1 0.0000 0.0000 10.0000
2 10.0000 2 1.0000 1.0000 11.0000
3 10.0000 3 0.6000 0.6000 10.6000
4 10.0000 4 2.0000 2.0000 12.0000
5 10.0000 1 0.0000 0.9100 10.0000
6 10.0000 1 0.0000 0.5700 10.0000
7 10.0000 1 0.0000 1.6700 10.0000
9 10.0000 2 1.0000 1.5700 11.0000
Purchase Items
id purchase_id tax_rate_id item_tax tax subtotal
1 1 1 0.0000 0.0000 10.0000
2 2 1 0.0000 0.0000 10.0000
3 3 1 0.0000 0.0000 10.0000
4 4 1 0.0000 0.0000 10.0000
5 5 2 0.9100 10.0000% 10.0000
6 6 3 0.5700 6.0000% 10.0000
7 7 4 1.6700 20.0000% 10.0000
9 9 3 0.5700 6.0000% 10.0000
And the output should be like this
tax_name sum_of_subtotal sum_of_item_tax sum_of_grand_total sum_of_total_tax
VAT #20% 10.00 1.67 10.00 2.00 3.67
VAT #10% 10.00 1.67 10.00 2.00 3.67
No Tax 40.00 0.00 0 0 0.00
GST #6% 10.00 1.67 10.00 2.00 3.67
Kindly help me
Query I used
SELECT
tax_rates.name,
(SUM(purchase_items.subtotal)) AS item_total_amount,
(SUM(purchase_items.item_tax)) AS item_tax_amount,
(SUM(purchases.grand_total) - SUM(purchases.order_tax)) AS total_amount,
(SUM(purchases.order_tax)) AS tax_amount
FROM tax_rates
LEFT JOIN purchases ON purchases.order_tax_id = tax_rates.id
LEFT JOIN purchase_items ON purchase_items.tax_rate_id = tax_rates.id
GROUP BY tax_rates.id
ORDER BY tax_rates.name desc
LIMIT 0, 10

I fixed the issue
SELECT
tax_rates.name,
purchase_item.subtotal AS item_total_amount,
purchase_item.item_tax AS item_tax_amount,
(purchases.grand_total - purchases.order_tax) AS total_amount,
purchases.order_tax AS tax_amount
FROM tax_rates
LEFT JOIN (SELECT a.order_tax_id, SUM(a.order_tax) as order_tax, SUM(a.grand_total) as grand_total FROM purchases AS a GROUP BY a.order_tax_id) AS purchases ON purchases.order_tax_id = tax_rates.id
LEFT JOIN (SELECT a.tax_rate_id, SUM(a.item_tax) as item_tax, SUM(a.subtotal) as subtotal FROM purchase_items AS a GROUP BY a.tax_rate_id) AS purchase_item ON purchase_item.tax_rate_id = tax_rates.id
GROUP BY tax_rates.id
ORDER BY tax_rates.name desc
LIMIT 0, 10

Related

Conflict between group by, case when, and where while using CTE

I have a long query, with joins from multiple tables. But for the sake of asking question here, I have simplified the query.
WITH cte1 AS
(
SELECT
id,
( (price * quantity) + ((gst * quantity) + (gst2 * quantity))
) gross_revenue
FROM orders
GROUP BY id
),
cte2 AS (
SELECT
id,
ROUND(gross_revenue, 2) gross_revenue,
ROUND((gross_revenue), 2) gross_profit
FROM cte1
),
cte3 AS (
SELECT id, gross_revenue,
CASE
WHEN gross_profit < 0
THEN 0
ELSE
gross_profit
END gross_profit
FROM cte2
)
SELECT
id, gross_revenue, gross_profit
FROM cte3
WHERE gross_profit >= 22.27
LIMIT 25
The above query gives me the following error:
Error Code: 1054
Unknown column 'cte1.gross_revenue' in 'where clause'
When I remove either GROUP BY, CASE WHEN
or replace WHERE to HAVING then the the query works correctly
or I remove the condition of gross_profit from WHERE clause,
Or if extract CASE WHEN from cte3 to the final SELECT statement, then the query works fine.
I am confused as what is the technical reason of this behavior?
Why is it working with HAVING but not with WHERE?
Why does it work fine when I extract CASE WHEN to the final SELECT statement?
Why does GROUP BY of cte1 is making problem at the very final SELECT statement?
Why does it work if I remove gross_profit condition from WHERE clause?
Sample Data for the given columns
id price, quantity gst gst2
1 90.0000 1.00 0.0000 0.0000
2 10.0000 1.00 0.0000 0.0000
3 30.0000 1.00 0.0000 0.0000
4 70.0000 100.00 0.0000 0.0000
5 500.0000 1.00 0.0000 0.0000
6 20.9100 20.00 2.0900 0.0000
7 100.0000 1.00 0.0000 0.0000
8 100.0000 -1.00 0.0000 0.0000
9 20.9100 -20.00 2.0000 0.0000
10 9.7100 1.00 0.0000 0.0000
11 80.0000 1.00 0.0000 0.0000
12 1100.0000 1.00 0.0000 0.0000
13 870.0000 1.00 0.0000 0.0000
14 947.0000 1.00 0.0000 0.0000
15 10.0000 1.00 1.0000 0.0000
16 200.0000 1.00 0.0000 0.0000
17 300.0000 1.00 0.0000 0.0000
18 600.0000 1.00 0.0000 0.0000
19 350.0000 1.00 0.0000 0.0000
20 10.0000 1.00 0.8000 0.0000
21 50.0000 1.00 0.0000 0.0000
22 60.0000 1.00 0.0000 0.0000
23 150.0000 1.00 0.0000 0.0000
24 20.0000 1.00 2.0000 0.0000
25 29.9500 1.00 3.0000 0.0000
Edit
Interestingly for me this query works on mysql-8.0.31 but not on mysql-8.0.27.

MySQL: select sum of column having specific values

What I'm trying to do is to select a specific amount of tickets (max 2) and every person that has the sum of the number of tickets less of 3 and the valid field has to be != 'e'
I have this table:
ID
id_person
nr_tickets
valid
1
220
1
s
2
220
1
s
3
330
2
s
4
330
1
e
5
331
1
s
6
220
2
s
7
441
1
s
8
442
2
s
9
443
1
s
10
444
1
s
11
445
2
s
Here is what I did:
SELECT m.id, m.id_person, m.nr_tickets, m.valid
FROM table m
JOIN table m1 ON m1.id <= m.id
WHERE m.nr_tickets > 0
GROUP BY m.id
HAVING SUM(case when m.valid != 'e' then m1.nr_tickets end) <= 10
This query gives me
ID
id_person
nr_tickets
valid
1
220
1
s
2
220
1
s
3
330
2
s
5
331
1
s
6
220
2
s
7
441
1
s
8
442
2
s
As you can see the query it's almost right, the thing is that the person 220 in the results has the sum of the tickets is greater than 2.
What I'm trying to achieve is to bypass the ID 6, and to have instead the ID 9
select `id`,`id_person`, sum(`nr_tickets`) as `nr_tickets`, `valid`
from `test`
group by `id_person`
having sum(`nr_tickets`) < 3 and `valid`!="e"
Output:
id id_person nr_tickets valid
5 331 1 s
7 441 1 s
8 442 2 s
9 443 1 s
10 444 1 s
11 445 2 s

SQL Query for Max Value of Grouping Till Date for All Dates

I have some values which is based on date for different groupings
For each grouping id, what is the max of value till a particular date.
Example
Date Grouping Id Value
2017-06-01 1 100
2017-06-03 1 101
2017-06-06 1 103
2017-06-02 2 200
2017-06-04 2 210
2017-06-08 2 220
2017-06-01 2 1000
2017-06-05 2 1020
2017-06-09 2 1050
I need the output like below
Date Grouping Id Value
2017-06-01 1 100
2017-06-02 1 100
2017-06-03 1 101
2017-06-04 1 101
2017-06-05 1 101
2017-06-06 1 103
2017-06-07 1 103
2017-06-08 1 103
2017-06-09 1 103
2017-06-10 1 103
2017-06-01 2 NULL
2017-06-02 2 200
2017-06-03 2 200
2017-06-04 2 210
2017-06-05 2 210
2017-06-06 2 210
2017-06-07 2 210
2017-06-08 2 220
2017-06-09 2 220
2017-06-10 2 220
2017-06-01 3 1000
2017-06-02 3 1000
2017-06-03 3 1000
2017-06-04 3 1000
2017-06-05 3 1020
2017-06-06 3 1020
2017-06-07 3 1020
2017-06-08 3 1020
2017-06-09 3 1050
2017-06-10 3 1050
So assuming you have the TEMPLATE_TABLE that has all days x all grouping IDs data, you can try below two queries:
CREATE TABLE TABLE_1 AS
SELECT A.DATE, A.GROUPING_ID, B.VALUE
FROM
TEMPLATE_TABLE A
LEFT JOIN
GIVEN_TABLE B
ON A.DATE = B.DATE AND A.GROUPING_ID = B.GROUPING_ID
ORDER BY A.GROUPING_ID, A.DATE;
Above table TABLE_1 will pad values for matches and NULL for non-matches.
You can use this table to find maximum values till a given date for all dates through a self join given in the below query:
SELECT B.DATE, B.GROUPING_ID, MAX(A.VALUE) AS VALUE
FROM
TABLE_1 A
INNER JOIN
TABLE_1 B
ON A.GROUPING_ID = B.GROUPING_ID AND A.DATE<=B.DATE
GROUP BY B.DATE, B.GROUPING_ID;
Hope this works. Let me know if this doesn't.

How to combine 2 tables with same date

I have 2 Tables with following data:
TABLE 1 (dummy_daily)
Entry storenum busidate daily_budget
1 1 2017-07-01 4000
2 1 2017-07-02 3500
3 1 2017-07-03 2000
4 1 2017-07-04 6000
5 1 2017-07-05 1500
TABLE 2 (site_labour)
Lab_id storenum busidate lab_hour
1123 1 2017-07-01 128
1124 1 2017-07-02 103
1125 1 2017-07-03 114
1126 1 2017-07-04 108
1127 1 2017-07-05 118
This is my current query to combine the 2 tables that have the same date to give result of daily_budget and lab_hour
QUERY:
SELECT
a.daily_budget as Ideal, c.lab_hour as Actual,
b.store_name, b.storenum,a.busidate
FROM dummy_daily a JOIN site_store b ON b.storenum=a.storenum JOIN
site_labour c ON b.storenum=c.storenum
WHERE b.storenum='1' AND
(CASE WHEN c.busidate BETWEEN '2017-07-01' AND '2017-07-05' THEN c.lab_hour ELSE 0 END)
AND (CASE WHEN a.busidate
BETWEEN '2017-07-01' AND '2017-07-05' THEN a.daily_budget ELSE 0 END)
But my current query give me a wrong result :
Wrong Result of Current Query
Ideal Actual storenum busidate
4000 128 1 2017-07-01
3500 128 1 2017-07-02
2000 128 1 2017-07-03
6000 128 1 2017-07-04
1500 103 1 2017-07-05
4000 103 1 2017-07-01
3500 103 1 2017-07-02
2000 103 1 2017-07-03
6000 103 1 2017-07-04
1500 103 1 2017-07-05
This data will continue until end of Actual 118
Expected Result
Ideal Actual storenum busidate
4000 128 1 2017-07-01
3500 103 1 2017-07-02
2000 114 1 2017-07-03
6000 108 1 2017-07-04
1500 118 1 2017-07-05
You have missed one more table so its make confusion to create logic,
As per my understanding, I have created a SELECT statement. Please try this:-
SELECT
dummy_daily.daily_budget as Ideal, site_labour.lab_hour as Actual,
site_store.store_name, site_store.storenum, dummy_daily.busidate
FROM dummy_daily
JOIN site_store
ON dummy_daily.storenum = site_store.storenum
JOIN site_labour
ON dummy_daily.storenum = site_labour.storenum
WHERE (dummy_daily.storenum = 1)
AND (dummy_daily.busidate BETWEEN '2017-07-01' AND '2017-07-05')
AND (site_labour.busidate BETWEEN '2017-07-01' AND '2017-07-05')
AND (dummy_daily.busidate = site_labour.busidate);
Let's try the SQL below:
SELECT
a.daily_budget as Ideal, c.lab_hour as Actual,
b.store_name, b.storenum,a.busidate
FROM dummy_daily a JOIN site_store b ON b.storenum=a.storenum AND b.busidate=a.busidate JOIN
site_labour c ON b.storenum=c.storenum AND b.busidate=c.busidate
WHERE b.storenum='1' AND
(CASE WHEN c.busidate BETWEEN '2017-07-01' AND '2017-07-05' THEN c.lab_hour ELSE 0 END)
AND (CASE WHEN a.busidate
BETWEEN '2017-07-01' AND '2017-07-05' THEN a.daily_budget ELSE 0 END)

How to first order by column A, return a top-3, then order the result by column B in one query?

(Please refer to SQLFiddle for a working example of this post)
I have a table with stock information, as follows:
sp100_id _date bullishness agreement
----------------------------------------------
1 2011-03-16 1.01 0.33
1 2011-03-17 0.85 1.28
1 2011-03-18 0.89 1.25
1 2011-03-21 1.46 1.21
1 2011-03-22 0.39 2.53
2 2011-03-16 3.07 1.27
2 2011-03-17 2.09 0.80
2 2011-03-18 0.91 0.12
2 2011-03-21 1.50 0.00
2 2011-03-22 2.62 1.10
3 2011-03-16 0.73 1.13
3 2011-03-17 1.13 1.21
3 2011-03-18 1.12 0.45
3 2011-03-21 1.00 1.01
3 2011-03-22 1.00 0.53
4 2011-03-16 0.40 1.10
4 2011-03-17 2.40 0.03
4 2011-03-18 3.16 0.10
4 2011-03-21 0.86 0.50
4 2011-03-22 1.00 0.10
I need to order the companies (sp100_id) by their averge bullishness over time into a top-3:
SELECT
sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id LIMIT 3
This works fine, as the result is
SP100_ID BULLISHNESS AGREEMENT
2 2.038 0.658
4 1.564 0.366
3 0.996 0.866
Now that I have the top-3, I need the top-3 to be re-ordered by AGREEMENT, ascending:
SP100_ID BULLISHNESS AGREEMENT
4 1.564 0.366
2 2.038 0.658
3 0.996 0.866
Is this possible to do with one query? I tried the following but it didn't work. It still only orders by bullishness
SELECT
sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id
ORDER BY bullishness DESC, agreement ASC LIMIT 3
So to be clear: (1) I need to find the top-3 companies with highest average bullsihness (2) this top-3 then needs to be ordered from lowest to highest agreement. Preferably with one query. Do you know how?
It's called structured query language because you can build structures in which queries (aka virtual tables) are nested inside other queries.
Take your first query, which is correct except it needs its own ORDER BY clause, and nest it in another, like so.
SELECT *
FROM (
SELECT sp100_id,
AVG(bullishness) as bullishness,
AVG(agreement) AS agreement
FROM stocks
WHERE _date BETWEEN '2011-03-16' AND '2011-03-22'
GROUP BY sp100_id
ORDER BY bullishness DESC
LIMIT 3
) subquery
ORDER BY agreement ASC
Go fiddle: http://sqlfiddle.com/#!2/c9ff0/7/0