how to count quantity of different between 2 tables? - sql-server

i need to count different between 2 tables (same table from 2 different days) to see what have changed.
for example table 1:
table 2:
and i want to get this table:
i try this code:
select a.of_key , case when a.color != b.color then count (a.color) ELSE 0 END AS color,
case when a.side != b.side then count (a.side) else 0 end as side
from 130720 A right JOIN 100720 B
ON a.of_key = b.of_key and a.num = b.bum
group by a.of_key
it is not working
please help
thanks!

Put your aggregate outside the case statement:
select a.of_key , SUM(case when a.color != b.color then 1 ELSE 0 END) AS color,
SUM(case when a.side != b.side then 1 else 0 end) as side
from 130720 A right JOIN 100720 B
ON a.of_key = b.of_key and a.num = b.bum
group by a.of_key

Related

select distinct with parent-child and return boolean for at least one child with a value?

I am currently searching for orders that have at least one orderline (product) with a certain boolean set:
- the product is a subscription product
- the product is a setup product
If one of the orderlines has this value set to 1, I want to return this in the query per DISTINCT order ID.
This does not seem to work for me:
SELECT DISTINCT [ORDER].[order_id]
,[ORDERLINE].[is_subscription] AS hasSubArticles
,[ORDERLINE].[is_setup] AS hasSetupArticles
FROM [ORDER]
LEFT JOIN [ORDERLINE]
ON [ORDER].[order_id] = [ORDERLINE].[f_order_id]
WHERE [G_ORDER].[status] = 1
ORDER BY [ORDER].[order_id]
,[ORDERLINE].[is_subscription] AS hasSubArticles
,[ORDERLINE].[is_setup] AS hasSetupArticles
When I check the returned records, I receive duplicate ORDER records:
order_id hasSubArticles hasSetupArticles
----------------------------------------
17804 NULL NULL
17804 1 0
I want to return only 1 record per order ID, thus this isn't working for me.
What am I doing wrong?
Distinct does not work for your requirement. MAX, Min functions are not allowed to use with bit type. You could use Group by and SUM like this
SELECT
[ORDER].[order_id]
,CASE WHEN SUM( CASE WHEN [ORDERLINE].[is_subscription] = 1 THEN 1 ELSE 0 END) > 0 THEN 1
ELSE 0
END AS hasSubArticles
,CASE WHEN SUM( CASE WHEN [ORDERLINE].[is_setup] = 1 THEN 1 ELSE 0 END) > 0
THEN 1
ELSE 0
END hasSetupArticles
FROM [ORDER]
LEFT JOIN [ORDERLINE]
ON [ORDER].[order_id] = [ORDERLINE].[f_order_id]
WHERE [G_ORDER].[status] = 1
GROUP BY [ORDER].[order_id]

Calculate a Running Monthly Average in SQL Server

We want to create a data-set which shows the monthly average count in our equipment table broken down by it's status: Active, Scrapped, New.
The more I ponder this it seems that the only way to accomplish this is to first create a container temp table and evaluate each record using a cursor.
Can this be accomplished without a temp table?
The following just shows the fields we're working with:
SELECT a1.statusdate, a1.CreateDate,
RunningTotalActive = count([status]='Active'),
RunningTotalScrapped = count([status]='Scrapped'),
NewEquipment = count(Month(a1.CreateDate) )
FROM dbo.Equipment AS a1
INNER JOIN dbo.Equipment AS a2
ON a2.statusdate <= a1.CreateDate
GROUP BY a1.statusdate
ORDER BY a1.statusdate desc
I'm making a few SWAGs about your data, but the idea is to average the sums over simple counts by month; using CTEs.
; WITH A AS (
SELECT a1.statusdate,
Active = CASE a1.[status] WHEN 'Active' THEN 1 ELSE 0 END,
Scrapped = CASE a1.[status] WHEN 'Scrapped' THEN 1 ELSE 0 END,
New = CASE WHEN a2.statusdate = a1.CreateDate THEN 1 ELSE 0 END --Guessing here that "new" means status date and create date are the same
FROM dbo.Equipment AS a1
INNER JOIN dbo.Equipment AS a2
ON a2.statusdate <= a1.CreateDate --"status" can be older than "create" for a piece of equipment? Not sure I understand this criteria. May need sample data.
), B AS (
SELECT Y = DATEPART(YEAR, statusdate)
, M = DATEPART(MONTH, statusdate)
, SumActive = SUM(Active)
, SumScrapped = SUM(Scrapped)
, SumNew = SUM(New)
FROM A
GROUP BY DATEPART(YEAR, statusdate), DATEPART(MONTH, statusdate)
)
SELECT Y, M,
RunningTotalActive = AVG(SumActive)OVER(PARTITION BY Y,M ORDER BY Y,M),
RunningTotalScrapped = AVG(SumScrapped)OVER(PARTITION BY Y,M ORDER BY Y,M),
NewEquipment = AVG(SumNew)OVER(PARTITION BY Y,M ORDER BY Y,M)
FROM B;
Can you show some sample data?
I had modified your script following my understanding. Can you try it?
SELECT YEAR(a1.statusdate) AS yr,MONTH(a1.statusdate) AS mon,
RunningTotalActive = count(CASE WHEN a1.[status]='Active' THEN 1 ELSE NULL END ), -- or SUM(CASE WHEN [status]='Active' THEN 1 ELSE 0 END ),
RunningTotalScrapped = count(CASE WHEN a1.[status]='Scrapped' THEN 1 ELSE NULL END),
NewEquipment = count(CASE WHEN YEAR(a1.CreateDate)*12+ MONTH(a1.CreateDate)= YEAR(a1.statusdate)*12+ MONTH(a1.statusdate)) THEN 1 ELSE NULL END )
FROM dbo.Equipment AS a1
GROUP BY YEAR(a1.statusdate),MONTH(a1.statusdate)
ORDER BY YEAR(a1.statusdate),MONTH(a1.statusdate) DESC

