SQL Server: Left outer join on whether ID exists - sql-server

The first three items from table ProviderValueCard add their respective amount if = 1. I'm also trying to add 50 to my TotalScore if the ProviderID exists in table SubscriptionsTV. GroupID is also from SubscriptionsTV in which the condition needs to be met. I beleive I need to have a left outer join in the 2nd query on ProviderID columns from both tables.
DECLARE #ProviderID int = '1717';
WITH cte as(
SELECT TOP 1 ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted
--IF #ProviderID EXISTS SUM(THEN 50 ELSE 0 END)
FROM ProviderValueCard
WHERE ProviderID = #ProviderID
GROUP BY Time_Stamp, ProviderID
ORDER BY Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted) AS TotalScore
FROM cte
--WHERE GroupID = 2
returns
ProviderID Time_Stamp TotalScore
----------- ----------------------- -----------
1717 2014-08-28 13:03:30.593 45
ProviderValueCard table
ProviderID AdditionalReports UniqueReportRequests SurveyCompleted Time_Stamp
----------- ----------------- -------------------- --------------- -----------------------
1717 0 1 1 2014-08-28 13:03:30.593
SubscriptionsTV table
ProviderID GroupID
----------- -----------
1717 2
My final result is this:
DECLARE #ProviderID int = '1717';
WITH cte as(
SELECT TOP 1 a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM ProviderValueCard a
LEFT JOIN SubscriptionsTV b
ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID AND GroupID = 2
GROUP BY Time_Stamp, a.ProviderID, event
ORDER BY event DESC, Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM cte

You are correct that this can be accomplished with a LEFT JOIN, and I'd use MAX() with a CASE statement:
DECLARE #ProviderID int = '1717';
WITH Subs AS (SELECT DISTINCT ProviderID
FROM SubscriptionsTV
)
,cte AS (SELECT TOP 1 a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SurveyCompleted] = '1' THEN 30 ELSE 0 END) as SurveyCompleted,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM ProviderValueCard a
LEFT JOIN Subs b
ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID
GROUP BY Time_Stamp, ProviderID
ORDER BY Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SurveyCompleted + SubscriptionExists) AS TotalScore
FROM cte
Update: Since multiple providerID's can exist, need DISTINCT, used a 2nd cte above, could also use a correlated sub-select inside the CASE statement.
Wasn't paying attention, ORDER BY is fine in a cte when TOP is used.

Related

SQL Server - Query with MAX(CASE ..) and GROUP BY runs too long

