SQL NESTED JOIN ISSUES - sql-server

I'm having a heck of a time getting my query to work properly. I have 3 tables (ORDERS, ORDERSITEMS, ORDERPAYMENTS) that I'm trying to build a report for monthly sales taxes due which will look like this:
MONTH YEAR TOTAL RECEIPTS EXEMPT RECEIPTS NON-EXEMPT RECEIPTS SALES TAX
1 2020 $5,000 $4,500 $500 $31.25
TOTAL RECEIPTS: To get this number you have to add together all of the C.OrderPayments_Amount for the given time frame, in this case MONTH(C.OrderPayments_Date) = 1 AND YEAR(C.OrderPayments_Date) = 2020
EXEMPT RECEIPTS: You have to determine if an item is taxable (eg. digital files are not sales taxable, physical prints are). To get this you have determine if the item is taxable by checking the B.OrdersItems_ItemChargeSalesTax. If this field is 0 it does not get charged sales tax and if it is 1 then it does. You then have to filter to only get ORDERSITEMS for the Jan 2020 time frame using by grouping by the C.OrderPayments_Date column that have the B.OrdersItems_ItemChargeSalesTax = 0 and finally add the B.OrdersItems_Total together.
NON-EXEMPT RECEIPTS: To get this number you do the same exact thing for EXEMPT RECEIPTS above except you look for B.OrdersItems_ItemChargeSalesTax = 1 and add the B.OrdersItems_Total together.
SALES TAX: To get this number you use the same date filter as before MONTH(C.OrderPayments_Date) = 1 AND YEAR(C.OrderPayments_Date) = 2020 and then add the A.Order_SalesTax column together.
The first query I have listed is working fine to bring me the total taxes paid and the total income for the month (right now I have hard coded the WHERE statement but that is going to be applied via filters on my list page). What I
need to get from the ORDERSITEMS table is a field called ORDERSITEMS_ItemTotal and sum that field so it is a single line entry on the query. I have seen another person do a nested join. Any suggestions would be greatly appreciated.
**ORDERS TABLE "A"**
Order_ID,
Order_SalesTax,
stateTaxAbbreviation
**ORDERSITEMS TABLE "B"**
Order_FK,
OrdersItems_ItemChargeSalesTax,
OrdersItems_Total
NOTE: In the ORDERSITEMS table a single Order_FK may appear several times as there can be many items on an order
**ORDERPAYMENTS TABLE "C"**
Order_FK,
OrderPayments_PaymentDate,
OrderPayments_Amount
NOTE: In the ORDERPAYMENTS table a single Order_FK may appear several times as there can be multiple payments on an order
While writing this out it seems to be an easy task but when I attempt to put it all together the numbers are wrong because it is adding entries multiple times because there are multiple items on an order and thus it is adding the total payment every time.
Here is the code that I've been tinkering with and I would really appreciate any guidance. Thank you in advance and hopefully I've explained my situation clearly enough.
Select
a.stateTaxAbbreviation AS StateAbbr,
MONTH(c.OrderPayments_Date) AS PaymentMonth,
YEAR(c.OrderPayments_Date) AS PaymentYear,
SUM(c.OrderPayments_Amount) AS TotalPayments,
SUM(a.Order_SalesTax) AS sales_tax
FROM dbo.ORDERS a
INNER JOIN ORDERPAYMENTS as c ON c.Order_FK = a.Order_ID
LEFT OUTER JOIN ORDERITEMS b on b.Order_FK = a.Order_ID
WHERE a.stateTaxAbbreviation = 'MA' AND Month(b.OrderPayments_Date) = 1 AND YEAR(b.OrderPayments_Date) = 2020
GROUP BY stateTaxAbbreviation , MONTH(c.OrderPayments_Date), Year(c.OrderPayments_Date)

