Unexplainable SQL behaviour - sql

I have a simple SQL query, with a handful of joined queries.
In my select I have a function shaping the date to a string format as below
LEFT(REPLACE(ADM_DT,'-',''),8)+REPLACE(ADM_TM,':','')+'00'
The script I am running should return 84 rows currently, but when executing the above in the select, it continuosly returns a different volume of rows every execution? there are no changes to the underlying tables between executions.
The strange thing is that whe I swith this back to a standard date conversion, the rows total 84
CONVERT(DATETIME,CONVERT(NVARCHAR,ADM_DT)+' '+ADM_TM)
Can anyone explain why SQL is behaving this way, I have not seen this before?
Full script below:
SELECT
[Visit ID] = a050.HSP_NO
,[Current Site] = currwd.HOSP
,[Current Specialty] = curr.SPEC
,[Current Ward] = currwd.WARD
,[Current Ward Name] = REPLACE(currwd.CURRDESC,'"','')
,[Current Consultant] = curr.PROF
,[Admission Date] = LEFT(REPLACE(ADM_DT,'-',''),8)+REPLACE(ADM_TM,':','')+'00'
,[Active] = '1'
,[PAS ID] = [crn].[crn]
,[Patient Class] = 'IP'
,NHS.[nhsno]
,CHI.CHI
,CASE WHEN OSV.X_CN IS NOT NULL THEN 'OSV' ELSE '' END OSV
,CASE WHEN NHS.[nhsno] LIKE '7%' THEN '7 NHSNO' ELSE '' END [PROBLEM NHS NO]
,DATEDIFF(D,PATS.DATE_OF_BIRTH,CONVERT(DATE,ADM_DT)) /365 [AGE ON ADMISSION]
FROM PCSSSA..SILVER.APK050_HPROVSPELL a050 WITH (NOLOCK)
-- Current Admission details
LEFT JOIN (
SELECT X_CN, CEP_NO, HSP_NO, SPEC, PROF --MSPEC
FROM PCSSSA..SILVER.APK051_CONEPIS epi WITH (NOLOCK)
-- Main Specialty Map
LEFT JOIN PCSSSA..SILVER.ENV050_DISCIPDETS en050 WITH (NOLOCK)
ON epi.SPEC = en050.OBJ_DISC
AND en050.OBJ_TYPE='SP'
AND en050.DATE_TO IS NULL
)curr
ON curr.X_CN = a050.X_CN
AND a050.HSP_NO = curr.HSP_NO
AND curr.CEP_NO = (SELECT TOP 1 a051.CEP_NO
FROM PCSSSA..SILVER.APK051_CONEPIS a051 WITH (NOLOCK)
Where a051.X_CN = a050.X_CN AND a050.HSP_NO = a051.HSP_NO
Order By CEP_NO DESC)
-- Current Ward Detail
JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY X_CN, CEP_NO ORDER BY WS_NO DESC) AS WR
FROM PCSSSA..SILVER.APK052_WARDSTAY wdstay WITH (NOLOCK)
LEFT JOIN (SELECT
CURRWARD = OBJ_LOC,
CURRDESC = OBJ_DESC
FROM [PCSSSA]..[SILVER].[ENV030_LOCDETS] WITH (NOLOCK)
WHERE OBJ_TYPE = 'WARD'
AND DATE_TO IS NULL
)wdname
ON wdstay.WARD = wdname.CURRWARD
) currwd
ON curr.X_CN = currwd.X_CN
AND curr.CEP_NO = currwd.CEP_NO
AND currwd.WR=1
--- Admitting details
LEFT JOIN (
SELECT X_CN, CEP_NO, HSP_NO, PROF, SPEC --MSPEC
FROM PCSSSA..SILVER.APK051_CONEPIS epi WITH (NOLOCK)
-- Main Specialty Map
LEFT JOIN PCSSSA..SILVER.ENV050_DISCIPDETS en050 WITH (NOLOCK)
ON epi.SPEC = en050.OBJ_DISC
AND en050.OBJ_TYPE='SP'
AND en050.DATE_TO IS NULL
)adm
ON adm.X_CN = a050.X_CN AND a050.HSP_NO = adm.HSP_NO
AND adm.CEP_NO = (SELECT TOP 1 a051.CEP_NO
FROM PCSSSA..SILVER.APK051_CONEPIS a051 WITH (NOLOCK)
Where a051.X_CN = a050.X_CN AND a050.HSP_NO = a051.HSP_NO
Order By CEP_NO)
-- Admitting Ward Detail
JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY X_CN,CEP_NO ORDER BY WS_NO) AS WR FROM PCSSSA..SILVER.APK052_WARDSTAY WITH (NOLOCK)) admwd
ON adm.X_CN = admwd.X_CN
AND adm.CEP_NO = admwd.CEP_NO
AND admwd.WR=1
-- Patient Detail
LEFT JOIN
(SELECT
[id].[RM_PATIENT_NO],
[id].[NUM_ID_TYPE] + CONVERT(NVARCHAR,[NUMBER_ID]) [crn]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] IN ('0', '1', 'W')
)[crn]
ON a050.[X_CN] = [crn].[RM_PATIENT_NO]
-- NHS NUMBERS
LEFT JOIN
(
SELECT
[id].[RM_PATIENT_NO],
[id].[NUMBER_ID] [nhsno]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] = ('NHS')
)NHS
ON NHS.RM_PATIENT_NO = a050.X_CN
-- CHI NUMBER
LEFT JOIN
(
SELECT
[id].[RM_PATIENT_NO],
[id].[NUMBER_ID] [CHI]
FROM [PCSSSA]..[SILVER].[NUMBER_IDS] [id] WITH (NOLOCK)
WHERE [id].[NUM_ID_TYPE] IN ('CHI')
)CHI
ON CHI.RM_PATIENT_NO = a050.X_CN
-- OVERSEES STATUS
LEFT JOIN
(
SELECT X_CN, [STATUS], SDATE, EDATE FROM PCSSSA..SILVER.CRS037_OSV_STATUS WITH (NOLOCK)
)OSV
ON OSV.X_CN = a050.X_CN
AND CONVERT(DATE,ADM_DT) >= OSV.SDATE
AND (OSV.SDATE IS NULL
OR CONVERT(DATE,ADM_DT) <= OSV.EDATE)
-- DEMOGRAPHICS
LEFT JOIN
(
SELECT RM_PATIENT_NO, DATE_OF_BIRTH FROM PCSSSA..[SILVER].[PATIENTS] WITH (NOLOCK)
)PATS
ON PATS.RM_PATIENT_NO = a050.X_CN
-- CURRENTLY ADMITTED ONLY
WHERE DIS_DT IS NULL
-- WITHOUT NHS NUMBER
AND (nhsno IS NULL
-- OR BRING IN ANY 7 NHS NUMBERS FOR CORRECTION
OR NHS.[nhsno] LIKE '7%'
-- ALSO INCLUDE OVERSEES
OR OSV.X_CN IS NOT NULL)
What is even stranger, is that if you wrap this in a subquery and coun(*) on the outer then it totals 84 as expected, very strange!

