SQL still have duplicates after Group By - sql

I'm trying to get a grand total of the qty_on_hand between our 2 warehouses combined but after I do a group by the totals don't combine. I'm not sure what I am doing wrong.
SELECT
sku_master.warehouse,
sku_master.sku
, sku_master.min_on_hand
, sku_master.max_on_hand
, x.total_qty_on_hand
FROM [wms].dbo.[sku_master]
left join
(
SELECT
sku_master.sku, sum(location_inventory.qty_on_hand) as total_qty_on_hand
FROM [wms].[dbo].[location_inventory]
JOIN [wms].dbo.[sku_master] ON location_inventory.sku = sku_master.sku
GROUP BY sku_master.sku) x on sku_master.sku = x.sku
Results
Expected Results

Looks like you want sum all qty_on_hand for each sku. Try something like this using OUTER APPLY
SELECT m.sku,
m.min_on_hand,
m.max_on_hand,
oa.total_qty_on_hand
FROM (SELECT sku,
Min(min_on_hand) min_on_hand,
Max(max_on_hand) max_on_hand
FROM [wms].dbo.[sku_master] m
GROUP BY sku) m
OUTER Apply (SELECT Sum(l.qty_on_hand) AS total_qty_on_hand
FROM [wms].[dbo].[location_inventory] l
WHERE l.sku = m.sku) oa

If you need only the grand total then don't join or just for sample add with a union this
SELECT
sku_master.warehouse,
sku_master.sku
, sku_master.min_on_hand
, sku_master.max_on_hand
, x.total_qty_on_hand
FROM [wms].dbo.[sku_master]
left join
(
SELECT
sku_master.sku, sum(location_inventory.qty_on_hand) as total_qty_on_hand
FROM [wms].[dbo].[location_inventory]
JOIN [wms].dbo.[sku_master] ON location_inventory.sku = sku_master.sku
GROUP BY sku_master.sku) x on sku_master.sku = x.sku
union
SELECT null, null, nullm null, sum(location_inventory.qty_on_hand)
FROM [wms].[dbo].[location_inventory]
JOIN [wms].dbo.[sku_master] ON location_inventory.sku = sku_master.sku
or do the fact you have sku_master.warehouse not grouped and repeated .. remove it form select
SELECT
sku_master.sku
, sku_master.min_on_hand
, sku_master.max_on_hand
, x.total_qty_on_hand
FROM [wms].dbo.[sku_master]
left join
(
SELECT
sku_master.sku, sum(location_inventory.qty_on_hand) as total_qty_on_hand
FROM [wms].[dbo].[location_inventory]
JOIN [wms].dbo.[sku_master] ON location_inventory.sku = sku_master.sku
GROUP BY sku_master.sku) x on sku_master.sku = x.sku

you can use this simple query
SELECT
t.sku,
min(t.min_on_hand) as min_qty_on_Hand,
max(t.max_on_hand) as max_on_hand,
sum(t.total_qty_on_hand) + sum(t2.total_qty_on_hand) as total_qty_on_hand
FROM table1 t
inner join table2 t2
on t.sku = t2.sku
group by t.sku
the attached image shows the process including the result
Note: the result here is same as you mentioned in your question and what you need here just change the table names into your table name

