I build query to get stock of each item from transaction data like this:
id id_item item_name qty multipler no_seal no_pallet Activity
---------------------------------------------------------------------------
1 23 Apple 20 1 SE002 PL123 IN
2 23 Apple 5 1 SE002 PL123 IN
3 23 Apple 10 -1 SE002 PL123 OUT
4 23 Apple 15 0 SE001 PL123 CHANGE_SEAL
5 23 Apple 15 0 SE001 PL055 CHANGE_PALLET
I try to get current stock of the item by query like this
SELECT id_item, item_name, SUM(qty * multipler) AS stock_qty, MAX(no_seal), MAX(no_pallet)
FROM item_transaction
GROUP BY id_item, item_name
id_item item_name qty no_seal no_pallet
-----------------------------------------------
23 Apple 15 SE002 PL123
but I have problem get last state of no_seal and no_pallet, aggregate function MAX() it give maximum value rather than last records,
I could use sub query to fetch max id of each item, but is it overkill to sum millions of data?
I want result stock of item id 23 (Apple) like this for no_seal and no_pallet
id_item item_name qty no_seal no_pallet
-----------------------------------------------
23 Apple 15 SE001 PL055
I'm sorry if my question is unclear, qty 15 come from
20 (in) + 5 (in) - 10 (out) + 0 (15 item change seal) + 0 (15 item change pallet) = 15
You could use an inner join of max id related to the item
SELECT
, a.item_name
, t.stock_qty
, a.no_seal
, a.no_pallet
from item_transaction a
inner join (
select max(id) max_id, SUM(a.qty * a.multipler) stock_qty, item_name
from item_transaction
group by item_name ) t on t.max_id = a.item_id and t.item_name = a.item_name
group by a.item_name
SELECT
*
FROM
(
SELECT id_item, item_name, SUM(qty * multipler) AS stock_qty, MAX(id) AS last_id
FROM item_transaction
GROUP BY id_item, item_name
)
summary
INNER JOIN
item_transaction
ON item_transaction.id = summary.last_id
If you want the last state for one stock item, then you can use
select id_item,
item_name,
no_seal,
no_pallet,
(select sum(qty * multipler) from item_transaction t2 where t2.id_item = t1.id_item) qty
from item_transaction t1
where id = (
select max(id)
from item_transaction t3
where id_item = 23
)
This solution assumes that id is unique and you want item_transaction with highest id.
Related
this is my starting table which provides sales information by Id.
Id
Store_Name
Market
Sales
Main_Product
1
StoreA
Rome
10
a
2
StoreB
Rome
15
b
3
StoreC
Rome
9
c
4
Mag1
Paris
10
a
5
Mag2
Paris
23
b
6
Mag3
Paris
12
c
7
Shop1
London
11
a
8
Shop2
London
31
b
9
Shop3
London
45
c
10
Shop4
London
63
d
In order to build a report and create some dynamic sentences, I will need the dataset to be "paginated" as per below table:
Id
Dimension
Dimension_Name
Sales
Main_Product
1
ShoppingCentre
StoreA
10
a
1
Market
Rome
34
a
2
ShoppingCentre
StoreB
15
b
2
Maket
Rome
34
b
3
ShoppingCentre
StoreC
9
c
3
Market
Rome
34
c
Do you have any tip about how to build the last table starting from the first one?
To sum-up:
The new table will be always by Id
Aggregation of market sales happens at row level where every single shopping centre is located
This is the query that I have built so far but wondering if there is a better and more efficient way to accomplish the same:
with store_temp_table as (
select
id
,Store_Name
,Market
, Main_Product
, sum(Sales) as Sales
from Production_Table
where 1=1
group by
1,2,3,4
)
, market_temp_table as (
select
market
, sum(Sales) as Sales
from Production_Table
where 1=1
group by
1
)
, store_temp_table_refined as(
Select
a.id
,a.Main_Product
, 'ShoppingCentre' as Dimension_Name
,SUM(a.Sales) as Sales
FROM store_temp_table a INNER JOIN
market_temp_table b on a.market = b.market
group by
1,2,3
)
, market_temp_table_refined as (
Select
a.id
,a.Main_Product
, 'Market' as DimensionName
,SUM(b.Sales) as Sales
FROM store_temp_table a INNER JOIN
market_temp_table b on a.market = b.market
group by
1,2,3
)
select * from store_temp_table_refined
union all
select * from market_temp_table_refined
Thank you
Use a CTE that returns the dimensions that you want and cross join it to a query that returns the columns of the table and an additional column with the total sales of each market:
WITH Dimensions(id, Dimension) AS (VALUES
ROW(1, 'ShoppingCentre'),
ROW(2, 'Market')
)
SELECT p.Id,
d.Dimension,
CASE d.id WHEN 1 THEN p.Store_Name ELSE p.Market END Dimension_Name,
CASE d.id WHEN 1 THEN p.Sales ELSE p.MarketSales END Sales,
p.Main_Product
FROM Dimensions d
CROSS JOIN (SELECT *, SUM(Sales) OVER (PARTITION BY Market) AS MarketSales FROM Production_Table) p
ORDER BY p.id, d.id;
Or, with UNION ALL:
SELECT Id,
'ShoppingCentre' Dimension,
Store_Name Dimension_Name,
Sales,
Main_Product
FROM Production_Table
UNION ALL
SELECT Id,
'Market',
Market,
SUM(Sales) OVER (PARTITION BY Market),
Main_Product
FROM Production_Table
ORDER BY Id,
CASE Dimension WHEN 'ShoppingCentre' THEN 1 WHEN 'Market' THEN 2 END;
See the demo.
I have below table where against the quantity I have Expected date of delivery. I need to find the nearest date and sum of quantity that will be shipped in.
Shipment table:-
Item
EDD
Quantity
A
15-Jul
20
A
15-Jul
25
A
18-Jul
15
B
20-Jul
10
B
20-Jul
10
C
25-Jul
5
C
28-Jul
7
The expected out should be
Item
date
Quantity
A
15-Jul
45
B
20-Jul
20
C
25-Jul
5
I have tried below query
SELECT
t2.item
t2.date,
t1.Quantity
FROM ( SELECT
item,
min(EDD) as date
FROM table
GROUP BY item
) AS t2
LEFT JOIN( SELECT
item,
min(EDD) as date,
Quantity
FROM table
GROUP BY item,
Quantity
) AS t1 ON (t2.item = t1.item AND t2.date = t1.date)
the output I am getting is
A - 15-Jul - 20
B - 20-Jul - 10
C - 25-Jul - 5
If I add sum(Quantity) anywhere in the query the result becomes
A - 15-Jul - 60
B - 20-Jul - 20
C - 25-Jul - 12
Need help to rectify the above issue.
Thanks
Assuming table name is shipment
select item, edd, sum(quantity) from shipment
where (item,edd) in (
select item, min(edd) date from shipment group by item
)
group by item, edd
Second version with join (always worth to check which has better execution plan)
select s.item, s.edd, sum(s.quantity) from shipment s
join (
select item, min(edd) min_date from shipment group by item
) m on m.item = s.item and m.min_date = s.edd
group by s.item, s.edd
Hi I have this table.
id lat lng userId
1 12 23 1
2 45 34 2
3 42 34 3
4 33 34 1
5 36 79 2
6 53 98 2
7 23 90 3
8 23 67 1
Here we have three users. (user ids 1,2,3). I want to get lateset record (id column max value) of each user.
My excepted output is this
userId lat lng
1 23 67
2 53 98
3 23 90
This query will give me group by option
SELECT
*
FROM
covid.locations
GROUP BY userId;
But how do I combine this with MAX(id) function.
One way is to use the following:
SELECT
cl.*
FROM covid.locations cl
INNER JOIN (
SELECT
userid
, MAX( id ) mid
FROM covid.locations
GROUP BY
userId
) g ON cl.userid = g.userid
AND cl.id = cl.mid
Another is to use row_number() over()
SELECT
userId
, lat
, lng
FROM (
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY id DESC) rn
FROM covid.locations
GROUP BY
userId
) d
WHERE rn = 1
Both will identify the "most recent" row in the source table based in the id column of that table. Note that the second query requires MySQL version 8+ as this is when row_number() became supported in that database. The first query should run in dbms supporting SQL.
This will do
SELECT
*
FROM
covid.locations
where id in (select max(t.id) from covid.locations t group by t.userId)
order by id desc;
An example of the above query can be found in this SQLFiddle
I have this table
table name: com_inv
item_name amount date_added
item 1 1 06/06/2015
item 2 2 07/06/2015
item 3 3 08/06/2015
item 1 10 09/06/2015
item 2 20 10/06/2015
item 3 30 11/06/2015
table name: sls_ordrs
item_name amount order_status date_received
item 1 1 received 06/06/2015
item 2 1 delivered
item 3 2 received 08/06/2015
item 1 5 received 09/06/2015
item 2 5 delivered
item 3 2 received 11/06/2015
What I want to achieve is, per item, subtract the sum of the amount in sls_ordrs that have been "received" from the sum of the amount in com_inv. The resulting table should be like this:
Item Name Stocked Dispensed Remaining
item 1 11 6 5
item 2 22 0 22
item 3 33 4 29
If I use SQL Server, I would just use the CTE but with MySql I need your help. This is the code I came up so far...
SELECT
a.item_name,
b.stocked AS 'Stocked',
sum(a.amount) AS 'Dispensed',
IFNULL(b.stocked, 0) - IFNULL(a.amount, 0) AS 'Remaining'
FROM
sls_ordrs a
LEFT JOIN (
SELECT
item_name AS 'item_name',
SUM(amount) AS 'stocked'
FROM
com_inv
GROUP BY
item_name
) b ON a.item_name = b.item_name
WHERE
a.order_status = 'received'
GROUP BY
item_name
The stocked column here gives me a null value.
Use this Query. Hope it should be working fine.
SQL FIDDLE DEMO
SELECT
I.item_name,
I.Stocked,
S.Dispensed,
COALESCE (I.Stocked, 0) - COALESCE (S.Dispensed, 0) AS Remaining
FROM
(
SELECT
item_name AS 'item_name',
SUM(amount) AS 'Stocked'
FROM
com_inv
GROUP BY
item_name
) I
LEFT JOIN (
SELECT
item_name,
order_status,
SUM(amount) AS Dispensed
FROM
sls_ordrs
WHERE
order_status = 'received'
GROUP BY
item_name
) S ON I.item_name = S.item_name;
I currently have a prices table with the following layout:
id codename price discount timestamp
1 1234 599 50 2015-06-10 00:00:00
2 1234 1099 25 2015-06-11 00:00:00
3 3344 199 33 2015-06-12 00:00:00
4 5565 2499 0 2015-06-13 00:00:00
5 5565 1299 50 2015-06-14 00:00:00
I need an SQL query that will give me a single row for each codename. Each row must contain the codename, then the lowest price (along with the associated discount and timestamp for that price), as well as the latest timestamp (again with the associated price and discount for that timestamp)
Desired output:
codename minTimePrice minTimeDis minTime latestPrice latestPriceDis latestPriceTime
1234 599 50 2015-06-10 00:00:00 1099 25 2015-06-11 00:00:00
3344 199 33 2015-06-12 00:00:00 199 33 2015-06-12 00:00:00
5565 1299 50 2015-06-14 00:00:00 1299 50 2015-06-14 00:00:00
EDIT: So I have gotten to where I can have the 2 seperate queries, one gets the row with the MIN(price) and the second gets the row with the MAX(timestamp) for each codename.
Now what I need to do is join them together so that they are all on the same row (grouped by codename) as in the example above.
SQL Fiddle of 2 queries
So after some playing with joins I was able to get the 2 queries to output onto a single row per codename:
SELECT *
FROM
(
SELECT p.*
FROM prices p
JOIN
(
SELECT codename, MIN(price) minPrice
FROM prices GROUP BY codename
) p2
ON p.price = p2.minPrice AND p.codename = p2.codename
) min
LEFT JOIN
(
SELECT p.*
FROM prices p
JOIN
(
SELECT codename, MAX(timestamp) maxTime
FROM prices GROUP BY codename
) p2
ON p.timestamp = p2.maxTime AND p.codename = p2.codename
) latest
ON latest.codename = min.codename
I'm sure the query is far from perfect, but it does give me the results I am looking for.
SQL Fiddle
If there is anything drastically wrong with this, please let me know and I can update.
Try following,
Select codename, minPrice, minDis, minTime, latestPrice, latestDis, latestTime from
(
Select T_Low.codename, minPrice, minDis, minTime, T_Latest.latestPrice, T_Latest.latestDis, T_Latest.latestTime from
(
select * from (
select row_number() over(partition by codename order by codename, price) row_id, codename, price as minPrice, discount as minDis, timestamp as minTime from
(
select codename, discount, timestamp , min(price) as price from prices
group by codename, discount, timestamp
)T
) T1
where row_id = 1
) T_Low
left join
(
select * from (
select row_number() over(partition by codename order by codename, timestamp desc) row_id, codename, price as latestPrice, discount as latestDis, timestamp as latestTime from
(
select codename, discount, timestamp , min(price) as price from prices
group by codename, discount, timestamp
)T
) T1
where row_id = 1
)t_Latest
ON T_Low.codename= T_Latest.codename and T_Low.row_id = T_Latest.row_id
)T
order by codename