Second Order By overrides first in SQL Server

In the following code the purchase_price overrides the case order by statement.
SELECT
i.products_mpn, i.active,
i.distributor_code, i.sales_price
FROM
#duplicates d
LEFT JOIN
import i ON i.products_mpn = d.products_mpn
AND i.distributor_code = (SELECT TOP 1 distributor_code
FROM dbo.kting_ICECAT_import
WHERE products_mpn = d.products_mpn
ORDER BY
(SELECT
CASE
WHEN (i.distributor_code = 'x' or i.distributor_code = 'y') AND CAST(stock as int) > 0
THEN 2
WHEN CAST(stock as int) > 0
THEN 1
ELSE 0
END) DESC,
CAST(purchase_price AS decimal(28,12)))
Is there any way to get it to work with ordering by the case statement and then the purchase_price?
If you want the ordering of the CASE statement to be applied first followed by the ordering of the purchase_price, then your ORDER BY already has the terms in the right place. I don't know what SELECT is doing in your CASE expression, or even if your current query runs. Something like this may be what you had in mind:
ORDER BY CASE WHEN (i.distributor_code = 'x' or i.distributor_code = 'y') AND
CAST(stock as int) > 0 THEN 2
WHEN CAST(stock as int) > 0 THEN 1
ELSE 0
END DESC,
CAST(purchase_price AS DECIMAL(28,12))
The problem was in the ORDER BY SELECT. I had used columns from the left join "i.distributor_code" should just have been distributor_code

SQL Server CASE - WHEN - ELSE

I have 2 tables like this:
Table CT: Number, CtID, Date, CTIE
Table VT: Number, VtID, Quantities
And my code:
SELECT
MAX(CT.Date), MAX(CT.CtID), VT.VtID,
SUM(VT.Quantities) AS SumVT,
CASE
WHEN CT.CTIE = 0 THEN SUM(VT.Quantities)
ELSE 0
END AS IMPORT,
CASE
WHEN CT.CTIE = 1 THEN SUM(VT.Quantities)
ELSE 0
END AS EXPORT
FROM
CT
INNER JOIN
VT ON CT.Number = VT.Number
GROUP BY
VT.VtID, CT.CTIE
ORDER BY
VT.VtID
This code works fine but the result is not what I want. With some VtID that have both CTIE = 1 and CTIE = 1, SQL now returns 2 separate rows with same VtID, one for CTIE = 0 and one for CTIE = 1. But I need it to display only 1 row for each VtID instead of 2.
Remove CT.CTIE in the group by and place your case statements inside the aggregate function
SElECT
MAX(CT.Date), MAX(CT.CtID), VT.VtID, SUM(VT.Quantities) AS SumVT,
SUM(CASE WHEN CT.CTIE = 0 THEN VT.Quantities ELSE 0 END) AS IMPORT,
SUM(CASE WHEN CT.CTIE = 1 THEN VT.Quantities ELSE 0 END) AS EXPORT
FROM CT INNER JOIN VT ON CT.Number=VT.Number
GROUP BY VT.VtID
ORDER by VT.VtID

SQL not doing the join correctly

I have a SQL statement with some JOIN condition it is working fine for all of them but not the last one the code is below:
SELECT
A.EMPL_CTG,
B.DESCR AS PrName,
SUM(A.CURRENT_COMPRATE) AS SALARY_COST_BUDGET,
SUM(A.BUDGET_AMT) AS BUDGET_AMT,
SUM(A.BUDGET_AMT)*100/SUM(A.CURRENT_COMPRATE) AS MERIT_GOAL,
SUM(C.FACTOR_XSALARY) AS X_Programp,
SUM(A.FACTOR_XSALARY) AS X_Program,
COUNT(A.EMPLID) AS EMPL_CNT,
COUNT(D.EMPLID),
SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END) AS PRMCNT,
SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END) AS EXPCNT,
(SUM(CASE WHEN A.PROMOTION_SECTION = 'Y' THEN 1 ELSE 0 END)+SUM(CASE WHEN A.EXCEPT_IND = 'Y' THEN 1 ELSE 0 END))*100/(COUNT(A.EMPLID)) AS PEpercent
FROM
EMP_DTL A INNER JOIN EMPL_CTG_L1 B ON A.EMPL_CTG = B.EMPL_CTG
INNER JOIN
ECM_PRYR_VW C ON A.EMPLID=C.EMPLID
INNER JOIN ECM_INELIG D on D.EMPL_CTG=A.EMPL_CTG and D.YEAR=YEAR(getdate())
WHERE
A.YEAR=YEAR(getdate())
AND B.EFF_STATUS='A'
GROUP BY
A.EMPL_CTG,
B.DESCR
ORDER BY B.DESCR
The COUNT(D.EMPLID) is returning the same value as COUNT(A.EMPLID) but I need the count of EMPLIDs for Table D in the join condition, any help?
COUNT() (and also the other GROUP BY aggregate functions) doesn't process only the rows from one of the tables.
They work on all the rows produced by the JOIN. If the JOIN without GROUP BY produces 42 rows then COUNT(*) and COUNT(1) returns 42 while COUNT(A.EMPLID) and COUNT(D.EMPLID) return the number of not-NULL values in those columns.
In order to get the number of rows extracted from one of the tables the you should use COUNT(DISTINCT). It ignores the NULL values and also the duplicates produced by the JOIN.
Change COUNT(D.EMPLID) to COUNT(DISTINCT D.EMPLID).

Resources