I added to my query max() and group by to exclude duplicates and now it's running very long, 56 minutes.
But before adding max() and group by it was running 7-8 min. It's ok, I'm using aggregate view in join and it takes time.
Without max() and group by I had duplicates of customers who opted-in and not opted-in. Where I wanted just to put value "1" if I see that customer has OptIn as "1".
Here is my code:
WITH
cteURC AS (
SELECT
distinct scvid
,MAX(CASE WHEN who = 'urc' AND OptIn = '1' THEN 1 ELSE 0 END) AS URC_OptIn
FROM
scv.OptIn
where who = 'urc'
),
cteSponsor AS (
SELECT
distinct scvid
,MAX(CASE WHEN who = 'sponsor/3rd party' AND OptIn = '1' THEN 1 ELSE 0 END) AS Partner_OptIn
FROM
scv.OptIn
where who = 'sponsor/3rd party'
GROUP BY scvid
),
cteLeinster AS (
SELECT
distinct scvid
,MAX(CASE WHEN who = 'leinster rugby' AND OptIn = '1' THEN 1 ELSE 0 END) AS Leinster_OptIn
FROM
scv.OptIn
where who = 'leinster rugby'
)
SELECT distinct(c.[ScvId])
,Title
,FirstName
,LastName
,EmailAddress
,DateOfBirth
,Address1
,City
,Telephone
,Gender
,URC_OptIn
,Partner_OptIn
,Leinster_OptIn
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2019' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2019
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2018' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2018
FROM scv.vwCustomer c
LEFT JOIN cteURC U ON c.scvid = U.scvid
LEFT JOIN cteSponsor S ON c.ScvId = S.ScvId
LEFT JOIN cteLeinster L on c.ScvId = L.ScvId
LEFT JOIN vwAggTransaction T ON c.ScvId = T.ScvId
group by c.[ScvId]
Title,
FirstName,
LastName,
EmailAddress,
DateOfBirth,
Address1,
City,
Telephone,
Gender,
URC_OptIn,
Partner_OptIn,
Leinster_OptIn,
order by c.scvid
How can I change query to make it run quicker?
Update
I became brave and re-wrote query. I was hesitating as my friend wrote the ctes and I thought that they are necessary.
This version works well and fast. Thank you everyone. I really appreciate your input!
SELECT (c.[ScvId])
,Title
,FirstName
,LastName
,EmailAddress
,DateOfBirth
,Address1
,City
,Telephone
,Gender
,MAX(CASE WHEN who = 'urc' AND OptIn = '1' THEN 1 ELSE 0 END) AS URC_OptIn
,MAX(CASE WHEN who = 'sponsor/3rd party' AND OptIn = '1' THEN 1 ELSE 0 END) AS Partner_OptIn
,MAX(CASE WHEN who = 'leinster rugby' AND OptIn = '1' THEN 1 ELSE 0 END) AS Leinster_OptIn
,MAX(CASE WHEN who = 'connacht rugby' AND OptIn = '1' THEN 1 ELSE 0 END) AS Connacht_OptIn
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2019' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2019
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2018' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2018
FROM vwCustomer c
LEFT JOIN OptIn o ON c.scvid = o.scvid
LEFT JOIN vwAggTransaction T ON c.ScvId = T.ScvId
group by c.[ScvId]
,Title
,FirstName
,LastName
,EmailAddress
,DateOfBirth
,Address1
,City
,Telephone
,Gender
order by c.scvid
I'm taking a stab at it without more information. I converted the CTE into OUTER APPLY. You might need to tweak it a bit for the cases when OptIn=0. Give it a try and see if the performance is any better.
SELECT distinct c.[ScvId]
,Title
,FirstName
,LastName
,EmailAddress
,DateOfBirth
,Address1
,City
,Telephone
,Gender
,URC_OptIn
,Partner_OptIn
,Leinster_OptIn
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2019' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2019
,MAX(CASE WHEN c.ScvId = T.ScvId AND ProductId = '2018' THEN 1 ELSE 0 END) AS FinalTicketPurchaser_2018
FROM scv.vwCustomer c
OUTER APPLY (
SELECT TOP 1 OptIn AS URC_OptIn
FROM scv.OptIn oiu
WHERE oiu.scvid = c.Scvid AND oiu.OptIn = '1' AND oiu.who = 'urc'
) AS U
OUTER APPLY (
SELECT TOP 1 OptIn AS Partner_OptIn
FROM scv.OptIn ois
WHERE ois.scvid = c.Scvid AND ois.OptIn = '1' AND ois.who = 'sponsor/3rd party'
) AS S
OUTER APPLY (
SELECT TOP 1 OptIn AS Leinster_OptIn
FROM scv.OptIn oil
WHERE oil.scvid = c.Scvid AND oil.OptIn = '1' AND oil.who = 'leinster rugby'
) AS L
LEFT JOIN vwAggTransaction T ON c.ScvId = T.ScvId
GROUP BY c.[ScvId]
Title,
FirstName,
LastName,
EmailAddress,
DateOfBirth,
Address1,
City,
Telephone,
Gender,
URC_OptIn,
Partner_OptIn,
Leinster_OptIn,
ORDER BY c.scvid

Need to add a subquery in a CASE expression that is part of an aggregate function