You should probably write 2 queries, one where you join the ORDERPAYMENTS table, and another where you join the ORDERITEMS table. Then you can combine them with UNION ALL.
Something like this:
SELECT StateAbbr,PaymentMonth,PaymentYear,SUM(TotalPayments),SUM(sales_tax),SUM(OrdersItems_Total)
FROM (
Select
a.stateTaxAbbreviation AS StateAbbr,
MONTH(c.OrderPayments_Date) AS PaymentMonth,
YEAR(c.OrderPayments_Date) AS PaymentYear,
SUM(c.OrderPayments_Amount) AS TotalPayments,
SUM(a.Order_SalesTax) AS sales_tax,
0 as OrdersItems_Total
FROM dbo.ORDERS a
INNER JOIN ORDERPAYMENTS as c ON c.Order_FK = a.Order_ID
WHERE a.stateTaxAbbreviation = 'MA' AND Month(c.OrderPayments_Date) = 1 AND YEAR(c.OrderPayments_Date) = 2020
GROUP BY stateTaxAbbreviation , MONTH(c.OrderPayments_Date), Year(c.OrderPayments_Date)
UNION ALL
Select
a.stateTaxAbbreviation AS StateAbbr,
MONTH(c.OrderPayments_Date) AS PaymentMonth,
YEAR(c.OrderPayments_Date) AS PaymentYear,
0 AS TotalPayments,
0 AS sales_tax,
SUM(B.OrdersItems_Total) as OrdersItems_Total
FROM dbo.ORDERS a
INNER JOIN ORDERITEMS b on b.Order_FK = a.Order_ID
WHERE a.stateTaxAbbreviation = 'MA' AND Month(b.OrderPayments_Date) = 1 AND YEAR(b.OrderPayments_Date) = 2020
GROUP BY stateTaxAbbreviation , MONTH(c.OrderPayments_Date), Year(c.OrderPayments_Date)
)t
GROUP BY StateAbbr,PaymentMonth,PaymentYear

Thanks to Wouter for pointing me in the right direction. After looking at his suggestion I went back and evaluated what I needed and I create the solution that worked that was based on his idea. Thanks for your patience Wouter, your insight helped a lot!
Select StateAbbr, OrderYear, OrderMonth, SUM(TotalSales) As TotalSales, SUM(TotalSales)-SUM(TaxableRevenue) As ExemptRevenue, SUM(TaxableRevenue) As TaxableRevenue, SUM(SalesTax) As SalesTax
FROM (
Select
/*Get Total Sales and Total Sales Tax Collected*/
a.stateTaxAbbreviation AS StateAbbr,
MONTH(a.Order_Date) As OrderMonth,
YEAR(a.Order_Date) As OrderYear,
SUM((a.Order_TotalBaseSale + a.Order_Shipping) - (((a.Order_PercentDiscount*a.Order_TotalBaseSale)/100) + a.Order_DollarDiscount)) As TotalSales,
SUM(0) As ExemptRevenue,
Sum(0) As TaxableRevenue,
SUM(a.Order_SalesTax) AS SalesTax
FROM dbo.ORDERS a
WHERE a.Order_Status != 'Cancelled'
Group By a.stateTaxAbbreviation, MONTH(a.Order_Date), YEAR(a.Order_Date)
UNION ALL
Select
/*GET EXEMPT ORDERS*/
a.stateTaxAbbreviation AS StateAbbr,
MONTH(a.Order_Date) As OrderMonth,
YEAR(a.Order_Date) As OrderYear,
Sum(0) As TotalSales,
Sum(OrdersItems_ItemTotal) AS ExemptRevenue,
Sum(0) AS TaxableRevenue,
Sum(0) As SalesTax
FROM ORDERSITEMS b
LEFT JOIN ORDERS a ON Order_ID = b.Order_FK
WHERE b.OrdersItems_ItemChargeSalesTax = 0 and a.Order_Status != 'Cancelled'
Group By a.stateTaxAbbreviation, MONTH(a.Order_Date), YEAR(a.Order_Date)
UNION ALL
Select
/*GET NON-EXEMPT ORDERS*/
a.stateTaxAbbreviation AS StateAbbr,
MONTH(a.Order_Date) As OrderMonth,
YEAR(a.Order_Date) As OrderYear,
SUM(0) As TotalSales,
SUM(0) AS ExemptRevenue,
Sum(OrdersItems_ItemTotal) AS TaxableRevenue,
Sum(0) As SalesTax
FROM ORDERSITEMS b
LEFT JOIN ORDERS a ON Order_ID = b.Order_FK
WHERE b.OrdersItems_ItemChargeSalesTax <> 0 and a.Order_Status != 'Cancelled'
Group By a.stateTaxAbbreviation, MONTH(a.Order_Date), YEAR(a.Order_Date)
)t
GROUP BY StateAbbr, OrderMonth, OrderYear
ORDER BY StateAbbr ASC, OrderYear DESC, OrderMonth ASC

