I'm triying to add quantities of fuels from two tables.
Payments table contains data about customers and dates.
Fuels table contains data about fuels recharged.
I need to add the litres by customer in 3 groups:
from yesterday until 46 days
47 days ago until 91
366 days ago until 410
Then I created this code:
The structure of the tables are:
TABLE payments
customer
id
date
AAA
001
2022-10-17
BBB
002
2021-10-01
CCC
003
2022-09-30
DDD
004
2022-07-10
DDD
005
2022-06-03
EEE
006
2021-09-27
EEE
007
2022-10-01
FFF
008
2021-08-31
TABLE fuels
id
litres
001
30
002
20
003
40
004
30
005
20
006
10
007
56
008
22
SELECT payments.customer,
SUM(CASE
WHEN ((TIMESTAMPDIFF(DAY, payments.date, now()) > 1) AND (TIMESTAMPDIFF(DAY, payments.date, now()) <= 46))
THEN fuels.litres
ELSE 0
END) AS "Quantity_d",
SUM(CASE
WHEN ((TIMESTAMPDIFF(DAY, payments.date, now()) > 46) AND (TIMESTAMPDIFF(DAY, payments.date, now()) <= 91))
THEN fuels.litres
ELSE 0
END) AS "Quantity_d2",
SUM(CASE
WHEN ((TIMESTAMPDIFF(DAY, payments.date, now()) > 365) AND (TIMESTAMPDIFF(DAY, payments.date, now()) <= 410))
THEN fuels.litres
ELSE 0
END) AS "Quantity_d3"
FROM payments
INNER JOIN fuels ON fuels.id=payments.id
WHERE payments.date > ADDDATE(now(),-411)
GROUP BY customer
The result is that Quantity_d1 is adding from yesterday until day 410, Quantity_d2 from 45 days ago until 410 and Quantity_d3 from 365 days ago until 410.
What am I doing wrong?
Thanks
Without knowing the table structures and relationships, I do find it odd that you're joining on payments.id and fuels.id as those both look like primary key fields. Is it possible that you are joining the wrong id fields, e.g. fuels.id = payments.fuel_id?
If I run your SQL without changes I get exactly what is specified:
customer
Quantity_d
Quantity_d2
Quantity_d3
AAA
30
0
0
BBB
0
0
20
CCC
40
0
0
DDD
0
0
0
EEE
56
0
10
If you still have issues, please explain!
Related
Many thanks for the help on my last question on extracting price data and putting it into month by years – the query works well to get the max price based on my criteria.
What I need now is a query to extract all the entries, so I can make a view that I can filter on filter on grid_calc.SexCategory, grid_calc.Teeth, grid_calc.WtMin’, grid_calc.WtMax and grid_header.BuyerID`,
This is what I currently have.
Q. can I reuse this or do I need to recreate a new query. If recreate how would I go about it?
select grid_calc.`FeedType`,
grid_calc.`SexCategory`,
grid_calc.`Teeth`,
grid_calc.`Price`,
grid_calc.`WtMin`,
grid_calc.`WtMax`,
grid_header.`BuyerID`,
monthname(grid_header.`EntryDate`) as Month,
max(case when year(grid_header.`EntryDate`) = 2018 then price else 0 end) as price_2018,
max(case when year(grid_header.`EntryDate`) = 2019 then price else 0 end) as price_2019,
max(case when year(grid_header.`EntryDate`) = 2020 then price else 0 end) as price_2020,
max(case when year(grid_header.`EntryDate`) = 2021 then price else 0 end) as price_2021,
max(case when year(grid_header.`EntryDate`) = 2022 then price else 0 end) as price_2022
FROM grid_calc
INNER JOIN grid_header
ON grid_header.`EntryDate` > '2018-01-01'
AND grid_calc.`GridID` = grid_header.`GridID`
WHERE 1=1
AND grid_header.`EntryDate` > '2018-01-01'
group by monthname(grid_header.`EntryDate`)
order by max(month(grid_header.`EntryDate`));
FY grid_calc table looks like this.
GridID
Price
Teeth
FeedType
WtMin
WtMax
SexCategory
ID
9851
5.3
2
434
300
340
438
140177
9851
5.2
2
434
260
280
438
140178
9851
5.25
4
434
300
420
438
140179
9851
5.2
6
434
300
420
438
140180
9851
5.15
8
434
300
420
438
140181
9851
4.05
8
434
320
500
439
140182
grid_header table looks like this
GridID
EntryDate
BuyerID
ConfigID
9851
23/01/2019
236
1
9851
23/01/2019
236
1
9851
23/01/2019
236
1
9851
23/01/2019
236
1
9851
23/01/2019
236
1
9851
23/01/2019
236
1
Many thanks in advance!
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)
I have a table named inventory_store.
Table name: inventory_store
date invoice_no permit_no quantity item_name
2014-01-21 121 111 10 A
2014-01-21 121 111 40 B
2014-01-21 121 111 10 C
2014-01-21 121 111 20 C
2014-01-21 122 112 20 A
2014-01-21 122 112 30 B
2014-01-21 122 112 60 C
2014-01-21 122 112 20 C
i want to merge data on the basis of four column(date,invoice_no,permit_no,item_name) of table inventory_store,and want to get output like i have shown below.
OUTPUT:
date invoice_no permit_no total_quantity(A+B) total_quantity(C)
2014-01-21 121 111 50 30
2014-01-21 122 112 50 80
Thanks in advance.
Just do this with conditional aggregation:
select date, invoice_no, permit_no,
sum(case when item_name in ('A', 'B') then quantity else 0 end) as A_B,
sum(case when item_name in ('C') then quantity else 0 end) as C
from inventory_store
group by date, invoice_no, permit_no
order by date, invoice_no, permit_no;
I have a running inventory table of different products that records the inventory count after every transaction. Transactions do not happen every day, so the table does not have a running daily count.
I need to have all dates listed for each product so that I can sum and average the counts over a period of time.
inventory
DATE ID Qty Count
2014-05-13 123 12 12
2014-05-19 123 -1 11
2014-05-28 123 -1 10
2014-05-29 123 -3 7
2014-05-10 124 5 5
2014-05-15 124 -1 4
2014-05-21 124 -1 3
2014-05-23 124 -3 0
I have a table that includes dates for a Join, but I am not sure how to make the missing dates join over multiple products.
I need the query as follows. It needs to to return the counts over the a period selected, but also include dates inbetween.
DATE ID Qty Count
2013-05-01 123 0 0
2013-05-02 123 0 0
2013-05-03 123 0 0
2013-05-04 123 0 0
2013-05-05 123 0 0
2013-05-06 123 0 0
2013-05-07 123 0 0
2013-05-08 123 0 0
2013-05-09 123 0 0
2013-05-10 123 0 0
2013-05-11 123 0 0
2013-05-12 123 0 0
2014-05-13 123 12 12
2013-05-14 123 0 12
2013-05-15 123 0 12
2013-05-16 123 0 12
2013-05-17 123 0 12
2013-05-18 123 0 12
2014-05-19 123 -1 11
2013-05-20 123 0 11
2013-05-21 123 0 11
2013-05-22 123 0 11
2013-05-23 123 0 11
2013-05-24 123 0 11
2013-05-25 123 0 11
2013-05-26 123 0 11
2013-05-27 123 0 11
2014-05-28 123 -1 10
2014-05-29 123 -3 7
2013-05-30 123 0 7
2013-05-31 123 0 7
2013-05-01 124 0 0
2013-05-02 124 0 0
2013-05-03 124 0 0
2013-05-04 124 0 0
2013-05-05 124 0 0
2013-05-06 124 0 0
2013-05-07 124 0 0
2013-05-08 124 0 0
2013-05-09 124 0 0
2014-05-10 124 5 5
2014-05-11 124 0 5
2014-05-12 124 0 5
2014-05-13 124 0 5
2014-05-14 124 0 5
2014-05-15 124 -1 4
2014-05-16 124 0 4
2014-05-17 124 0 4
2014-05-18 124 0 4
2014-05-19 124 0 4
2014-05-20 124 0 4
2014-05-21 124 -1 3
2014-05-22 124 0 3
2014-05-23 124 -3 0
2014-05-24 124 0 0
2014-05-25 124 0 0
2014-05-26 124 0 0
2014-05-27 124 0 0
2014-05-28 124 0 0
2014-05-29 124 0 0
2014-05-30 124 0 0
2014-05-31 124 0 0
Use inv join inv to build up at least 31 rows and construct a table of 31 days. Then join the ids, and finally the original table.
select a.d, a.id, a.qty,
if(a.id=#lastid, #count:=#count+a.qty, #count:=a.count) `count`,
#lastid:=a.id _lastid
from (
select a.d, b.id, ifnull(c.qty, 0) qty, ifnull(c.count, 0) `count`
from (
select adddate('2014-05-01', #row) d, #row:=#row+1 i
from inv a
join inv b
join (select #row := 0) c
limit 31) a
join (
select distinct id
from inv) b
left join inv c on a.d = c.date and b.id = c.id
order by b.id, a.d) a
join (select #count := 0, #lastid := 0) b;
fiddle
Here are the steps needed:
Get all dates between the two given dates.
Get the initial stock per ID. This is: get the first date on or after the given start date for that ID, read this record's stock and subtract its transaction quantity.
For every date get the previous stock. If there is a record for this date, then add its transaction quantity and compare the result with its stock quantity. Throw an error if values don't match. (This is because you store data redundantly; a record's quantity must equal the quantity of the previous record plus its own transaction quantity. But data can always be inconsistent, so better check it.) Show the new stock and the difference to the previous stock.
All this would typically be achieved with a recursive CTE for the dates, a derived table for all initial stocks at best using a KEEP DENSE_RANK function, and the LAG function to look into the previous record.
MySQL doesn't support recursive CTEs - or CTEs at all for that matter. You can emulate this with a big enough table and a variable.
MySQL doesn't support the KEEP DENSE_RANK function. You can work with another derived table instead to find the minimum date per ID first.
MySQL doesn't support the LAG function. You can work with a variable in MySQL instead.
Having said this, I suggest to use a programming language instead (Java, C#, PHP, whatever). You would just select the raw data with SQL, use a loop and simply do all processiong on a per record base. This is much more convenient (and readable) than building a very complex query that does all that's needed. You can do this in SQL, even MySQL; I just don't recommend it.
The SQL I ended up using to resolve this question used a combination of #Fabricators answer (which really was a correct answer) and my edits.
I ended up using an existing table to create the date rows instead of a cross join. The cross join had poor performance for how many products I was working with.
SELECT
POSTDATE,
IF(#PROD_ID = PRODUCT_ID, #NEW := 0, #NEW := 1) AS New_Product,
(#PROD_ID := PRODUCT_ID) AS PRODUCT_ID,
QUANTITY,
IF(#NEW = 1, #INVENTORY := QUANTITY, #INVENTORY := #INVENTORY+QUANTITY) AS 'Count'
FROM (
(
SELECT
POSTDATE,
PRODUCT_ID,
QUANTITY
FROM
inventory
)
UNION ALL
(
SELECT
dateslist_sub.TransDate AS POSTDATE,
productlist_sub.PRODUCT_ID,
0 AS QUANTITY,
FROM
(
SELECT
TransDate
FROM
(
SELECT
adddate('2013-05-01', #row) AS TransDate,
#row:=#row+1 i
FROM
any_table,
(SELECT #row := 0) row
) datestable
WHERE
TransDate <= CURDATE()
) dateslist_sub
cross join (
SELECT
PRODUCT_ID
FROM
products_table
ORDER BY
PRODUCT_ID ASC
) productlist_sub
ORDER BY
productlist_sub.PRODUCT_ID ASC,
dateslist_sub.TransDate ASC
)
ORDER BY
PRODUCT_ID ASC,
POSTDATE ASC
) daily_rows_sub
I'm having the following data set (note that my database/schemata is somewhat complex so it's not feasible to include all the details here)
This is a simplified version of my data which I extracted from my base tables and created a view.
workout_activity_record_id attribute_metric_id attribute_metric_value workout_exercise_set_created_on
234 17 10 2012-02-06 00:00:00
234 18 30 2012-02-06 00:00:00
234 17 20 2012-03-03 00:00:00
234 18 12.9 2012-03-03 00:00:00
234 17 20 2012-04-02 00:00:00
234 18 40 2012-04-02 00:00:00
.
.
. (So on for further workout_activity_record_ids)
I need to compute (look up in the data to understand better)
Grand Total = (10 * 30) + (20 * 12.9) + (20 * 40) grouped by month.
A basic approach here that would aid in multiplying is transpose the rows into columns. So the above structure would become -
workout_activity_record_id ex17 ex18 workout_exercise_set_created_on
234 10 30 2012-02-06 00:00:00
234 20 12.9 2012-03-03 00:00:00
234 20 40 2012-04-02 00:00:00
.
.
.
.
. (And so on for remaining workout_activity_record_ids)
For this, I went through several SO posts and after trying out various viable/non-viable (:D) options, I came up with the following query.
SELECT
CASE attribute_metric_id
WHEN '17' THEN attribute_metric_value END AS 'ex17',
CASE attribute_metric_id WHEN '18' THEN attribute_metric_value END AS 'ex18',
workout_exercise_set_created_on
FROM exercise_attribute
WHERE workout_activity_record_id =234
And the actual output I got was
workout_activity_record_id ex17 ex18 workout_exercise_set_created_on
234 10 NULL 2012-02-06 00:00:00
234 NULL 30 2012-02-06 00:00:00
234 20 NULL 2012-03-03 00:00:00
234 NULL 12.9 2012-03-03 00:00:00
234 20 NULL 2012-04-06 00:00:00
234 NULL 40 2012-04-02 00:00:00
Can anyone shed some light over this? I'd be grateful. Thanks!
This computes the grand total for you, grouped by year and month:
SELECT YEAR(workout_exercise_set_created_on) AS YEAR,
MONTH(workout_exercise_set_created_on) AS MONTH,
sum(SubTotal) AS GrandTotal
FROM
(SELECT workout_exercise_set_created_on,
max(CASE WHEN attribute_metric_id = 17 THEN attribute_metric_value END) * max(CASE WHEN attribute_metric_id = 18 THEN attribute_metric_value END) AS SubTotal
FROM MyTable
GROUP BY workout_exercise_set_created_on) a
GROUP BY YEAR(workout_exercise_set_created_on),
MONTH(workout_exercise_set_created_on)
SQL Fiddle Example
Output
YEAR MONTH GRANDTOTAL
2012 2 300
2012 3 258
2012 4 800
Just add aggregate function :
SELECT
MAX(CASE attribute_metric_id
WHEN '17' THEN attribute_metric_value
END) AS 'ex17',
MAX(CASE attribute_metric_id
WHEN '18' THEN attribute_metric_value
END) AS 'ex18',
workout_exercise_set_created_on
FROM exercise_attribute
WHERE workout_activity_record_id =234
GROUP BY workout_exercise_set_created_on
If you need to show results for different workout_activity_record_id you should modify group by workout_activity_record_id,workout_exercise_set_created_on