I need to add the number of records in which the status is set to 'reopened'. But the 'reopened' status has several IDs.
This is the subquery that will Id the 'reopen' statuses:
SELECT (CASE WHEN s.sr_status_recid = 1 THEN 1 ELSE 0 END) AS Reopened
from v_rpt_service s
where vsrv.sr_status_recid in
(select distinct SR_Status_RecID from SR_Status where [Description] like '%Re-opened%'))
This is the main query that the above query needs to be a part:
SELECT DATEPART(WK, vsrv.date_entered) as WkNumber,
COUNT(vsrv.TicketNbr) AS OpenedIssues, --total ticket count
SUM(CASE WHEN vsrv.Closed_Flag = 1 THEN 1 ELSE 0 END) AS ClosedIssues, --sum of tickets with closed_flag = 1
(SELECT SUM(CASE WHEN s.sr_status_recid = 1 THEN 1 ELSE 0 END)
from v_rpt_service s
where vsrv.sr_status_recid in
(select distinct SR_Status_RecID from SR_Status where [Description] like '%Re-opened%')) AS ReopenedIssues,
SUM(CASE WHEN vsrvy.Surveys_Completed = 1 THEN 1 ELSE 0 END) AS SurveysCompletedWithConnectWise, -- Surveys_Completed flag in view is 1
SUM(CASE WHEN Source = 'Portal' THEN 1 ELSE 0 END) AS IssueLoggedPortal,
SUM(CASE WHEN Source = 'Email Connector' THEN 1 ELSE 0 END) AS IssueLoggedEmai
FROM v_rpt_service vsrv LEFT OUTER JOIN v_rpt_SurveysByTicket vsrvy ON vsrv.TicketNbr = Vsrvy.SR_Service_RecID
WHERE vsrv.company_name <> 'XYZ Test Company' AND vsrv.date_entered BETWEEN '01/01/2016' AND '10/07/2016'
GROUP BY DATEPART(WK, vsrv.date_entered)
ORDER BY WkNumber
How can I have a subquery that uses a CASE statement and the CASE statement is aggregated?
You can use CROSS APPLY
SELECT DATEPART(WK, vsrv.date_entered) as WkNumber,
COUNT(vsrv.TicketNbr) AS OpenedIssues, --total ticket count
SUM(CASE WHEN vsrv.Closed_Flag = 1 THEN 1 ELSE 0 END) AS ClosedIssues, --sum of tickets with closed_flag = 1
SUM(CountReopen.YesNo) AS NumberOfReopen,
SUM(CASE WHEN vsrvy.Surveys_Completed = 1 THEN 1 ELSE 0 END) AS SurveysCompletedWithConnectWise, -- Surveys_Completed flag in view is 1
SUM(CASE WHEN Source = 'Portal' THEN 1 ELSE 0 END) AS IssueLoggedPortal,
SUM(CASE WHEN Source = 'Email Connector' THEN 1 ELSE 0 END) AS IssueLoggedEmail
FROM v_rpt_service vsrv
LEFT OUTER JOIN v_rpt_SurveysByTicket vsrvy
ON vsrv.TicketNbr = Vsrvy.SR_Service_RecID
CROSS APPLY (
SELECT IIF(COUNT(*) > 0,1,0) YesNo
FROM SR_Status
where [Description] like '%Re-opened%'
AND SR_Status_ID = vsrv.sr_status_recid
) CountReopen(YesNo)
WHERE vsrv.company_name <> 'XYZ Test Company'
AND vsrv.date_entered BETWEEN '01/01/2016' AND '10/07/2016'
GROUP BY DATEPART(WK, vsrv.date_entered)
ORDER BY WkNumber

SQL Server: This created score is multiplying by 4?

The TotalScore result is 320 when it should just be 80(30 + 50) since the top 1 record for ProviderID 874 has SessionsProgress = 3 and the providerID is also present in the joined SubscriptionsTV table.
DECLARE #ProviderID int = '874';
WITH cte as(
SELECT TOP 1 a.ProviderID, Time_Stamp,
SUM(CASE WHEN [AdditionalReports] = '1' THEN 5 ELSE 0 END) as AdditionalReports,
SUM(CASE WHEN [UniqueReportRequests] = '1' THEN 15 ELSE 0 END) as UniqueReportsRequests,
SUM(CASE WHEN [SessionsProgress] > '0' THEN 30 ELSE 0 END) as SessionsProgress,
MAX(CASE WHEN b.ProviderID IS NULL THEN 0 ELSE 50 END) as SubscriptionExists
FROM ProviderValueCard a
LEFT JOIN SubscriptionsTV b
ON a.ProviderID = b.ProviderID
WHERE a.ProviderID = #ProviderID AND GroupID = 2
GROUP BY Time_Stamp, a.ProviderID, event
ORDER BY event DESC, Time_Stamp DESC
)
SELECT ProviderID, Time_Stamp, (AdditionalReports + UniqueReportsRequests + SessionsProgress + SubscriptionExists) AS TotalScore
FROM cte
Here are the 2 records for ProviderID 874 which only the most recent by TimeStamp is used.
ProviderID AdditionalReports UniqueReportRequests Time_Stamp AdditionalReportsNum UniqueReportsNum SessionsProgress AdditionalReportsNumQtr UniqueReportsNumQtr SurveyCompleted
----------- ----------------- -------------------- ----------------------- -------------------- ---------------- ---------------- ----------------------- ------------------- ---------------
874 0 1 2015-01-30 08:13:44.660 0 55 3 0 10 1
874 0 0 2014-12-30 08:31:20.893 0 0 3 0 0 1

How to add Totals in SQL