Related

Join in SQL Server when some query doesn't have results

I have a table with stock product movements (MOVSTOCKS) in two warehouses (CodAlm). For simplify the question, I will focus on a single product (with CodArt = C5):
CodArt
DescArt
CodAlm
UnidadesStock
EntranStock
SalenStock
FecDoc
TipDoc
C5
Palet
1
16
16
0
2021-12-31
IN
C5
Palet
2
0
0
0
2021-12-31
IN
C5
Palet
1
3
0
3
2022-01-11
SL
C5
Palet
1
4
0
4
2022-01-20
SL
C5
Palet
1
7
7
0
2022-02-01
EN
C5
Palet
1
6
0
6
2022-02-14
SL
C5
Palet
1
9
9
10
2022-05-01
IN
C5
Palet
2
1
1
0
2022-05-01
IN
C5
Palet
1
2
0
2
2022-06-10
SL
I need to get the stock on a certain day. For this, is necessary obtain stock quantity of the last inventory (TipDoc = IN) and add it purchases quantities (TipDoc = EN) and subtract the sales (TipDoc = SL).
I tried this query:
SELECT MV.CODART, MV.DESCART, MV.CODALM, SC.UNIDADESSTOCK + SUM(MV.ENTRANSTOCK) - SUM(MV.SALENSTOCK) as STOCK
FROM MOVSTOCKS MV
JOIN ( SELECT MV1.CODART, MV1.CODALM, MV2.FECDOC, MV1.UNIDADESSTOCK
FROM MOVSTOCKS MV1
JOIN ( SELECT CODART, CODALM, MAX(FECDOC) FECDOC
FROM MOVSTOCKS
WHERE TIPDOC = 'IN'
GROUP BY CODART, CODALM) MV2
ON MV1.CODART = MV2.CODART AND MV1.CODALM = MV2.CODALM AND MV1.FECDOC = MV2.FECDOC
WHERE MV1.TIPDOC = 'IN' ) SC
ON MV.CODART = SC.CODART AND MV.CODALM = SC.CODALM AND MV.FECDOC > SC.FECDOC
WHERE MV.CODART = 'C5' and MV.FECDOC <= '2022-06-01'
GROUP BY MV.CODART, MV.DESCART, MV.CODALM, SC.UNIDADESSTOCK
ORDER BY MV.CODART, MV.CODALM
With above data example and the query I expected to get following results:
CodArt
DescArt
CodAlm
Stock
C5
Palet
1
9
C5
Palet
2
1
The problem is that after the last inventory (2022-05-01) there have been no movements and then the join query get 0 rows because the filter MV.FECDOC <= '2022-06-01' in the WHERE doesn't get rows. I could modify the 'ON' condition in the join to MV.FECDOC >= SC.FECDOC and then get at least the inventory row, but I shouldn't do that because on inventory day there might be other previous movements that I shouldn't get for stock calculation.
Moreover, I will have the same problem if I want to get stock in a date for a product without inventory movements, because subquery 'SC' won't get rows.
Any help, please?
If you know that the inventory records exist, but the other transaction records might or might not exist afterwards, you will need to select your inventory records first and then LEFT JOIN the other transaction records.
If we only had to select one inventory record, we could start with a SELECT TOP 1 * ... ORDER BY FECDOC DESC with appropriate additional conditions. However, to get the latest inventory record for each of multiple warehouses, it get a bit more complicated. Two approaches that come to mind.
One would be to first select distinct warehouse codes (or perhaps distinct warehouse and product codes) and then CROSS APPLY a subselect to retrieve the latest inventory record for each.
The other approach would be to use the ROW_NUMBER() window function to number the inventory records by descending date (partitioned by warehouse codes and product codes) and then exclude all but row number = 1.
In either case, the next step would be to LEFT JOIN the transaction records, apply a GROUP BY, and SUM() up the results. Since SUM() returns NULL if there are no elements to sum, we need to use the ISNULL() function to assign a default value of zero.
The following two similar queries demonstrate the above approaches.
DECLARE #CODART VARCHAR(10) = 'C5'
DECLARE #AsOfDate DATETIME2 = '2022-06-01'
-- Method 1: SELECT DISTINCT followed by a cross apply
SELECT
SC.CODART, SC.DESCART, SC.CODALM,
SC.UNIDADESSTOCK + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
FROM (
SELECT DISTINCT MV.CODART, MV.CODALM
FROM #MOVSTOCKS MV
WHERE MV.CODART = #CODART
) A
CROSS APPLY (
-- Most recent inventory for each selected CODART, CODALM
SELECT TOP 1 MV1.*
FROM #MOVSTOCKS MV1
WHERE MV1.CODART = A.CODART
AND MV1.CODALM = A.CODALM
AND MV1.TIPDOC = 'IN'
AND MV1.FECDOC <= #AsOfDate
ORDER BY MV1.FECDOC DESC
) SC
LEFT JOIN #MOVSTOCKS MV2
ON MV2.CODART = SC.CODART
AND MV2.CODALM = SC.CODALM
AND MV2.TIPDOC IN ('EN', 'SL')
AND MV2.FECDOC > SC.FECDOC
AND MV2.FECDOC <= #AsOfDate
GROUP BY SC.CODART, SC.DESCART, SC.CODALM, SC.UNIDADESSTOCK
ORDER BY SC.CODART, SC.CODALM
-- Method 2: Using the ROW_NUMBER() window function
SELECT
SC.CODART, SC.DESCART, SC.CODALM,
SC.UNIDADESSTOCK + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
FROM (
-- Most recent inventory at or before #AsOfDate will have Recency = 1
SELECT MV1.*,
ROW_NUMBER() OVER(PARTITION BY CODART, CODALM ORDER BY FECDOC DESC) AS Recency
FROM #MOVSTOCKS MV1
WHERE MV1.FECDOC <= #AsOfDate
AND MV1.TIPDOC = 'IN'
) SC
LEFT JOIN #MOVSTOCKS MV2
ON MV2.CODART = SC.CODART
AND MV2.CODALM = SC.CODALM
AND MV2.FECDOC > SC.FECDOC
AND MV2.FECDOC <= #AsOfDate
AND MV2.TIPDOC IN ('EN', 'SL')
WHERE SC.Recency = 1
AND SC.CODART = #CODART
GROUP BY SC.CODART, SC.DESCART, SC.CODALM, SC.UNIDADESSTOCK
ORDER BY SC.CODART, SC.CODALM
Both queries above produce the desired result. See this db<>fiddle for a working demo.
*** UPDATE *** To handle cases where we might have transactions (added stock and/or sales) but no prior reference inventory, we will need to assume an initial inventory of zero and include all transactions since the beginning-of-time (start or data). This also requires making the initial SELECT DISTINCT the primary source for product and warehouse information. The CROSS APPLY becomes an OUTER APPLY (similar to a LEFT JOIN) and we need to make other adjustments to handle a possible null inventory record. That includes adjusting the date range for the transaction join.
The updated query would be something like:
SELECT
A.CODART, A.DESCART, A.CODALM,
ISNULL(SC.UNIDADESSTOCK, 0) + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
, SC.UNIDADESSTOCK AS PriorInventory
, SUM(MV2.ENTRANSTOCK) AS NewStock
, SUM(MV2.SALENSTOCK) as Sales
FROM (
SELECT DISTINCT MV.CODART, MV.DESCART, MV.CODALM
FROM #MOVSTOCKS MV
WHERE MV.CODART = #CODART
) A
OUTER APPLY (
-- Most recent inventory for each selected CODART, CODALM combination
SELECT TOP 1 MV1.*
FROM #MOVSTOCKS MV1
WHERE MV1.CODART = A.CODART
AND MV1.CODALM = A.CODALM
AND MV1.TIPDOC = 'IN'
AND MV1.FECDOC <= #AsOfDate
ORDER BY MV1.FECDOC DESC
) SC
LEFT JOIN #MOVSTOCKS MV2
-- Transactions since inventory was last recorded
ON MV2.CODART = A.CODART
AND MV2.CODALM = A.CODALM
AND MV2.TIPDOC IN ('EN', 'SL') -- Alternately <> 'IN' or omitted entirely.
AND MV2.FECDOC > ISNULL(SC.FECDOC, '1900-01-01')
AND MV2.FECDOC <= #AsOfDate
GROUP BY A.CODART, A.DESCART, A.CODALM, SC.UNIDADESSTOCK
ORDER BY A.CODART, A.CODALM
See this db<>fiddle for an updated demo. For this demo, I added a new stock record for warehouse 3 and set the #AsOfDate to '2022-12-31'. I also added details to the result showing the separate initial inventory, new stock, and sales that feed the final STOCK calculation.
CODART
DESCART
CODALM
STOCK
PriorInventory
NewStock
Sales
C5
Palet
1
7
9
0
2
C5
Palet
2
1
1
null
null
C5
Palet
3
6
null
6
0
The above includes cases having inventory with transactions, inventory but no transactions, and transactions with no initial inventory.
I abandoned the ROW_NUMBER() alternate approach.

