I am trying to compare a table to itself in SQL Server 2012. The table consists of among other columns Client Name, Client Number and Fiscal Year. Within the table there is data for FY15 and FY16 and clients can repeat multiple times.
I am trying to add a column to the table that will stipulate whether the client in each row is either "New" (exists in FY16 but not FY15), "Existing" (exists in FY16 and FY15), or "Lost" (exists in FY15 but not FY16).
I've tried joining the table to itself and using case statements but no luck.
You can do it using a LEFT JOIN:
SELECT c1.Name, c1.Number, c1.FiscalYear,
CASE
WHEN c1.FiscalYear = 2015 AND c2.FiscalYear = 2016 THEN 'Existing'
WHEN c1.FiscalYear = 2015 AND c2.FiscalYear IS NULL THEN 'Lost'
WHEN c1.FiscalYear = 2016 AND c2.FiscalYear = 2015 THEN 'Existing'
WHEN c1.FiscalYear = 2016 AND c2.FiscalYear IS NULL THEN 'New'
END AS category
FROM clients AS c1
LEFT JOIN clients AS c2
ON c1.Name = c2.Name AND
((c1.FiscalYear = 2015 AND c2.FiscalYear = 2016) OR
(c1.FiscalYear = 2016 AND c2.FiscalYear = 2015))
Demo here
If you just want to get category per client name, then you can use a GROUP BY:
SELECT Name,
CASE
WHEN COUNT(DISTINCT FiscalYear) = 2 THEN 'Existing'
WHEN SUM(FiscalYear = 2015) > 0 AND SUM(FiscalYear = 2016) = 0 THEN 'Lost'
WHEN SUM(FiscalYear = 2016) > 0 AND SUM(FiscalYear = 2015) = 0 THEN 'New'
END AS category
FROM clients
WHERE FiscalYear IN (2015, 2016)
GROUP BY Name
Demo here
You also can use the above query to perform an UPDATE:
UPDATE clients
INNER JOIN (
SELECT Name,
CASE
WHEN COUNT(DISTINCT FiscalYear) = 2 THEN 'Existing'
WHEN SUM(FiscalYear = 2015) > 0 AND SUM(FiscalYear = 2016) = 0 THEN 'Lost'
WHEN SUM(FiscalYear = 2016) > 0 AND SUM(FiscalYear = 2015) = 0 THEN 'New'
END AS category
FROM clients
WHERE FiscalYear IN (2015, 2016)
GROUP BY Name
) AS t ON clients.name = t.name
SET clients.category = t.category
Demo here
Version with update:
update customer
set status = case when
(select count(*) from customer C2 where C2. ClientName = customer.ClientName and C2.Year in (2015,2016) ) = 2 then 'Existing'
when
(select count(*) from customer C2 where C2.clientName = customer.ClientName and C2.Year = 2015 ) = 1 then 'Lost'
when
(select count(*) from customer C2 where C2.clientName = customer.ClientName and C2.Year in (2016) ) = 1 then 'New'
end;
Sample in SQL Fiddle here
Related
I have the following query that will pull the status of the courses enrolled for each user. I need to display a single record for that user that will represent the overall status of the courses. As you can see in the query below, it uses case statement to decide the prioritisation of the status. I have tried to use a group by clause but it still shows all the courses in the resultset. Could someone let me know what am I doing wrong in the query
DECLARE #Rep1 INT;
SET #Rep1 = 13119;
SELECT
cr.[CourseID]
, cr.[UserID]
,u.[Code]
,u.[DisplayName]
,t.[Name]
,cr.[CourseResultStatusID] AS [CourseResultStatusID]
,case
when min(case when crs.[Description] = 'Complete' then 1 else 0 end) = 1
then 'Complete'
when max(case when crs.[Description] = 'Fail' then 1 else 0 end) = 1
then 'Fail'
when max(case when crs.[Description] = 'Expired' then 1 else 0 end) = 1
then 'Expired'
when max(case when crs.[Description] = 'In Progress' then 1 else 0 end) = 1
then 'In Progress'
end as [CourseResultStatusDescription]
,c.[PointsRequired]
,cr.[ExpiryDateTime]
FROM [training].[CourseResult] cr
INNER JOIN [training].[Course] c
ON cr.[CourseID] = c.[ID] and c.[IsOptional] = 0 -- and cr.ExpiryDateTime > GetDate() and cr.ExpiryDateTime <= dateadd(dd,30,getdate())
INNER JOIN [training].[CourseResultStatus] crs
ON cr.[CourseResultStatusID] = crs.[ID]
INNER JOIN org.RepresentativeTierHistory rth on rth.RepresentativeID = cr.[UserID] and GetDate() between rth.StartDate and rth.EndDate
INNER JOIN org.tier t on t.ID = rth.TierID
LEFT JOIN [org].[User] u
ON u.[ID] = cr.[UserID]
WHERE cr.[UserID] IN (
SELECT hd.DescendantId FROM org.HierarchyDescendant hd WHERE hd.RepresentativeId = #Rep1 UNION ALL SELECT #Rep1 -- for management exchange info
)
group by cr.[CourseID], cr.[UserID], u.[Code], u.[DisplayName], t.[Name], [CourseResultStatusID],c.[PointsRequired],cr.[ExpiryDateTime]
The result of the query is below. As you can see there are 24 records. It is currently showing all the 6 courses per user. It should ideally only only 4 records.
REsultset that I am looking for
I have a query I've used to extract data from a database:
SELECT a.YOA YOA, a.Claim_Status_Type,
SUM(Cumulative_Total_Incurred_Cost*Exchange_Rate_Multiplier)AS
Cumulative_Total_Incurred_Cost
FROM F_Claims_Monthly_Snapshot a
inner join Dim_period b on (b.Period_Key = a.Accounting_Period_Key)
inner join tgt.Dim_BusinessDate c on (b.Month_End_Date_Key =
c.Business_Date_Key)
inner join tgt.Dim_BusinessUnit h on (a.Business_Unit_Key = h.Business_Unit_Key)
inner join tgt.Dim_Currency ccy on ccy.Currency_Key= a.Currency_Key
inner join tgt.Dim_Currency input_curr on input_curr.Currency_Key = a.Currency_Key
inner join tgt.Fct_CurrencyRate cr on cr.FROM_Currency_Key = a.Currency_Key and cr.Exchange_Date_Key = a.Month_End_Date_Key and Exchange_Rate_Type = 'Actual Rates'
inner join tgt.Dim_Currency report_curr on report_curr.Currency_Key = cr.To_Currency_Key and report_curr.Currency_Code='GBP'
inner join tgt.Dim_PRAClass i on (a.PRA_Class_Key=i.PRA_Class_Key)
inner join tgt.Dim_MasterAgreement j on (a.Master_Agreement_Key = j.Master_Agreement_Key)
inner join tgt.Dim_BusinessDate k on (a.Month_End_Date_Key = k.Business_Date_Key)
WHERE a.YOA between 2014 and 2018
and left(convert(date,(cast(a.Month_End_Date_Key as char(10))),3),8) = left(convert(date,(cast(First_Cost_Movement_Date_Key as char(10))),3),8)
and h.Business_Unit_name = 'Delegated Commercial'
GROUP BY a.YOA,i.PRA_Class,a.Claim_Status_Type;
The Query produces the following table:
YOA Claim_Status Total_Cost
2016 CLOSED 2266634.000000
2014 CLOSED 9880638.990000
2015 OPEN 5904188.060000
2016 CLOSED 4088.570000
2016 OPEN 3589749.000000
2015 CLOSED 22701.000000
2017 OPEN 1001.000000
2017 OPEN 844649.000000
2016 OPEN 6594017.000000
2014 OPEN 50000.000000
2017 OPEN 1835594.810000
2017 CLOSED 112805.000000
2016 CLOSED 4292586.25000
I would now like to alter the table above to look like below:
YOA Open_Total Closed_Total
2017 (SUM of all OPEN Status'for 2017) (SUM of all CLOSED Status' for 2017)
2016 (SUM of all OPEN Status'for 2016) (SUM of all CLOSED Status' for 2016)
2015 (SUM of all OPEN Status'for 2015) (SUM of all CLOSED Status' for 2015)
2014 (SUM of all OPEN Status'for 2014) (SUM of all CLOSED Status' for 2014)
So in short I would like to create a new query which will produce a table that will displayed the:
SUM of all OPEN total_costs for 2016 as new column called 'OPEN total'
SUM of all CLOSED total_costs for 2015 as new column called 'CLOSED_total'
Try with a CASE WHEN inside your SUM(..):
SELECT
a.YOA YOA,
SUM(CASE a.Claim_Status_Type
WHEN N'OPEN'
THEN Cumulative_Total_Incurred_Cost*Exchange_Rate_Multiplier
ELSE 0.0 END) AS Open_Cumulative_Total_Incurred_Cost,
SUM(CASE a.Claim_Status_Type
WHEN N'CLOSED'
THEN Cumulative_Total_Incurred_Cost*Exchange_Rate_Multiplier
ELSE 0.0 END) AS Closed_Cumulative_Total_Incurred_Cost
FROM F_Claims_Monthly_Snapshot a
inner join Dim_period b on (b.Period_Key = a.Accounting_Period_Key)
inner join tgt.Dim_BusinessDate c
on (b.Month_End_Date_Key = c.Business_Date_Key)
inner join tgt.Dim_BusinessUnit h on (a.Business_Unit_Key = h.Business_Unit_Key)
inner join tgt.Dim_Currency ccy on ccy.Currency_Key= a.Currency_Key
inner join tgt.Dim_Currency input_curr on input_curr.Currency_Key = a.Currency_Key
inner join tgt.Fct_CurrencyRate cr on cr.FROM_Currency_Key = a.Currency_Key and cr.Exchange_Date_Key = a.Month_End_Date_Key and Exchange_Rate_Type = 'Actual Rates'
inner join tgt.Dim_Currency report_curr on report_curr.Currency_Key = cr.To_Currency_Key and report_curr.Currency_Code='GBP'
inner join tgt.Dim_PRAClass i on (a.PRA_Class_Key=i.PRA_Class_Key)
inner join tgt.Dim_MasterAgreement j on (a.Master_Agreement_Key = j.Master_Agreement_Key)
inner join tgt.Dim_BusinessDate k on (a.Month_End_Date_Key = k.Business_Date_Key)
WHERE a.YOA between 2014 and 2018
and left(convert(date,(cast(a.Month_End_Date_Key as char(10))),3),8) = left(convert(date,(cast(First_Cost_Movement_Date_Key as char(10))),3),8)
and h.Business_Unit_name = 'Delegated Commercial'
GROUP BY a.YOA;
select yoa, sum(case when claimstatus='open' then Total_Cost else null end) open_total,
sum(case when claimstatus='closed' then Total_Cost else null end) closed_total
from table_name
group by yoa
How to select table column without specify name of column and can apply same condition for all column.
I am Using following SQL query. Can I achieve same result using single line query in SQL server
SELECT FEE.admissionfees AS AMT
,'Admission Fee' amtType
FROM tblFeesDetails FEE
INNER JOIN tblStudentFeeSheet STF ON FEE.feesId = STF.feeId
WHERE feeId = 1
AND enrollMentNo = 'EDU0001'
AND FEE.admissionfees != 0
UNION
SELECT FEE.electricityAndBuildingMaintanance AS AMT
,'Elec. & Buld. Maint. Fee' amtType
FROM tblFeesDetails FEE
INNER JOIN tblStudentFeeSheet STF ON FEE.feesId = STF.feeId
WHERE feeId = 1
AND enrollMentNo = 'EDU0001'
AND FEE.electricityAndBuildingMaintanance != 0
UNION
SELECT FEE.functions AS AMT
,'Functions & Other Act. Fee' amtType
FROM tblFeesDetails FEE
INNER JOIN tblStudentFeeSheet STF ON FEE.feesId = STF.feeId
WHERE feeId = 1
AND enrollMentNo = 'EDU0001'
AND FEE.functions != 0
UNION
SELECT FEE.gamesAndExtraCurriculam AS AMT
,'Games & other Curriculam' amtType
FROM tblFeesDetails FEE
INNER JOIN tblStudentFeeSheet STF ON FEE.feesId = STF.feeId
WHERE feeId = 1
AND enrollMentNo = 'EDU0001'
AND FEE.gamesAndExtraCurriculam != 0
I was wondering if it is possible to use a bound joined table in a CASE statment when declaring a column in a select statment. I have included a simplified example of my problem in the snippet below.Any ideas? Thanks!
SELECT M.MID
,[Count] = CASE (SELECT COUNT(*) FROM Refund R2
WHERE R2.RefundID = R.RefundID) = 1
THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID
The "WHERE R2.RefundID = R.RefundID says that the "R.RefundID cannot be bound.
If you are using SQL Server 2005 or later, you could try a different approach:
SELECT
M.MID,
[Count] = CASE COUNT(*) OVER (PARTITION BY R.RefundID)
WHEN 1 THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID
You have a bad alias. You have an R but not an R2, which is referenced:
SELECT M.MID
,[Count] = CASE WHEN (SELECT COUNT(*) FROM ReferralTypeKey R2
WHERE R2.RefundID = R.RefundID) = 1
THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID
I Have the following SQL Case statement which works perfectly as long as the Years match MF.Date & M.MemberCurrentYear. There will be scenarios where the years do not match and this returns a Balance of NULL. I would like it to return a Zero.
SELECT SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END) AS Balance
FROM dbo.MemberFinancials AS MF
INNER JOIN dbo.Members AS M ON MF.MemberID = M.MemberID
AND DATEPART(yyyy, MF.Date) = M.MemberCurrentYear
INNER JOIN dbo.FinancialTypes AS FT ON MF.FinancialTypeID = FT.FinancialTypeID
Thanks
SELECT
ISNULL(SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END),0) AS Balance
FROM dbo.MemberFinancials AS MF INNER JOIN
dbo.Members AS M ON MF.MemberID = M.MemberID AND DATEPART(yyyy, MF.Date) = M.MemberCurrentYear INNER JOIN
dbo.FinancialTypes AS FT ON MF.FinancialTypeID = FT.FinancialTypeID
Use ISNULL (Or COALESCE if you prefer...)
SELECT ISNULL( SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END), 0) AS Balance
SELECT
COALESCE(
SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END)
, 0) AS Balance