I am trying to get the totals of each month as of YTD (Years to date) Can someone please help me figure out how to integrate this in my query? thank you This is what I have so far.
DECLARE #Year int
set #Year = 2013
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
From tContact a Join tContract b ON a.contact_id = b.contract_id
Group by a.first_name, a.last_name
This is just an example of how you could count up rows that fall under a certain month.
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)
Hopefully this will help you with your query.
Thanks
What I tried to do here is create an upper bound record for each month in tContract then join that back into the query you already had. It is joined on dates that are between the beginning of the year and the current month.
DECLARE #Year int
set #Year = 2013
select Ms.thismonth, count(B.thing_You_are_Totalling) from (
select thisMonth = dateadd(month,datediff(month,0,Funded_date),0)
from tContract
where moid = 2005405
and year(Funded_date) = #Year
group by dateadd(month,datediff(month,0,Funded_date),0)
) Ms
inner join (select * from tContact a inner join tContract ON a.contact_id = tContract.contract_id) B
on B.Funded_date >=dateadd(year,datediff(year,0,B.Funded_date),0) -- beginning of year
and B.Funded_date <= Ms.thisMonth -- this month
where year(B.Funded_date) = #Year -- restrict to only this year
group by thisMonth, first_name, last_name
I don't have your full table definition so there might be some issues (maybe a SqlFiddle is in order)
Not sure if this is what you are asking for.
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
, COUNT(*) TotalCount
, SUM(CASE WHEN MONTH(b.Funded_date) = 1 THEN Amount ELSE NULL END) JanuaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 2 THEN Amount ELSE NULL END) FebruaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 3 THEN Amount ELSE NULL END) MarchAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 4 THEN Amount ELSE NULL END) AprilAmount
From tContact a Join tContract b ON a.contact_id = b.contact_id
WHERE YEAR(b.Funded_date) = #Year
Group by a.first_name, a.last_name
How about this:
declare #year int = 2013
select a.first_name
, a.last_name
, month(b.Funded_date) [Month]
, datename(month, dateadd(month, month(date_of_birth_dt), - 1)) [MonthName]
, count(month(b.Funded_date)) [Total]
from tContact a
where a.[Year] = #year
group by a.first_name, a.last_name, month(b.Funded_date)
It returns the total of each Month for the year 2013. a.[Year] might not the the name of the field that you have so adjust accordingly. Also, [Month] returns numeric value for month.
Use the Count(*) As Total function. I'm sure this will help you
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)

SQL Server - How to display master details data in columns

I have two tables, to be concise let’s call them TableA and TableB. This is the schema:
TableA
ID – int
Name varchar(50)
TableB
ID – int
TableA_Fk – int
Value varchar(50)
Each record in table A can have at most 9 records in table B. I want to be able to retrieve the data in a columnar form:
TableA-Name, TableB-Value1, … TableB-Value9
Is this possible using queries? Thanks!
You could do something like:
SELECT rank() OVER (ORDER BY tableA_FK) as rank, tableA_fk, value
INTO #temp
FROM TableB b
ORDER BY rank
SELECT a.Name,
CASE WHEN t.rank = 1 THEN t.Value ELSE NULL END AS TableB-Value1,
CASE WHEN t.rank = 2 THEN t.Value ELSE NULL END AS TableB-Value2,
CASE WHEN t.rank = 3 THEN t.Value ELSE NULL END AS TableB-Value3,
.... (etc.)
FROM TableA a
INNER JOIN #temp t ON a.Id = t.tableA_fk
You need Sql Server 2005 or up.
Sorry, but I don't have Sql Server (or the time) to test this well. Hope this gives you an idea and helps.
You will require a LEFT JOIN and a PIVOT table
This should do it, in addition to be DBRM independant.
SELECT A.Name
, SUM(CASE WHEN B.Value = 1 THEN 1 ELSE NULL END) AS B_Value_1
, SUM(CASE WHEN B.Value = 2 THEN 2 ELSE NULL END) AS B_Value_2
, SUM(CASE WHEN B.Value = 3 THEN 3 ELSE NULL END) AS B_Value_3
, SUM(CASE WHEN B.Value = 4 THEN 4 ELSE NULL END) AS B_Value_4
, SUM(CASE WHEN B.Value = 5 THEN 5 ELSE NULL END) AS B_Value_5
, SUM(CASE WHEN B.Value = 6 THEN 6 ELSE NULL END) AS B_Value_6
, SUM(CASE WHEN B.Value = 7 THEN 7 ELSE NULL END) AS B_Value_7
, SUM(CASE WHEN B.Value = 8 THEN 8 ELSE NULL END) AS B_Value_8
, SUM(CASE WHEN B.Value = 9 THEN 9 ELSE NULL END) AS B_Value_9
FROM A
INNER JOIN B ON B.TableA_FK = A.ID
GROUP BY A.Name
ORDER BY A.Name

Resources