SQL Server return distinct rows?

I'm running this SQL statement:
SELECT
s.indx, S.custid, S.date, S.qty, S.item, S.price, S.extprice,
S.salestax, S.linetotal, S.salenbr, C.company, P.MOP
FROM
sales S
JOIN
cust C ON S.custid = C.custid
JOIN
pmts P ON S.salenbr = p.salenbr
WHERE
(s.salenbr = 16749)
It's returning this result set:
indx custid date qty item price extprice salestax linetotal salenbr company MOP
170835 695 2021-09-27 10:00:44.000 1.00 1X4X12 7.85 7.85 0.75 8.60 16749 COUNTER SALE CS
170835 695 2021-09-27 10:00:44.000 1.00 1X4X12 7.85 7.85 0.75 8.60 16749 COUNTER SALE CC
170836 695 2021-09-27 10:00:44.000 1.00 1X6X12 11.62 11.62 1.10 12.72 16749 COUNTER SALE CS
170836 695 2021-09-27 10:00:44.000 1.00 1X6X12 11.62 11.62 1.10 12.72 16749 COUNTER SALE CC
I want to just pull the rows where the method of payment "MOP" is different. I'm using the data to run a report and need it just with distinct or unique MOP's.
Thank You
You could use ROW_NUMBER here an arbitrarily take the "first" record from each MOP group, according to some order:
WITH cte AS (
SELECT s.indx, S.custid, S.date, S.qty, S.item, S.price, S.extprice,
S.salestax, S.linetotal, S.salenbr, C.company, P.MOP,
ROW_NUMBER() OVER (PARTITION BY P.MOP ORDER BY S.date) rn
FROM sales S
INNER JOIN cust C ON S.custid = C.custid
INNER JOIN pmts P ON S.salenbr = P.salenbr
WHERE S.salenbr = 16749
)
SELECT indx, custid, date, qty, item, price, exitprice,
salestax, linetotal, salenbr, company, MOP
FROM cte
WHERE rn = 1;
So, what you want to do will probably work better using a Common Table Expression or CTE. Something like this:
WITH CTE_Sales AS
(
SELECT
s.indx, S.custid, S.date, S.qty, S.item, S.price, S.extprice,
S.salestax, S.linetotal, S.salenbr, C.company, P.MOP,
COUNT(1) AS salesCount
FROM
sales S
JOIN
cust C ON S.custid = C.custid
JOIN
pmts P ON S.salenbr = p.salenbr
GROUP BY
s.indx, S.custid, S.date, S.qty, S.item, S.price, S.extprice,
S.salestax, S.linetotal, S.salenbr, C.company, P.MOP
)
SELECT
indx, custid, date, qty, item, price, extprice,
salestax, linetotal, salenbr, company
FROM
CTE_Sales
GROUP BY
indx, custid, date, qty, item, price, extprice,
salestax, linetotal, salenbr, company
HAVING
salesCount > 1
What this does is that the CTE contains all your data, which makes it easier to not deal with joins every time. You've also done a group by so you know how many records you have for the same sale.
Then, when you pull the data, you're grouping the records without the MOP. Since the first record is grouped with MOP and the second is grouped without, you know that the MOPs are different.
Me thinks I need to go back and do some redesigning in my code and data tables SMor you are correct about the details vs. the transactions. Live and learn :) Thanks to you all for taking the time to respond. I work solo so It's always great to hear other comments and ideas. Thanks!

