I have this extremely long winded query below. I am having issues with running it as it takes forever and keeps timing out on me:
with t as
(
select a.ID,
a.Date_Reported AS [Date Sent],
b.Date_Received AS [Date Returned],
(datediff(dd, a.date_reported, b.date_received)
+ CASE WHEN Datepart(dw, b.date_received) = 7 THEN 1 ELSE 0 END
- (Datediff(wk, a.date_reported, b.date_received) * 2 )
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0 END +
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0
END) AS [Overall_Time_Spent]
from [Transactions_External] a
join [Transactions] b on b.id like '%'+a.id+'%'
where a.customer = 'AA'
AND a.Date_Reported >= DATEADD(MONTH,-1,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0))
AND a.Date_Reported < DATEADD(d,1,EOMONTH(GETDATE(),-1))
AND a.ID IS NOT NULL
AND a.ID <> ''
AND b.ID not like '%_H'
)
select V.*
from
(
select
sum(case when Overall_Time_Spent < 0 then 1 else 0 end) as Errors,
sum(case when Overall_Time_Spent between 0 and 3 then 1 else 0 end) as _0_3_days,
sum(case when Overall_Time_Spent = 4 then 1 else 0 end) as _4_days,
sum(case when Overall_Time_Spent = 5 then 1 else 0 end) as _5_days,
sum(case when Overall_Time_Spent between 6 and 8 then 1 else 0 end) as _6_8_days,
sum(case when Overall_Time_Spent >= 9 then 1 else 0 end) as more_than_9_days,
count(Overall_Time_Spent) as Total
from t
) T1
cross apply
( values
('Count', convert(int, [Errors]), convert(int, [_0_3_days]), convert(int, [_4_days]), convert(int, [_5_days]), convert(int, [_6_8_days]), convert(int, [more_than_9_days]), convert(int, [Total]))
)
v([Time Taken (days)], [Errors], [0-3],[4],[5],[6-8],[9+], [Total])
The query is essentially looking at two tables, joining on id (which is slightly different on either table hence the like on the join) and then finding the difference in two dates to find the overall time spent. Then later on the times are split up into ranges. The query is restricted to last month only.
Any ideas what I can do to make this run faster or change the query about to help it run faster. I think the issue may be in the original select:
datediff(dd, a.date_reported, b.date_received)
+ CASE WHEN Datepart(dw, b.date_received) = 7 THEN 1 ELSE 0 END
- (Datediff(wk, a.date_reported, b.date_received) * 2 )
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0 END +
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0
END) AS [Overall_Time_Spent]
I may be selecting on all the database rather than last month?
one important thing to note is i am unable to create any tables or split the query up- so i really need to run selects and do it in one query. I am not sure this is possible.
join with like and "%" first is not recommended
join [Transactions] b on b.id like '%'+a.id+'%'
Index will not be used on a.id (if any) and it would require full scan. Maybe try to do an EXPLAIN of your query to see number of row scanned
Related
I want to separate the morning and evening patient checked-in count gender-wise and also if gender age less then show the Female child and M child on the basis of gender.
SELECT
COUNT(ch.EnteredOn) AS counter,
CONVERT(date, ch.EnteredOn) AS sessionDay,
SUM(CASE WHEN CAST(CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) < 12 THEN 1 ELSE 0 END) AS 'Morning',
SUM(CASE WHEN CAST(CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) >= 12 THEN 1 ELSE 0 END) AS 'Evening',
SUM(CASE WHEN p.Gender = 1 THEN 1 ELSE 0 END) AS Male,
SUM(CASE WHEN p.Gender = 2 THEN 1 ELSE 0 END) AS Fmale,
SUM(CASE WHEN DATEDIFF(hour, P.DOB, GETDATE()) / 8766 <= 18
AND P.Gender = 1 THEN 1 ELSE 0 END) AS MChild,
SUM(CASE WHEN DATEDIFF(hour, P.DOB, GETDATE()) / 8766 <= 18
AND P.Gender = 2 THEN 1 ELSE 0 END) AS FChild
FROM
Patient.CheckIn ch
INNER JOIN
Patient.Patients P ON ch.PatientId = p.PatientId
GROUP BY
Ch.EnteredOn
I have only three columns like Gender, Time and DOB. Gender id 1 shows the male and Gender id 2 is using for females.
enter image description here
SELECT convert(date, ch.EnteredOn) AS sessionDay, CAST( CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) <12 as morning, count(ch.EnteredOn) AS counter
,sum(case when p.Gender=1 Then 1 ELSE 0 end) as Male
,sum(case when p.Gender=2 Then 1 ELSE 0 end) as Fmale
,Sum( case when DATEDIFF(hour,P.DOB,GETDATE())/8766<=18 AND P.Gender=1 Then 1 ELSE 0 end ) as MChiled
,Sum( case when DATEDIFF(hour,P.DOB,GETDATE())/8766<=18 AND P.Gender=2 Then 1 ELSE 0 end ) as FChiled
FROM Patient.CheckIn ch
inner join Patient.Patients P on ch.PatientId=p.PatientId
Group by Ch.EnteredOn
Group BY can be
Group by convert(date, ch.EnteredOn) AS sessionDay, CAST( CONVERT(CHAR(2), ch.EnteredOn, 108) AS INT) <12
The below query selects all the rows from a master table (there are no duplicates in the table i have checked) and this query counts the number of business days and checks it against a certain number of days, if the count is greater than that certain number of days, it is late, else it is not late. For some reason when I run this query, even with the select DISTINCT, my rows are duplicating. I see a row for each tracking number showing one as Late and the other as Not Late but I don't see how they could possibly be showing both answers? Could anyone help me understand why my rows are being duplicated?
SELECT DISTINCT case UT.[Service] when '0PW' then 'UPS SurePost 1 lb or Greater' else UT.[Service] end as 'Service'
,US.[Region]
,UT.[Tracking_Number] as 'TrackingCounts'
,UT.Manifest_Date
,UT.Date_Delivered
,Ship_To_Postal_Code
,WarehouseLocation
,CASE
WHEN UT.[Service] = 'UPS Ground' AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > UZ.TNTDAYS, 1, 0)
WHEN UT.[Service] in ('UPS SurePost 1 lb or Greater','UPS SurePost Less than 1 lb','0PW') AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > (UZ.TNTDAYS + 1), 1, 0)
ELSE iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END))
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > USS.[Days], 1, 0)
End as LATE
FROM [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_QVM_Tracking] UT
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_States] US on US.[State] = UT.[Ship_To_State_Province]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Ground_Zips] UZ on UZ.[DESTZIPCODE] = UT.[Ship_To_Postal_Code]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
where cast(UT.Manifest_Date as date) between '1/20/2019' and '1/26/2019' AND WarehouseLocation = 'Wausau' and UT.Status = 'Delivered'
group by UT.[Service],US.[Region], USS.Days, UT.[Manifest_Date], UT.[Date_Delivered], TNTDAYS, Tracking_Number, Ship_To_Postal_Code, WarehouseLocation
So I found the issue is on INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
however I don't understand why when i join UT.SERVICE on USS.Service the uss.service field shows every possible service, and not the value that Ut.SERVICE has.
if UT.Service = UPS 2nd Day Air wouldn't the join on USS only give me UPS 2nd Day Air values?
The root cause is one of the joins returns more than 1 records
The way you need to find the the root cause of issue is:
1- Remove all columns from your select to become Select * from yourtable
2- comment all joins
3- uncomment joins and watch your data to see if the become duplicate
3.1- if the records are not duplicated that join is OK, do the same on next join
3.2- if records get duplicated, means join might not be right, usually some join conditions are missing
4- After fixing the join issue, remove * and bring back the fields
5- do final check
I have this query that returns 1 row of aggregate sums
DECLARE #Income9 int
SELECT #Income9 = IncomeLevel FROM PovertyLevels WHERE HouseholdNumber = 9
;WITH CTE
AS
(
SELECT PatientProfileID, CASE WHEN v.FamilyMembersinHousehold > 8
THEN ROUND((CAST(AnnualIncome as float)/(CAST(#Income9 as float) +((V.FamilyMembersinHousehold-8)* CAST(#Income9 as Float)))*100.00), 5)
WHEN ((v.FamilyMembersinHousehold IS NULL) OR (AnnualIncome IS NULL)) THEN NULL
ELSE ROUND(((CAST(AnnualIncome AS Float)/CAST(pl.IncomeLevel as Float)) * 100.00), 5) END AS PercentOfPoverty
FROM vPatientDemographics v
LEFT OUTER JOIN PovertyLevels pl ON v.FamilyMembersinHousehold = pl.HouseholdNumber
)
SELECT SUM(CASE WHEN PercentOfPoverty <= 100 THEN 1 ELSE 0 END) AS NumOfPatientsBelow100,
SUM(CASE WHEN PercentOfPoverty BETWEEN 101 AND 150 THEN 1 ELSE 0 END) AS NumOfPatientsBetween101And150,
SUM(CASE WHEN PercentOfPoverty BETWEEN 151 AND 200 THEN 1 ELSE 0 END) AS NumOfPatientsBetween151And200,
SUM(CASE WHEN PercentOfPoverty > 200 THEN 1 ELSE 0 END) AS NumOfPatientsOver200,
SUM(CASE WHEN PercentOfPoverty IS NULL THEN 1 ELSE 0 END) AS NumOfPatientsUnknown
FROM CTE
I would like to have the sum data to be in rows not columns.
I tried adding this UNPIVOT but it does not recognize the column names.
UNPIVOT
(
Levels for PovertyLevels in (NumOfPatientsBelow100, NumOfPatientsBetween101And150, NumOfPatientsBetween151And200,
NumOfPatientsOver200, NumOfPatientsUnknown)
) as Unpvt
How can I unpivot the initial data set to that it is in rows not columns?
It is because Where clause is evaluated before the select
SELECT #Income9 = IncomeLevel FROM PovertyLevels WHERE HouseholdNumber = 9
;WITH CTE
AS
(
SELECT PatientProfileID, CASE WHEN v.FamilyMembersinHousehold > 8
THEN ROUND((CAST(AnnualIncome as float)/(CAST(#Income9 as float) +((V.FamilyMembersinHousehold-8)* CAST(#Income9 as Float)))*100.00), 5)
WHEN ((v.FamilyMembersinHousehold IS NULL) OR (AnnualIncome IS NULL)) THEN NULL
ELSE ROUND(((CAST(AnnualIncome AS Float)/CAST(pl.IncomeLevel as Float)) * 100.00), 5) END AS PercentOfPoverty
FROM vPatientDemographics v
LEFT OUTER JOIN PovertyLevels pl ON v.FamilyMembersinHousehold = pl.HouseholdNumber
),intr as
(
SELECT SUM(CASE WHEN PercentOfPoverty <= 100 THEN 1 ELSE 0 END) AS NumOfPatientsBelow100,
SUM(CASE WHEN PercentOfPoverty BETWEEN 101 AND 150 THEN 1 ELSE 0 END) AS NumOfPatientsBetween101And150,
SUM(CASE WHEN PercentOfPoverty BETWEEN 151 AND 200 THEN 1 ELSE 0 END) AS NumOfPatientsBetween151And200,
SUM(CASE WHEN PercentOfPoverty > 200 THEN 1 ELSE 0 END) AS NumOfPatientsOver200,
SUM(CASE WHEN PercentOfPoverty IS NULL THEN 1 ELSE 0 END) AS NumOfPatientsUnknown
FROM CTE
)
Select cnt,range from intr
cross apply (values (NumOfPatientsBelow100,'NumOfPatientsBelow100'),
(NumOfPatientsBetween101And150,'NumOfPatientsBetween101And150'),
(NumOfPatientsBetween151And200,'NumOfPatientsBetween151And200'),
(NumOfPatientsOver200,'NumOfPatientsOver200'),
(NumOfPatientsUnknown,'NumOfPatientsUnknown')) cs (cnt,range)
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
I am performing the follwing sql to return a data where there is a match of both dob and address in tables1 & 2.
select table1.dob
, table1.address
, sum(case when person_status in ('A','B','C') then 1 else 0 end) as 'ABC_count'
, sum(case when person_status in ('D','E') then 1 else 0 end) as 'DE_Count'
, sum(case when person_status in ('F','G') then 1 else 0 end) as 'FG_Count'
from table1
inner join table2
on (table1.dob = table2.dob and table1.address = table2.address)
where table1.dob > #myDate
group by table1.dob, table1.address
order by table1.dob, table1.address
However I now want to return the data from table1 when there is no match in table2 and only that data, I thought simply changing inner join to left outer would perform what I required, it does not.
Thanks!
If there is no match in the join, the field from the second table are NULL, so you have to check for a NULL value in table2. Assuming dob is NOT NULL in table2, this should solve your problem:
select table1.dob
, table1.address
, sum(case when person_status in ('A','B','C') then 1 else 0 end) as 'ABC_count'
, sum(case when person_status in ('D','E') then 1 else 0 end) as 'DE_Count'
, sum(case when person_status in ('F','G') then 1 else 0 end) as 'FG_Count'
from table1
left outer join table2
on (table1.dob = table2.dob and table1.address = table2.address)
where table1.dob > #myDate and table2.dob is null
group by table1.dob, table1.address
order by table1.dob, table1.address
In this case thre's not a join, you should use NOT EXISTS function.
In my opinion LEFT JOIN is much more cleaner and you should go with that if there is no big difference between the performance of LEFT JOIN and NOT EXISTS. #JNK said "EXISTS and NOT EXISTS are ordinarily faster than joins or other operators like IN because they short circuit - the first time they get a hit they move on to the next entry", but my understanding is that NOT EXISTS and NOT IN are usually expensive as sql server has to go through all the records in the lookup table to make sure that the entry in fact does NOT EXIST, so i dont know how the short circuit would work
You could also use the EXCEPT keyword here.
select table1.dob
, table1.address
, sum(case when person_status in ('A','B','C') then 1 else 0 end) as 'ABC_count'
, sum(case when person_status in ('D','E') then 1 else 0 end) as 'DE_Count'
, sum(case when person_status in ('F','G') then 1 else 0 end) as 'FG_Count'
from table1
where table1.dob > #myDate
EXCEPT
select table1.dob
, table1.address
, sum(case when person_status in ('A','B','C') then 1 else 0 end) as 'ABC_count'
, sum(case when person_status in ('D','E') then 1 else 0 end) as 'DE_Count'
, sum(case when person_status in ('F','G') then 1 else 0 end) as 'FG_Count'
from table1
inner join table2
on (table1.dob = table2.dob and table1.address = table2.address)
where table1.dob > #myDate
That would get you all of the records in the first query that are not in the second query.