In your request's comments you explain that you prefer one warehouse over the other. In this case you should have a table containing the warehouses with a column for the priority. Thus the query wouldn't have to know about warehouse priorities. (Just imagine you add a warehouse some day - you'd have to change all your queries.)
My query aggregates sku_master records per SKU and warehouse and then picks the best warehouse per SKU. It then joins the aggregated inventory rows by SKU.
Here is the query without a warehouse table.
select
m.warehouse,
m.sku,
m.total_min_on_hand,
m.total_max_on_hand,
li.total_qty_on_hand
from
(
select
sku,
warehouse,
sum(min_on_hand) as total_min_on_hand,
sum(max_on_hand) as total_max_on_hand,
row_number() over (partition by sku
order by case when warehouse = 'XDGM' then 1 else 2 end) as rn
from sku_master
group by sku
) m
join
(
select sku, sum(qty_on_hand) as total_qty_on_hand
from location_inventory
group by sku
) li on li.sku = m.sku
where m.rn = 1; -- only the better warehouse when there is more than one for the SKU
With a warehouse table the from clause would slightly change to:
from
(
select
sku,
warehouse,
sum(min_on_hand) as total_min_on_hand,
sum(max_on_hand) as total_max_on_hand,
row_number() over (partition by sku order by w.priority) as rn
from sku_master sm
join warehouse w on w.warehouse = sm.warehouse
group by sku
) m

Related

Filter between dates grouping 3 tables in SQL Server

I have this SQL in SQL Server:
SELECT
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data,
SUM(ValorUnitario) AS Total,
SUM(Quantidade) AS Quantidade
FROM
Itens
INNER JOIN
Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN
Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE
Cabecalho.Data >= '2016-01-01'
AND Cabecalho.Data <= '2018-12-31'
GROUP BY
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data
ORDER BY
4 DESC
It is returning the following result.
The highlighted values are repeating, I do not want to be repeated, I want to show only once each item and that the Quantidade and Total fields are SUM.
For example:
`Camisa Polo` -> **Quantidade = 23**
`Calça Jeans` -> **Quantidade = 15**
`Camiseta Estampada` -> **Quantidade = 21**
Assuming thate the relation between Sales and SaleItems is based on SalesId
you can use between assign to your_start_date and your_end_date a proper value
select Products.ProductName
, sum(SaleItems.Price)
, sum(SaleItems.Quantity)
from Products
inner join SaleItems on SaleItems.IdProduct = Products.IdProduct
inner join Sales on Sales.IdSale = SaleItems.IdSale
where SaleDate between your_start_date and your_end_date
group by Products.ProductName
In you case remove or aggregated the Cabecalho.Data column eg:
SELECT Itens.Mercadoria
, Mercadoria.Nome
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
or
SELECT Itens.Mercadoria
, Mercadoria.Nome
, max(Cabecalho.Data)
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC

Easy Left Join SQL Syntax

New to SQL and want to complete a LEFT JOIN.
I have two seperate tables with the below code:
SELECT
StockCode, SalesOrder, SUM(OrderQty)
FROM
dbo.IopSalesPerf
WHERE
dbo.IopSalesPerf.CustRequestDate BETWEEN '2017-07-01' AND '2017-07-31'
AND EntrySystemTime = 1
AND Warehouse = '01'
AND StockCode = '001013'
GROUP BY
StockCode,SalesOrder
ORDER BY
StockCode ASC
SELECT
SalesOrder, SUM(NetSalesValue), SUM(QtyInvoiced)
FROM
ArTrnDetail
GROUP BY
SalesOrder
I would like to LEFT JOIN the last table onto the first using SalesOrder as the joining column. Can anyone assist with the syntax?
Simpliest way would be:
SELECT * FROM
(
SELECT StockCode,SalesOrder,sum(OrderQty)
FROM dbo.IopSalesPerf
WHERE dbo.IopSalesPerf.CustRequestDate between '2017-07-01' and '2017-07-31'
and EntrySystemTime = 1 and Warehouse = '01' and StockCode = '001013'
GROUP BY StockCode,SalesOrder
Order BY StockCode ASc
) AS A
LEFT JOIN
(
SELECT SalesOrder,sum(NetSalesValue),sum(QtyInvoiced)
FROM ArTrnDetail
Group by SalesOrder
) AS B
ON A.SalesOrder = B.SalesOrder

Get Distinct results of all columns based on MAX DATE of one

Using SQL Server 2012
I have seen a few threads about this topic but I can't find one that involves multiple joins in the query. I can't create a VIEW on this database so the joins are needed.
The Query
SELECT
p.Price
,s.Type
,s.Symbol
, MAX(d.Date) Maxed
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON
p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
The query works but does not produce distinct results. I am using Order by to validate the results, but it is not required once I get it working. I The result set looks like this.
Price Type Symbol Maxed
10.57 bfus *bbkd 3/31/1989
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
100.8161 cbus 001397AA6 7/21/2005
The result set I want is
Price Type Symbol Maxed
10.77 bfus *bbkd 2/28/1990
100.74049 cbus 001397AA6 8/2/2005
Here were a few other StackOverflow threads I tried but couldn't get t work with my specific query
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
SQL Selecting distinct rows from multiple columns based on max value in one column
If you want data for the maximum date, use row_number() rather than group by:
SELECT ts.*
FROM (SELECT p.Price, s.Type, s.Symbol, d.Date,
ROW_NUMBER() OVER (PARTITION BY s.Type, s.Symbol
ORDER BY d.Date DESC
) as seqnum
FROM AdventDW.dbo.FactPrices p INNER JOIN
dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID INNER JOIN
dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
) ts
WHERE seqnum = 1
ORDER BY s.Symbol;
You should use a derived table since you really only want to group the DateTimeKey table to get the MAX date.
SELECT p.Price ,
s.Type ,
s.Symbol ,
tmp.MaxDate
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s ON s.SecurityID = p.SecurityID
INNER JOIN
( SELECT MAX(d.Date) AS MaxDate ,
d.DateTimeKey
FROM dbo.DimDateTime d
GROUP BY d.DateTimeKey ) tmp ON p.DateTimeKey = tmp.DateTimeKey
ORDER BY s.Symbol;
/*
this is your initial select which is fine because this is base from your original criteria,
I cannot ignore this so i'll keep this in-tact. Instead from here i'll create a temp
*/
SELECT
p.Price
, s.Type
, s.Symbol
, MAX(d.Date) Maxed
INTO #tmpT
FROM AdventDW.dbo.FactPrices p
INNER JOIN dbo.DimSecurityMaster s
ON s.SecurityID = p.SecurityID
INNER JOIN dbo.DimDateTime d
ON p.DateTimeKey = d.DateTimeKey
GROUP BY p.Price ,
s.Type ,
s.Symbol
ORDER BY s.Symbol
SELECT innerTable.Price, innerTable.Symbol, innerTable.Type, innerTable.Maxed
FROM (
SELECT
ROW_NUMBER () OVER (PARTITION BY t1.Symbol, t1.Type, t1.Maxed ORDER BY t1.Maxed DESC) as row
, *
FROM #tmpT AS t1
) AS innerTable
WHERE row = 1
DROP TABLE #tmpT

How to Sum up a field in MS Access

I have 2 tables with same field but with inaccurate data. I've found the difference in price but how do I sum up the field "difference" as a different field for me to make a report on the total of the variance.
SELECT
a.barcode AS BarcodeSUS,
a.sell AS PriceSUS,
b.price AS PricePOS,
a.sell-b.price AS difference
FROM SUS AS a LEFT JOIN POS AS b ON a.barcode = b.barcode
ORDER BY b.price;
If you want the accumulated value in each row this should do the trick:
SELECT
a.barcode AS BarcodeSUS
, a.sell AS PriceSUS
, b.price AS PricePOS
, a.sell-b.price AS difference
, (SELECT
SUM(SUS.sell-POS.price)
FROM SUS
LEFT JOIN POS ON SUS.barcode = POS.barcode
WHERE SUS.barcode <= a.barcode
) AS [accumulated difference]
FROM SUS AS a
LEFT JOIN POS AS b ON a.barcode = b.barcode
ORDER BY a.barcode;
If you want the total difference only:
SELECT
a.barcode AS BarcodeSUS
, a.sell AS PriceSUS
, b.price AS PricePOS
, a.sell-b.price AS difference
, (SELECT
SUM(SUS.sell-POS.price)
FROM SUS
LEFT JOIN POS ON SUS.barcode = POS.barcode
) AS [total difference]
FROM SUS AS a
LEFT JOIN POS AS b ON a.barcode = b.barcode
ORDER BY a.barcode;
"Summing in reports" is explained in detail here: https://support.office.com/en-gb/article/Summing-in-reports-ad4e310d-64e9-4699-8d33-b8ae9639fbf4?omkt=en-GB&ui=en-US&rs=en-GB&ad=GB

How to improve SQL query performance (correlated subqueries)?

I Would like to write the below query in a better & efficient way any help?
SELECT a.assetnum as Asset,
a.assettag as Asset_Tag,
a.manufacturer as Manufacturer,
a.serialnum as Serial,
a.description as Description,
(
SELECT CASE a.isrunning
WHEN 1
THEN 'Operational'
WHEN 0
THEN 'Down'
END
) AS Condition ,
l.kbs_loctag as Location,
(
SELECT TOP 1 wo.wonum
FROM workorder wo
WHERE wo.assetnum = a.assetnum
and wo.worktype = 'UN'
ORDER BY wo.reportdate DESC
) AS Last_Workorder,
(
SELECT wo.statusdate
FROM workorder wo
WHERE wo.wonum IN
(
SELECT top 1 wo.wonum
FROM workorder wo
WHERE wo.assetnum = a.assetnum
AND wo.worktype = 'UN'
ORDER BY wo.reportdate DESC
)
) AS Last_Status_Date,
(
SELECT top 1 lt.memo
FROM labtrans lt
WHERE lt.assetnum = a.assetnum
AND lt.transtype = 'REPAIR'
ORDER BY lt.transdate DESC
) AS Action
FROM asset a
LEFT OUTER JOIN locations l
ON a.location = l.location
WHERE (
a.description like '%WASH%'
or a.description LIKE '%DRYER%'
)
ORDER BY l.location,
a.description
In most cases I prefer to use APPLY operator instead of correlated subquery.
In your case I would suggest the next solution:
SELECT a.assetnum as Asset,
a.assettag as Asset_Tag,
a.manufacturer as Manufacturer,
a.serialnum as Serial,
a.description as Description,
CASE a.isrunning
WHEN 1 THEN 'Operational'
WHEN 0 THEN 'Down'
END AS Condition,
l.kbs_loctag as Location,
wo.wonum AS Last_Workorder,
wo.statusdate AS Last_Status_Date,
lt.memo AS Action
FROM asset a
LEFT OUTER JOIN locations l ON a.location = l.location
OUTER APPLY (
SELECT TOP 1 wonum, statusdate
FROM workorder
WHERE assetnum = a.assetnum
and worktype = 'UN'
ORDER BY reportdate DESC) AS wo
OUTER APPLY (
SELECT top 1 memo
FROM labtrans
WHERE assetnum = a.assetnum
AND transtype = 'REPAIR'
ORDER BY transdate DESC) AS lt
WHERE (
a.description like '%WASH%'
or a.description LIKE '%DRYER%'
)
ORDER BY l.location, a.[description]
BTW - you can find amazing video lesson (from Itzik Ben-Gan)about using APPLY Operator here.