Look at data in one date range and count from another date range

I'm stuck on a query where I am trying to get information on just customers that are newly acquired during a certain date range.
I had need to get a list of customers who placed their first order (of all time) in the first 6 months of the year. I then need to get total of their invoices, first invoice date, last invoice date, and count of orders for just the last 6 months.
I used a HAVING clause to ensure that I am just looking at customers that placed their first order in that 6 month period, but since we are past that period now, the total invoice info and order count information would include orders placed after this time. I considered including a restriction in the HAVING clause for the 'last invoice date', but then I am eliminating customers whose first order date was in the 6 month block, but also ordered after that. I'm not sure what to do next and am not having luck finding similar questions. Here is what I have so far:
SELECT c.customer, MAX(c.name) AS Name,
SUM(
CASE WHEN im.debit = 0
THEN im.amount * -1
ELSE im.amount
END
) AS TotalInvoiceAmount,
MIN(
im.date) AS FirstInvoiceDate,
MAX(
im.date) AS LastInvoiceDate,
COUNT(DISTINCT om.[order]) AS OrderCount
FROM invoicem im
INNER JOIN customer c ON im.customer = c.customer
FULL JOIN orderm om ON im.customer = om.customer
WHERE im.amount <> 0
GROUP BY c.customer
HAVING MIN(im.date) BETWEEN '01-01-2015' AND '06-30-2015'
ORDER BY c.customer
You can put the first 6 months qualification as a subquery. This would also work as a CTE
declare #startDate date = dateadd(month,-6,getdate())
SELECT c.customer, MAX(c.name) AS Name,
SUM(
CASE WHEN im.debit = 0
THEN im.amount * -1
ELSE im.amount
END
) AS TotalInvoiceAmount,
MIN(
im.date) AS FirstInvoiceDate,
MAX(
im.date) AS LastInvoiceDate,
COUNT(DISTINCT om.[order]) AS OrderCount
FROM invoice im
INNER JOIN (SELECT customer from invoice
GROUP BY customer
HAVING MIN(date) BETWEEN '01-01-2015'
AND '06-30-2015') im2
ON im.customer = im2.customer
INNER JOIN customer c ON im.customer = c.customer
FULL JOIN orderm om ON im.customer = om.customer
WHERE im.amount <> 0
AND im.date >= #startdate
GROUP BY c.customer
ORDER BY c.customer