Related

Where Clause Using Conditional Statement

i have query below
SELECT #RoleUser = MR.Code FROM MasterRole MR INNER JOIN MasterUsersRole MUR ON MR.Id = MUR.RoleId
INNER JOIN MasterUsers MU ON Mu.UserCode = MUR.UserCode
WHERE MU.UserCode = #UserLoginID
select 1 Num
, MyHistory.ID
, MyHistory.RequestNumber
, MyHistory.FlowID
, MyHistory.FlowProcessStatusID
from
(
select *
from Requests R
inner join
(
--DECLARE #UserLoginID nvarchar(200) = 'dum.testing.3'
select distinct
RequestID
from dbo.RequestTrackingHistory RTH
where IIF(#UserLoginID = 'admin', #UserLoginID, RTH.CreatedBy) = #UserLoginID
OR ( CreatedBy IN
SELECT Mu.UserCode from MasterUsers MU
INNER JOIN MasterUsersRole MUR ON MU.UserCode = MUR.UserCode
INNER JOIN MasterRole MR ON MUR.RoleId = MR.Id
WHERE MR.Code = #RoleUser
)
)
) RT on R.ID = RT.RequestID
) as MyHistory
inner join MasterFlow F on MyHistory.FlowID = F.ID
inner join
(
select FP.ID
, FP.Name
, FP.AssignType
, FP.AssignTo
, FP.IsStart
, case FP.AssignType
when 'GROUP' then
G.Name
end as 'AssignToName'
from MasterFlowProcess FP
left join dbo.MasterRole G on FP.AssignTo = G.ID and FP.AssignType = 'GROUP'
) FP on MyHistory.FlowProcessID = FP.ID
inner join MasterFlowProcessStatus FPS on MyHistory.FlowProcessStatusID = FPS.ID
left join MasterFlowProcessStatusNext FPSN on FPS.ID = FPSN.ProcessStatusFlowID
left join MasterFlowProcess FPN on FPSN.NextProcessFlowID = FPN.ID
left JOIN MasterRole MR ON MR.Id = FPN.AssignTo
left join MasterUsersRole MUR on MR.Id = MUR.RoleId
left join MasterUsers MURO on MUR.UserCode = MURO.UserCode
inner join MasterUsers UC on MyHistory.CreatedBy = UC.UserCode
left join MasterUsers UU on MyHistory.UpdatedBy = UU.UserCode
LEFT JOIN RequestMT RMT ON MyHistory.ID = RMT.RequestID
LEFT JOIN RequestGT RGT ON MyHistory.ID = RGT.RequestID
left join (SELECT sum(QtyCU) countQty , RequestId from dbo.RequestGTDetail where IsActive = 1 group by RequestId) RGTD on RGTD.RequestId = RGT.RequestId
left join (SELECT sum(QtyPCS) countQty , RequestId from dbo.RequestMTDetail where IsActive = 1 group by RequestId) RMTD on RMTD.RequestId = RMT.RequestId
left join (SELECT COUNT(IIF(returnable = 0, returnable, null)) countReturnable , RequestId from dbo.RequestMTDetail group by RequestId) RMTR on RMTR.RequestId = RMT.RequestId
left JOIN dbo.MasterDistributor md ON md.Code = RGT.CustId or md.Code = RMT.CustId
left JOIN dbo.MasterUsersDistributor MUD ON MUD.UserCode = MURO.UserCode AND md.Code = MUD.DistributorCode
LEFT JOIN dbo.MasterReason MRMT ON RMT.ReasonId = MRMT.Id
LEFT JOIN dbo.MasterReason MRGT ON RGT.ReasonId = MRGT.Id
LEFT JOIN dbo.MasterDistributorGroup MDG ON MDG.Id = MD.GroupId
OUTER APPLY dbo.FnGetHistoryApproveDate(MyHistory.Id) AS x
where REPLACE(FPS.Name, '#Requestor', uc.Name) <> 'DRAFT'
AND MUD.DistributorCode IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = #UserLoginID)
i want to add some logic in where clause
this line
==> AND MUD.DistributorCode IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = #UserLoginID)
it depend on the #RoleUser variable, if #RoleUser IN ('A','B') then where clause above is executed, but if #RoleUser Not IN ('A','B') where clause not executed
i,m trying this where clause
AND IIF(#RoleUser IN ('A','B'), MUD.DistributorCode, #RoleUser) IN (SELECT DistributorCode FROM dbo.MasterUsersDistributor WHERE UserCode = IIF(#RoleUser IN ('A','B'), #UserLoginID, NULL))
it didn't work, only executed if #RoleUser IS ('A','B') other than that it return 0 record
any help or advice is really appreciated
thank you
The cleanest way I'm implemented these kind of crazy rules is a
holderTable
and a countVariable against the holder table.
I'll give a generic examples.
This is a "approach" and "philosophy", not a specific answer....with complex WHERE clauses.
DECLARE #customerCountryCount int
DECLARE #customerCountry TABLE ( CountryName varchar(15) )
if ( "the moon is blue on tuesday" ) /* << whatever rules you have */
BEGIN
INSERT INTO #customerCountry SELECT "Honduras" UNION ALL SELECT "Malaysia"
END
if ( "favorite color = green" ) /* << whatever rules you have */
BEGIN
INSERT INTO #customerCountry SELECT "Greenland" UNION ALL SELECT "Peru"
END
SELECT #customerCountryCount = COUNT(*) FROM #customerCountry
Select * from dbo.Customers c
WHERE
(#customerCountryCount = 0)
OR
( exists (select null from #customerCountry innerVariableTable where UPPER(innerVariableTable.CountryName) = UPPER(c.Country) ))
)
This way, instead of putting all the "twisted logic" in an overly complex WHERE statement..... you have "separation of concerns"...
Your inserts into #customerCountry are separated from your use of #customerCountry.
And you have the #customerCountryCount "trick" to distinguish when nothing was used.
You can add a #customerCountryNotExists table as well, and code it to where not exists.
As a side note, you may want to try using a #temp table (instead of a #variabletable (#customerCountry above)... and performance test these 2 options.
There is no "single answer". You have to "try it out".
And many many variables go into #temp table performance (from a sql-server SETUP, not "how you code a stored procedure". That is way outside the scope of this question.
Here is a SOF link to "safe" #temp table usage.
Temporary table in SQL server causing ' There is already an object named' error

Query takes too long if i include a column in select statement

Below is the query which i need to optimize:
DECLARE #Power VARCHAR(10), #Button VARCHAR(10), #Casing VARCHAR(10), #Screen VARCHAR(10)
SELECT #Power = ActivityId FROM t_Activity WHERE ActivityName = 'PhonePowersUp?'
SELECT #Button = ActivityId FROM t_Activity WHERE ActivityName = 'T/S and Buttons functioning OK?'
SELECT #Casing = ActivityId FROM t_Activity WHERE ActivityName = 'Casing - no major defects?'
SELECT #Screen = ActivityId FROM t_Activity WHERE ActivityName = 'LCD works OK?'
SELECT
HQ.HandsetQuoteId [HandsetQuoteId], SS.Name [quote_status], HQ.QuoteDate [Quote Date], INS.DateInspected [DateInspected], PA.IMEI [IMEI_Quoted],
PA1.IMEI [IMEI_Inspected], INS.Grade [Grade], PB.PackageBoxName [PackageBoxName], CC.Name [ContactChannel], PhnBrd.Name [Brand], PM.ModelName [ModelQuoted],
PM1.ModelName [ModelInspected], U.FirstName [FirstName], U.Surname [Surname], U.Username [Username], UW.WarehouseId [WarehouseId], W.Name [Warehouse Name],
HQA.Value [Original Quote Value], HQ.QuoteValue [Quote Value], INS.InspectionValue [InspectionValue], HQ.AgreedValue [Agreed Value], CUS.FirstName [Store Name],
DATEDIFF(DAY, HQ.QuoteDate, GETDATE()) [Quote Age],
[ST_POWER] = CASE WHEN (CHARINDEX(','+ #Power +',', ','+PAR.Ok+',') > 0) THEN 'YES' WHEN (CHARINDEX(','+ #Power +',', ','+PAR.Fault+',') > 0) THEN 'NO' ELSE NULL END,
[ST_BUTTONS] = CASE WHEN (CHARINDEX(','+ #Button +',', ','+PAR.Ok+',') > 0) THEN 'YES' WHEN (CHARINDEX(','+ #Button +',', ','+PAR.Fault+',') > 0) THEN 'NO' ELSE NULL END,
[ST_CASING] = CASE WHEN (CHARINDEX(','+ #Casing +',', ','+PAR.Ok+',') > 0) THEN 'YES' WHEN (CHARINDEX(','+ #Casing +',', ','+PAR.Fault+',') > 0) THEN 'NO' ELSE NULL END,
[ST_Screen] = CASE WHEN (CHARINDEX(','+ #Screen +',', ','+PAR.Ok+',') > 0) THEN 'YES' WHEN (CHARINDEX(','+ #Screen +',', ','+PAR.Fault+',') > 0) THEN 'NO' ELSE NULL END,
st_deduct = PAR.PercentageDeduction, wt_deduct = MAX(APD.PercentageDeduction)
FROM t_Inspection AS INS
INNER JOIN t_HandsetQuote HQ ON HQ.HandsetQuoteId = INS.HandsetQuoteId
INNER JOIN t_QuoteHeader QH ON QH.QuoteHeaderId = HQ.QuoteHeaderId
INNER JOIN t_Customer CUS ON CUS.CustomerId = QH.CustomerId
INNER JOIN t_ContactChannel CC ON CC.ContactChannelId = CUS.ContactChannelId
INNER JOIN t_PackageBoxHandset PBH ON PBH.HandsetQuoteId = HQ.HandsetQuoteId
INNER JOIN t_PackageBox PB ON PB.PackageBoxId = PBH.PackageBoxId
INNER JOIN t_StockStatus SS ON SS.StockStatusId = HQ.StockStatusId
INNER JOIN t_PhoneAudit PA ON PA.PhoneAuditId = HQ.QuotePhoneAuditId
INNER JOIN t_PhoneModel PM ON PM.PhoneModelId = PA.PhoneModelId AND PA.PhoneAuditId = HQ.QuotePhoneAuditId
INNER JOIN t_PhoneBrand PhnBrd ON PM.PhoneBrandId = PhnBrd.PhoneBrandId
INNER JOIN t_PhoneAudit PA1 ON PA1.PhoneAuditId = HQ.InspectionPhoneAuditId
INNER JOIN t_PhoneModel PM1 ON PM1.PhoneModelId = PA1.PhoneModelId AND PA1.PhoneAuditId = HQ.InspectionPhoneAuditId
INNER JOIN t_PhoneBrand PhnBrd1 ON PM1.PhoneBrandId = PhnBrd1.PhoneBrandId
INNER JOIN t_User U ON INS.InspectorId = U.UserId
INNER JOIN t_UserWarehouse UW ON U.UserId = UW.UserId
INNER JOIN t_Warehouse W ON UW.WarehouseId = W.WarehouseId
LEFT JOIN t_HandsetQuoteAdditionalInfo HQA ON HQ.HandsetQuoteId = HQA.HandsetQuoteId AND HQA.KeyName = 'OriginalQuoteValue'
LEFT JOIN t_PhoneAuditRetail PAR ON PAR.HandsetQuoteId = HQ.HandsetQuoteId
LEFT JOIN t_HandsetQuoteActivity HQA1 ON HQA1.HandsetQuoteId = HQ.HandsetQuoteId AND HQA1.ActivityTestOK = 0 AND HQA1.ActivityStartTime = (
CASE
WHEN ((SELECT Count(1) FROM t_HandsetQuoteActivity WHERE HandsetQuoteId = HQA1.HandsetQuoteId AND ActivityStartTime <= QH.Cache_QuoteAcceptedDate AND ActivityId = HQA1.ActivityId) > 0)
THEN (SELECT Max(ActivityStartTime) FROM t_HandsetQuoteActivity WHERE HandsetQuoteId = HQA1.HandsetQuoteId AND ActivityStartTime <= QH.Cache_QuoteAcceptedDate AND ActivityId = HQA1.ActivityId GROUP BY HandsetQuoteId, ActivityId)
ELSE
(SELECT Min(ActivityStartTime) FROM t_HandsetQuoteActivity WHERE HandsetQuoteId = HQA1.HandsetQuoteId AND ActivityStartTime >= QH.Cache_QuoteAcceptedDate AND ActivityId = HQA1.ActivityId GROUP BY HandsetQuoteId, ActivityId)
END)
LEFT JOIN t_Activity_PercentageDeduction APD ON APD.ActivityId = HQA1.ActivityId AND APD.ContactChannelId = CUS.ContactChannelId AND APD.ContactChannelId = CC.ContactChannelId
WHERE Ins.DateInspected > GETDATE()-90
GROUP BY HQ.HandsetQuoteId, SS.Name, QH.CreatedDate, INS.DateInspected, PA.IMEI, PA1.IMEI, INS.Grade, PB.PackageBoxName, CC.Name, PhnBrd.Name, PM.ModelName, PM1.ModelName,
U.FirstName, U.Surname, U.Username, UW.WarehouseId, W.Name, HQA.Value, HQ.QuoteValue, INS.InspectionValue, HQ.AgreedValue, CUS.Firstname, HQ.QuoteDate, PAR.Ok, PAR.Fault,
PAR.PercentageDeduction
And, after properly debugging it, I came to know that when i remove wt_deduct = MAX(APD.PercentageDeduction) from the select list, the query executes with in less than a minute.
But, however i am not able to figure it out, that whats wrong with the column APD.PercentageDeduction, because when i include it in the select list, my query stucks and becomes too slow and takes 15 minutes to run and excluding it from the select list makes the query to run with in 30 seconds.
Additional Information:
Table -> t_Activity_PercentageDeduction contains only 400 records, column PercentageDeduction is of Decimal datatype.
Please let me know if you want some other information too.
If Im not mistaken you are only joining to that table in order to get that MAX value, and by adding this Max value, you are also having to do all the grouping. So there is actually quite a difference in the queries.
I would suggest using a co-related sub-query to get this piece of data.
remove the left join
LEFT JOIN t_Activity_PercentageDeduction APD ON APD.ActivityId = HQA1.ActivityId AND APD.ContactChannelId = CUS.ContactChannelId AND APD.ContactChannelId = CC.ContactChannelId
and set wt_deduct = to the new co-related sub-query
wt_deduct = (select MAX(PercentageDeduction) from t_Activity_PercentageDeduction
where ActivityId = HQA1.ActivityId
AND ContactChannelId = CUS.ContactChannelId
AND ContactChannelId = CC.ContactChannelId)
And you can remove all the grouping that is no longer required too.

How can I optimize the SQL query?

I have a query an SQL query as follows, can anybody suggest any optimization for this; I think most of the effort is being done for the Union operation - is there anything else can be done to get the same result ?
Basically I wanna query first portion of the UNION and if for each record there is no result then the second portion need to be run. Please help.
:
SET dateformat dmy;
WITH incidentcategory
AS (
SELECT 1 ord, i.IncidentId, rl.Description Category FROM incident i
JOIN IncidentLikelihood l ON i.IncidentId = l.IncidentId
JOIN IncidentSeverity s ON i.IncidentId = s.IncidentId
JOIN LikelihoodSeverity ls ON l.LikelihoodId = ls.LikelihoodId AND s.SeverityId = ls.SeverityId
JOIN RiskLevel rl ON ls.RiskLevelId = rl.riskLevelId
UNION
SELECT 2 ord, i.incidentid,
rl.description Category
FROM incident i
JOIN incidentreportlikelihood l
ON i.incidentid = l.incidentid
JOIN incidentreportseverity s
ON i.incidentid = s.incidentid
JOIN likelihoodseverity ls
ON l.likelihoodid = ls.likelihoodid
AND s.severityid = ls.severityid
JOIN risklevel rl
ON ls.risklevelid = rl.risklevelid
) ,
ic AS (
SELECT ROW_NUMBER() OVER (PARTITION BY i.IncidentId ORDER BY (CASE WHEN incidentTime IS NULL THEN GETDATE() ELSE incidentTime END) DESC,ord ASC) rn,
i.incidentid,
dbo.Incidentdescription(i.incidentid, '',
'',
'', '')
IncidentDescription,
dbo.Dateconverttimezonecompanyid(closedtime,
i.companyid)
ClosedTime,
incidenttime,
incidentno,
Isnull(c.category, '')
Category,
opencorrectiveactions,
reportcompleted,
Isnull(classificationcompleted, 0)
ClassificationCompleted,
Cast (( CASE
WHEN closedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
IncidentClosed,
Cast (( CASE
WHEN investigatorfinishedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationFinished,
Cast (( CASE
WHEN investigationcompletetime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationComplete,
Cast (( CASE
WHEN investigatorassignedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigatorAssigned,
Cast (( CASE
WHEN (SELECT Count(*)
FROM incidentinvestigator
WHERE incidentid = i.incidentid
AND personid = 1588
AND tablename = 'AdminLevels') = 0
THEN 0
ELSE 1
END ) AS BIT)
IncidentInvestigator,
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader,
incidentstatus,
incidentstatussearch
FROM incident i
LEFT OUTER JOIN incidentcategory c
ON i.incidentid = c.incidentid
WHERE i.isdeleted = 0
AND i.companyid = 158
AND incidentno <> 0
--AND reportcompleted = 1
--AND investigatorassignedtime IS NOT NULL
--AND investigatorfinishedtime IS NULL
--AND closedtime IS NULL
),
ic2 AS (
SELECT * FROM ic WHERE rn=1
)
SELECT * FROM ic2
--WHERE rownumber >= 0
-- AND rownumber < 0 + 10
--WHERE ic2.incidentid in(53327,53538)
--WHERE ic2.incidentid = 53338
ORDER BY incidentid DESC
Following is the execution plan I got:
https://www.dropbox.com/s/50dcpelr1ag4blp/Execution_Plan.sqlplan?dl=0
There are several issues:
1) use UNION ALL instead of UNION ALL to avoid the additional operation to aggregate the data.
2) try to modify the numerous function calls (e.g. dbo.Incidentdescription() ) to be an in-lie table valued function so you can reference it using CROSS APPLY or OUTER APPLY. Especially, if those functions referencing a table again.
3) move the subqueries from the SELECT part of the query to the FROM part using CROSS APPLY or OUTER APPLY again.
4) after the above is done, check the execution plan again for any missing indexes. Also, run the query with STATISTICS TIME, IO on to verify that the number of times a table
is referenced is correct (sometimes the execution plan put you in the wrong direction, especially if function calls are involved)...
Since the first inner query produces rows with ord=1 and the second produces rows with ord=2, you should use UNION ALL instead of UNION. UNION will filter out equal rows and since you will never get equal rows it is more efficient to use UNION ALL.
Also, rewrite your query to not use the WITH construct. I've had very bad experiences with this. Just use regular derived tables instead. In the case the query is still abnormally slow, try to serialize some derived tables to a temporary table and query the temporary table instead.
Try alternate approach by removing
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader
from the SELECT. Avoid using complex functions/sub-queries in select.

How to pick Max value of SQL Output

SQL Query Syntax issue. I have a query which returns around 150,000 rows of records. In this query, you can see ROW_NUMBER() OVER PARTITION. On select * from cte, I need to pick only the highest value of ROW_NUMBER() for each Pat_id.
If RowNumber is 150 for one pat_id. I need only that row of records. I am having difficult in narrowing down to one record. I request experts to share your syntax to help me.
with cte
as (
select pat.pat_id,
pat.fname as [FirstName],
pat.mname as [MiddleName],
pat.lname as [LastName],
[DOB] =Convert(VARCHAR(12),pat.birth_date,101),
csc.name as [AccountType],
[Plan Name] = CASE when (isnull(org.name,'')='') then 'CASH' else org.name end
,cprx_disp.disp_days_supply
,cprx_disp.dispense_date
,(cprx_disp.dispense_date + cprx_disp.disp_days_supply) as [DateDue]
,ROW_NUMBER() over(PARTITION BY pat.pat_id ORDER BY cprx_disp.dispense_date) as [RowNumber]
From cppat pat (nolock)
left outer join cppat_ins patins(NoLock) ON patins.pat_id = pat.pat_id
left outer join csorg org on org.org_id = patins.org_id
inner join csct_code csc on pat.pat_type_cn = csc.code_num
join cprx on cprx.pat_id = pat.pat_id
join cprx_disp (nolock) on cprx.last_rxdisp_id = cprx_disp.rxdisp_id
where csc.ct_id = 163
and csc.code_num in (1033,1010,1011,1012,1016,1017,1016,1018)
and patins.status_cn = 1
and patins.priority = 1
-- Commented.
-- and pat.pat_id = 2561
)
select cte.[FirstName],
cte.[MiddleName],
cte.[LastName],
cte.[DOB],
cte.[AccountType],
cte.[Plan Name],
Cte.DateDue
from cte
Well, you're not actually using the RowNumber in the output, so I would just reverse it and then return those that equal 1:
with cte
as (
select pat.pat_id,
pat.fname as [FirstName],
pat.mname as [MiddleName],
pat.lname as [LastName],
[DOB] =Convert(VARCHAR(12),pat.birth_date,101),
csc.name as [AccountType],
[Plan Name] = CASE when (isnull(org.name,'')='') then 'CASH' else org.name end
,cprx_disp.disp_days_supply
,cprx_disp.dispense_date
,(cprx_disp.dispense_date + cprx_disp.disp_days_supply) as [DateDue]
,ROW_NUMBER() over(PARTITION BY pat.pat_id ORDER BY cprx_disp.dispense_date DESC) as [RowNumber]
from cppat pat (nolock)
left outer join cppat_ins patins(NoLock) on patins.pat_id = pat.pat_id
left outer join csorg org on org.org_id = patins.org_id
inner join csct_code csc on pat.pat_type_cn = csc.code_num
join cprx on cprx.pat_id = pat.pat_id
join cprx_disp (nolock) on cprx.last_rxdisp_id = cprx_disp.rxdisp_id
where csc.ct_id = 163
and csc.code_num in (1033,1010,1011,1012,1016,1017,1016,1018)
and patins.status_cn = 1
and patins.priority = 1
-- Commented.
-- and pat.pat_id = 2561
)
select cte.[FirstName],
cte.[MiddleName],
cte.[LastName],
cte.[DOB],
cte.[AccountType],
cte.[Plan Name],
cte.DateDue
from cte
WHERE RowNumber = 1;

TSQL Conditionally Select Specific Value

This is a follow-up to #1644748 where I successfully answered my own question, but Quassnoi helped me to realize that it was the wrong question. He gave me a solution that worked for my sample data, but I couldn't plug it back into the parent stored procedure because I fail at SQL 2005 syntax. So here is an attempt to paint the broader picture and ask what I actually need.
This is part of a stored procedure that returns a list of items in a bug tracking application I've inherited. There are are over 100 fields and 26 joins so I'm pulling out only the mostly relevant bits.
SELECT
tickets.ticketid,
tickets.tickettype,
tickets_tickettype_lu.tickettypedesc,
tickets.stage,
tickets.position,
tickets.sponsor,
tickets.dev,
tickets.qa,
DATEDIFF(DAY, ticket_history_assignment.savedate, GETDATE()) as 'daysinqueue'
FROM
dbo.tickets WITH (NOLOCK)
LEFT OUTER JOIN dbo.tickets_tickettype_lu WITH (NOLOCK) ON tickets.tickettype = tickets_tickettype_lu.tickettypeid
LEFT OUTER JOIN dbo.tickets_history_assignment WITH (NOLOCK) ON tickets_history_assignment.ticketid = tickets.ticketid
AND tickets_history_assignment.historyid = (
SELECT
MAX(historyid)
FROM
dbo.tickets_history_assignment WITH (NOLOCK)
WHERE
tickets_history_assignment.ticketid = tickets.ticketid
GROUP BY
tickets_history_assignment.ticketid
)
WHERE
tickets.sponsor = #sponsor
The area of interest is the daysinqueue subquery mess. The tickets_history_assignment table looks roughly as follows
declare #tickets_history_assignment table (
historyid int,
ticketid int,
sponsor int,
dev int,
qa int,
savedate datetime
)
insert into #tickets_history_assignment values (1521402, 92774,20,14, 20, '2009-10-27 09:17:59.527')
insert into #tickets_history_assignment values (1521399, 92774,20,14, 42, '2009-08-31 12:07:52.917')
insert into #tickets_history_assignment values (1521311, 92774,100,14, 42, '2008-12-08 16:15:49.887')
insert into #tickets_history_assignment values (1521336, 92774,100,14, 42, '2009-01-16 14:27:43.577')
Whenever a ticket is saved, the current values for sponsor, dev and qa are stored in the tickets_history_assignment table with the ticketid and a timestamp. So it is possible for someone to change the value for qa, but leave sponsor alone.
What I want to know, based on all of these conditions, is the historyid of the record in the tickets_history_assignment table where the sponsor value was last changed so that I can calculate the value for daysinqueue. If a record is inserted into the history table, and only the qa value has changed, I don't want that record. So simply relying on MAX(historyid) won't work for me.
Quassnoi came up with the following which seemed to work with my sample data, but I can't plug it into the larger query, SQL Manager bitches about the WITH statement.
;WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticketid ORDER BY savedate DESC) AS rn
FROM #Table
)
SELECT rl.sponsor, ro.savedate
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.savedate
FROM rows rc
JOIN rows rn
ON rn.ticketid = rc.ticketid
AND rn.rn = rc.rn + 1
AND rn.sponsor <> rc.sponsor
WHERE rc.ticketid = rl.ticketid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
I played with it yesterday afternoon and got nowhere because I don't fundamentally understand what is going on here and how it should fit into the larger context.
So, any takers?
UPDATE
Ok, here's the whole thing. I've been switching some of the table and column names in an attempt to simplify things so here's the full unedited mess.
snip - old bad code
Here are the errors:
Msg 102, Level 15, State 1, Procedure usp_GetProjectRecordsByAssignment, Line 159
Incorrect syntax near ';'.
Msg 102, Level 15, State 1, Procedure usp_GetProjectRecordsByAssignment, Line 179
Incorrect syntax near ')'.
Line numbers are of course not correct but refer to
;WITH rows AS
And the ')' char after the WHERE rl.rn = 1
)
Respectively
Is there a tag for extra super long question?
UPDATE #2
Here is the finished query for anyone who may need this:
CREATE PROCEDURE [dbo].[usp_GetProjectRecordsByAssignment]
(
#assigned numeric(18,0),
#assignedtype numeric(18,0)
)
AS
SET NOCOUNT ON
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY recordid ORDER BY savedate DESC) AS rn
FROM projects_history_assignment
)
SELECT projects_records.recordid,
projects_records.recordtype,
projects_recordtype_lu.recordtypedesc,
projects_records.stage,
projects_stage_lu.stagedesc,
projects_records.position,
projects_position_lu.positiondesc,
CASE projects_records.clientrequested
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS clientrequested,
projects_records.reportingmethod,
projects_reportingmethod_lu.reportingmethoddesc,
projects_records.clientaccess,
projects_clientaccess_lu.clientaccessdesc,
projects_records.clientnumber,
projects_records.project,
projects_lu.projectdesc,
projects_records.version,
projects_version_lu.versiondesc,
projects_records.projectedversion,
projects_version_lu_projected.versiondesc AS projectedversiondesc,
projects_records.sitetype,
projects_sitetype_lu.sitetypedesc,
projects_records.title,
projects_records.module,
projects_module_lu.moduledesc,
projects_records.component,
projects_component_lu.componentdesc,
projects_records.loginusername,
projects_records.loginpassword,
projects_records.assistedusername,
projects_records.browsername,
projects_browsername_lu.browsernamedesc,
projects_records.browserversion,
projects_records.osname,
projects_osname_lu.osnamedesc,
projects_records.osversion,
projects_records.errortype,
projects_errortype_lu.errortypedesc,
projects_records.gsipriority,
projects_gsipriority_lu.gsiprioritydesc,
projects_records.clientpriority,
projects_clientpriority_lu.clientprioritydesc,
projects_records.scheduledstartdate,
projects_records.scheduledcompletiondate,
projects_records.projectedhours,
projects_records.actualstartdate,
projects_records.actualcompletiondate,
projects_records.actualhours,
CASE projects_records.billclient
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS billclient,
projects_records.billamount,
projects_records.status,
projects_status_lu.statusdesc,
CASE CAST(projects_records.assigned AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
WHEN '20000' THEN 'Client'
WHEN '30000' THEN 'Tech Support'
WHEN '40000' THEN 'LMI Tech Support'
WHEN '50000' THEN 'Upload'
WHEN '60000' THEN 'Spider'
WHEN '70000' THEN 'DB Admin'
ELSE rtrim(users_assigned.nickname) + ' ' + rtrim(users_assigned.lastname)
END AS assigned,
CASE CAST(projects_records.assigneddev AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assigneddev.nickname) + ' ' + rtrim(users_assigneddev.lastname)
END AS assigneddev,
CASE CAST(projects_records.assignedqa AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assignedqa.nickname) + ' ' + rtrim(users_assignedqa.lastname)
END AS assignedqa,
CASE CAST(projects_records.assignedsponsor AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assignedsponsor.nickname) + ' ' + rtrim(users_assignedsponsor.lastname)
END AS assignedsponsor,
projects_records.clientcreated,
CASE projects_records.clientcreated
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS clientcreateddesc,
CASE projects_records.clientcreated
WHEN '1' THEN rtrim(clientusers_createuser.firstname) + ' ' + rtrim(clientusers_createuser.lastname) + ' (Client)'
ELSE rtrim(users_createuser.nickname) + ' ' + rtrim(users_createuser.lastname)
END AS createuser,
projects_records.createdate,
projects_records.savedate,
projects_resolution.sitesaffected,
projects_sitesaffected_lu.sitesaffecteddesc,
DATEDIFF(DAY, projects_history_assignment.savedate, GETDATE()) as 'daysinqueue',
projects_records.iOnHitList,
projects_records.changetype
FROM
dbo.projects_records WITH (NOLOCK)
LEFT OUTER JOIN dbo.projects_recordtype_lu WITH (NOLOCK) ON projects_records.recordtype = projects_recordtype_lu.recordtypeid
LEFT OUTER JOIN dbo.projects_stage_lu WITH (NOLOCK) ON projects_records.stage = projects_stage_lu.stageid
LEFT OUTER JOIN dbo.projects_position_lu WITH (NOLOCK) ON projects_records.position = projects_position_lu.positionid
LEFT OUTER JOIN dbo.projects_reportingmethod_lu WITH (NOLOCK) ON projects_records.reportingmethod = projects_reportingmethod_lu.reportingmethodid
LEFT OUTER JOIN dbo.projects_lu WITH (NOLOCK) ON projects_records.project = projects_lu.projectid
LEFT OUTER JOIN dbo.projects_version_lu WITH (NOLOCK) ON projects_records.version = projects_version_lu.versionid
LEFT OUTER JOIN dbo.projects_version_lu projects_version_lu_projected WITH (NOLOCK) ON projects_records.projectedversion = projects_version_lu_projected.versionid
LEFT OUTER JOIN dbo.projects_sitetype_lu WITH (NOLOCK) ON projects_records.sitetype = projects_sitetype_lu.sitetypeid
LEFT OUTER JOIN dbo.projects_module_lu WITH (NOLOCK) ON projects_records.module = projects_module_lu.moduleid
LEFT OUTER JOIN dbo.projects_component_lu WITH (NOLOCK) ON projects_records.component = projects_component_lu.componentid
LEFT OUTER JOIN dbo.projects_browsername_lu WITH (NOLOCK) ON projects_records.browsername = projects_browsername_lu.browsernameid
LEFT OUTER JOIN dbo.projects_osname_lu WITH (NOLOCK) ON projects_records.osname = projects_osname_lu.osnameid
LEFT OUTER JOIN dbo.projects_errortype_lu WITH (NOLOCK) ON projects_records.errortype = projects_errortype_lu.errortypeid
LEFT OUTER JOIN dbo.projects_resolution WITH (NOLOCK) ON projects_records.recordid = projects_resolution.recordid
LEFT OUTER JOIN dbo.projects_sitesaffected_lu WITH (NOLOCK) ON projects_resolution.sitesaffected = projects_sitesaffected_lu.sitesaffectedid
LEFT OUTER JOIN dbo.projects_gsipriority_lu WITH (NOLOCK) ON projects_records.gsipriority = projects_gsipriority_lu.gsipriorityid
LEFT OUTER JOIN dbo.projects_clientpriority_lu WITH (NOLOCK) ON projects_records.clientpriority = projects_clientpriority_lu.clientpriorityid
LEFT OUTER JOIN dbo.projects_status_lu WITH (NOLOCK) ON projects_records.status = projects_status_lu.statusid
LEFT OUTER JOIN dbo.projects_clientaccess_lu WITH (NOLOCK) ON projects_records.clientaccess = projects_clientaccess_lu.clientaccessid
LEFT OUTER JOIN dbo.users users_assigned WITH (NOLOCK) ON projects_records.assigned = users_assigned.userid
LEFT OUTER JOIN dbo.users users_assigneddev WITH (NOLOCK) ON projects_records.assigneddev = users_assigneddev.userid
LEFT OUTER JOIN dbo.users users_assignedqa WITH (NOLOCK) ON projects_records.assignedqa = users_assignedqa.userid
LEFT OUTER JOIN dbo.users users_assignedsponsor WITH (NOLOCK) ON projects_records.assignedsponsor = users_assignedsponsor.userid
LEFT OUTER JOIN dbo.users users_createuser WITH (NOLOCK) ON projects_records.createuser = users_createuser.userid
LEFT OUTER JOIN dbo.clientusers clientusers_createuser WITH (NOLOCK) ON projects_records.createuser = clientusers_createuser.userid
LEFT OUTER JOIN dbo.projects_history_assignment WITH (NOLOCK) ON projects_history_assignment.recordid = projects_records.recordid
AND projects_history_assignment.historyid = (
SELECT ro.historyid
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.historyid
FROM rows rc
JOIN rows rn
ON rn.recordid = rc.recordid
AND rn.rn = rc.rn + 1
AND rn.assigned <> rc.assigned
WHERE rc.recordid = rl.recordid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
AND rl.recordid = projects_records.recordid
)
WHERE
(#assignedtype='0' and projects_records.assigned = #assigned)
OR (#assignedtype='1' and projects_records.assigneddev = #assigned)
OR (#assignedtype='2' and projects_records.assignedqa = #assigned)
OR (#assignedtype='3' and projects_records.assignedsponsor = #assigned)
OR (#assignedtype='4' and projects_records.createuser = #assigned)
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticketid ORDER BY savedate DESC) AS rn
FROM #Table
)
SELECT projects_records.recordid,
projects_records.recordtype,
/* skipped */
AND projects_history_assignment.historyid = (
SELECT ro.historyid
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.savedate
FROM rows rc
JOIN rows rn
ON rn.recordid = rc.recordid
AND rn.rn = rc.rn + 1
AND rn.assigned <> rc.assigned
WHERE rc.recordid = rl.recordid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
AND rl.recordid = projects_records.recordid
)
Well, if that query does not work out -- you could always consider a trigger on the tickets_history_assignment table. You could use INSTEAD OF INSERT, UPDATE which fires before any changes are made, so you would have full control of what is about to change and what to do.