ISNULL() for calculated column in Full Join. SQL Server

I'm currently facing a problem when calculating the standard deviation in an SQL Server statement.
My problem: I have two tables.
T1:
Reg_Month
---------
1
2
3
...
T2:
Product Month Consumption
-------------------------------
ProdA 1 200
ProdB 1 10
ProdA 1 300
ProdC 2 100
ProdA 2 200
...
Now what I want is something like this, for calculating my STDEV over a year:
Reg_Month Product Month Sum
---------------------------------
1 ProdA 1 500
1 ProdB 1 10
1 ProdC 1 0
2 ProdA 2 200
2 ProdB 2 0
2 ProdC 2 0
So now I don't need this table to be set up, but I need to calculate the STDEV and AVG of the column "Sum" for each Product. The Problem is to include the NULLS.
This gives me the table I want for ProdA, but with NULLS whenever there was no consumption:
SELECT *
FROM T1
FULL JOIN (SELECT Product, Month, SUM(Consumption) AS Sum,
FROM T2
WHERE (Product = 'ProdA')
GROUP BY Month, Product) sub ON (T1.Reg_Month = T2.Month)`
This gives me the STDEV:
SELECT Stdev(Sum)
FROM
(SELECT *
FROM T1
FULL JOIN (SELECT Product, Month, SUM(Consumption) AS Sum,
FROM T2
WHERE (Product = 'ProdA')
GROUP BY Month, Product) sub ON (T1.Reg_Month = T2.Month)) sub
WHERE Product = 'ProdA'`
But the problem is, that it doesn't give me the correct STDEV for the entire year, if there is a month in which there was no consumption, because the NULLs (that appear due to the join) are ignored.
My approaches:
ISNULL():
SELECT Stdev(Sum)
FROM
(SELECT *
FROM T1
FULL JOIN (SELECT Product, Month, ISNULL(SUM(Consumption), 0) AS Sum,
FROM T2
WHERE (Product = 'ProdA')
GROUP BY Month, Product) sub ON (T1.Reg_Month = T2.Month)) sub
WHERE Product = 'ProdA'`
doesn't work (maybe because the null is generated after the join?)
CASE:
SELECT Stdev(Sum)
FROM
(SELECT *
FROM T1
FULL JOIN (SELECT Product, Month, CASE WHEN SUM(Consumption) IS NULL THEN 0 ELSE Sum(Consumption) END AS Sum,
FROM T2
WHERE (Product = 'ProdA')
GROUP BY Month, Product) sub ON (T1.Reg_Month = T2.Month)) sub
WHERE Product = 'ProdA'
doesn't work (probably the same reason)
I hope I was able to illustrate my example properly. Now, do you have any idea how get the right results for the STDEV?
Your input would be greatly appreciated!
Thanks a lot,
Clemens
if you are only doing one product at a time
SELECT sum(isnull(T2month.MonthSum ,0))
, Stdev(isnull(T2month.MonthSum ,0))
FROM T1
LEFT JOIN
(select Month, sum(Consumption) as MonthSum
from T2
where Product = 'ProdA'
group by Month) T2month
ON T1.Reg_Month = T2month.Month
for all products
SELECT Product.Name
, sum(isnull(T2month.MonthSum ,0))
, Stdev(isnull(T2month.MonthSum ,0))
FROM T1
cross apply
(values ('ProdA'), ('ProdB'), ('ProdC')) Product(Name)
LEFT JOIN
(select Product, Month, sum(Consumption) as MonthSum
from T2
group by Product, Month) T2month
ON T1.Reg_Month = T2month.Month
AND T2month.Product = Product.Name
Group By Product.Name
Hey OP left join does NOT leave out periods
That is what a left join does
select lj.val, isnull(jj.val,0)
from ( values (1), (2), (3), (4) ) lj(val)
left join ( values (1), (2), (4) ) jj(val)
on lj.val = jj.val
order by lj.val

Counting duplicate items in different order

Goal:
To know if we have purchased duplicate StockCodes or Stock Description more than once on difference purchase orders
So, if we purchase Part ABC on Purchase Order 1 and Purchase Order 2, it should return the result of
PurchaseOrders, Part#, Qty
Purchase Order1, Purchase Order2, ABC, 2
I just don't know how to pull the whole code together, more to the point, how do I know if it's occurred on more than 1 Purchase Order without scrolling through all the results , may also have to do with Multiple (Having Count) Statements as I only seem to be doing by StockCode
SELECT t1.PurchaseOrder,
t1.MStockCode,
Count(t1.MStockCode) AS SCCount,
t1.MStockDes,
Count(t1.MStockDes) AS DescCount
FROM PorMasterDetail t1
INNER JOIN PorMasterHdr t2
ON t1.PurchaseOrder = t2.PurchaseOrder
WHERE Year(t2.OrderEntryDate) = Year(Getdate())
AND Month(t2.OrderEntryDate) = Month(Getdate())
GROUP BY t1.PurchaseOrder,
t1.MStockCode,
t1.MStockDes
HAVING Count(t1.MStockCode) > 1
Using responses I came up with the following
select * from
(
SELECT COUNT(dbo.InvMaster.StockCode) AS Count, dbo.InvMaster.StockCode AS StockCodes,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
FROM dbo.InvMaster INNER JOIN dbo.PorMasterDetail ON
dbo.InvMaster.StockCode = dbo.PorMasterDetail.MStockCode
INNER JOIN dbo.PorMasterHdr ON dbo.PorMasterDetail.PurchaseOrder = dbo.PorMasterHdr.PurchaseOrder
WHERE YEAR(dbo.PorMasterHdr.OrderEntryDate) = YEAR(GETDATE())
GROUP BY dbo.InvMaster.StockCode, dbo.InvMaster.StockCode,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
) Count
Where Count.Count > 1
This returns the below , which is starting to be a bit more helpful
In result line 2,3,4 we can see the same stock code (*30044) ordered 3 times on different
purchase orders.
I guess the question is, is it possible to look at If something was ordered more than once within say a 30 day period.
Is this possible?
Count StockCodes PurchaseOrder OrderEntryDate
2 *12.0301.0021 322959 2014-09-08
2 *30044 320559 2014-01-21
8 *30044 321216 2014-03-26
4 *30044 321648 2014-05-08
5 *32317 321216 2014-03-26
4 *4F-130049/TEST 323353 2014-10-22
5 *650-1157/E 322112 2014-06-24
2 *650-1757 321226 2014-03-27
SELECT *
FROM
(
SELECT h.OrderEntryDate, d.*,
COUNT(*) OVER (PARTITION BY d.MStockCode) DupeCount
FROM
PorMasterHdr h
INNER JOIN PorMasterDetail d ON
d.PurchaseOrder = h.PurchaseOrder
WHERE
-- first day of current month
-- http://blog.sqlauthority.com/2007/05/13/sql-server-query-to-find-first-and-last-day-of-current-month/
h.OrderEntryDate >= CONVERT(VARCHAR(25), DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)
) dupes
WHERE
dupes.DupeCount > 1;
This should work if you're only deduping on stock code. I was a little unclear if you wanted to dedupe on both stock code and stock desc, or either stock code or stock desc.
Also I was unclear on your return columns because it almost looks like you're wanting to pivot the columns so that both purchase order numbers appear on the same line.

Resources