SQL SP runs Slow - sql

Hi
I am using an SP which takes 7 minutes in a server which has 7336 recrds
and 6seconds in another server which has 3500 records.
Can anybody help me to know why is it happening?
Thanks,
-Divya
THE SP:
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE
ON EMPLEE.PERSON_ID = PER.PERSON_ID
AND
dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN
ON PERSON_ASGN.ASSIGNMENT_ID =
dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT
ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE'
AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
INNER JOIN
(SELECT w1.ASSIGNMENT_ID, w1.WORKSHEET_ID, w1.EFFECTIVE_DATE, w1.APPROVED_BY, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3
ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE = CASE
WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID
AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) =w2.EFFECTIVE_DATE))
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
)
PERSON_WKS
ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN
(SELECT ASSIGNMENT_ID, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP')
)HOME_PAYROLL
ON HOME_PAYROLL.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
WHERE
(#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND
(#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1)
OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND
(#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND
(#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND
(#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND
(#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND
(#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND
(#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND
(#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND
(#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND
(#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND
(#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND
(#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND
(#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY PER.LAST_NAME ASC,
PER.FIRST_NAME ASC,
PERSON_WKS.EFFECTIVE_DATE DESC
The Function in the 5th line is the one which is running slow. rest of the part is running in 4secs
The FUNCTION:
BEGIN
DECLARE
#v_ASGN_COUNT INT,
#v_RESULT INT
SELECT #v_ASGN_COUNT = COUNT(ASSIGNMENT_ID) --to find out if this employee has any assignment
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I')
IF(#v_ASGN_COUNT > 0) --yes assignment, check against SECURITY_ASSIGNMENT_VW
BEGIN
SELECT #v_RESULT = COUNT(ASSIGNMENT_ID)
FROM SECURITY_ASSIGNMENT_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
ASSIGNMENT_ID IN (SELECT ASSIGNMENT_ID
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I'))
END
ELSE --no assignment, so check against SECURITY_PERSON_VW
BEGIN
SELECT #v_RESULT = COUNT(PERSON_ID)
FROM SECURITY_PERSON_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
PERSON_ID = #p_PERSON_ID
END
RETURN #v_RESULT
END

Do the schemas match exactly... in particular check for missing indexes.

Well to begin with you have scalar functions which will run significantly slower as the number of records increase becasue they process row-by-agonizing-row. Not only that you've used the functions in joins which is a horrible practice if you need performance. You have a bunch of OR conditions which tend to slowness. And while it is too hard to actually read the code you posted (please try to format and only use all caps for keywords), I would suspect that some of those conditions are not sargable.
To know what is actually happening check the Execution plan (SQL Server) or Explain Plan (mySQL and others I think) or the equivalent feature in your database. Likely you wil find table scans which of course are going to get significantly slower as the number of records increases.
You may also have a problem with parameter sniffing. Please google to see how to fix that.

One improvement would be to make sure that dbo.FN_GETRPTSSIGNMENTID only gets executed once.
Currently, it gets executed three times.
You can replace two of those calls by joining to the field of the (one) remaing call.
Something like
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE ON EMPLEE.PERSON_ID = PER.PERSON_ID AND dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
INNER JOIN (
SELECT w1.ASSIGNMENT_ID
, w1.WORKSHEET_ID
, w1.EFFECTIVE_DATE
, w1.APPROVED_BY
, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3 ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE =
CASE WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (
SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) = w2.EFFECTIVE_DATE)
)
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
) PERSON_WKS ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN (
SELECT ASSIGNMENT_ID
, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (
SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP'
)
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN ON PERSON_ASGN.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE' AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
) HOME_PAYROLL ON HOME_PAYROLL.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
WHERE (#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND (#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1) OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND (#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND (#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND (#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND (#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND (#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND (#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND (#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND (#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND (#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND (#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND (#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND (#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY
PER.LAST_NAME ASC
, PER.FIRST_NAME ASC
, PERSON_WKS.EFFECTIVE_DATE DESC

Related

How can I had multiple values to a variable or an Array

I have a working query below. however I need to make OWNRSHP_ID a variable that I can supply a list of OWNRSHP_IDs to be ran through the query one by one.
The idea is to have a variable that I can supply a list of ID and the query will run through each one one by one.
This SQL that I'm currently running in Teradata.
Select distinct
inv_corp.OWNRSHP_ID
,SE.Sending_entity_nm AS Bottler
,snap.FSH_DSTR_OWNRSHP_ID AS DELIVERY_SOURCE
,inv_corp.BTLR_DLVR_PNT_NO AS BTLR_DLVR_PNT_NO
,snap.DLVR_PNT_NM AS BTLR_DLVR_PNT_NM
,snap.CHNL_TYPE_DESC AS MARKET_TYPE
,snap.TRADE_CHNL_DESC AS TRADE_CHNL_DESC
,snap.TCCC_SUB_CHNL_NM AS TCCC_SUB_CHNL_NM
,snap.STATE AS STATE
,CASE
WHEN cbs.CBS_BUSINESS_TYPE = 1 THEN 'TRADE SALE'
WHEN cbs.CBS_BUSINESS_TYPE = 4 THEN 'FULL SERVE'
WHEN cbs.CBS_BUSINESS_TYPE = 5 THEN 'EXTRNL SLS'
ELSE NULL
END AS CBS_BUSINESS_TYPE
,ptype.PRD_TYP_NM AS PROD_TYPE
,cal.CUR_YR_AC_PRD AS CAL_YEAR_MONTH
--,cal.CUR_YR_AC_PRD AS CAL_YEAR_MONTH
,inv_corp.Inv_dt
,sum(CASE
WHEN (qty) IS NOT NULL THEN (qty* TCCC_192CONV(FLOAT))
ELSE 0
END )AS VolEQ --20 fields
,sum(CASE
WHEN (qty) IS NOT NULL THEN (cast(qty as FLOAT )* cast(prodet.STD_ADJ_FCT as FLOAT))
ELSE 0
END) AS VolStd
,(sum(Whlsl_Price_Xtnd) - sum(Off_Inv_Cma_Disc)) - (sum(Off_Inv_Ctm_Disc) - sum(On_Inv_Disc) ) as DNSI
FROM CORP_LINES_VIEWS.LINE_CORP line_corp
join corp_invoice_VIEWS.invoice_corp inv_corp
On line_corp.Tsr_Inv_Ref_No = inv_corp.Tsr_Inv_Ref_No
and line_corp.OWNRSHP_ID = inv_corp.OWNRSHP_ID
Join CBS_VIEWS.CBS_DELIVERY_POINT cbs
ON inv_corp.BTLR_DLVR_PNT_NO = cbs.BTLR_DLVR_PNT_NO
and inv_corp.OWNRSHP_ID = cbs.OWNRSHP_ID
Join CHR_VIEWS.DPT_SNAPSHOT_SELECT snap
ON inv_corp.BTLR_DLVR_PNT_NO = snap.BTLR_DLVR_PNT_NO
and inv_corp.OWNRSHP_ID = snap.OWNRSHP_ID
Join CBS_VIEWS.sending_entity se
ON inv_corp.OWNRSHP_ID = se.OWNRSHP_ID
Join NSR_VIEWS.PRODET prodet
ON prodet.cce_material_no = line_corp.cce_material_no
Join DLCCC_CUST_CNTC_CNTR_LAB.TBL_3PY_to_YTD_CAL cal
ON CAL.fact_dt = line_corp.Inv_dt
Join CORP_LINES.MATL_JOIN_KEY mkey
ON mkey.cce_material_no = line_corp.cce_material_no
and mkey.OWNRSHP_ID = line_corp.OWNRSHP_ID
Join IWR_VIEWS.MN_PROD_TYPE ptype
ON ptype.tsr_prd_typ = prodet.tsr_prd_typ
Where 1=1
and line_corp.inv_dt>'2018-01-01'
and line_corp.OWNRSHP_ID IN (10,55,75,110,65,85,95)
GROUP BY
inv_corp.OWNRSHP_ID
,SE.Sending_entity_nm
,snap.FSH_DSTR_OWNRSHP_ID
,inv_corp.BTLR_DLVR_PNT_NO
,snap.DLVR_PNT_NM
,snap.CHNL_TYPE_DESC
,snap.TRADE_CHNL_DESC
,snap.TCCC_SUB_CHNL_NM
,snap.STATE
,cbs.CBS_BUSINESS_TYPE
,ptype.PRD_TYP_NM
,cal.CUR_YR_AC_PRD
,inv_corp.Inv_dt
Well, you currently do supply a list of OWNRSHP_IDs in
and line_corp.OWNRSHP_ID IN (10,55,75,110,65,85,95)
But assuming you want to pass this list as a comma-separated string you can apply STRTOK_SPLI_TO_TABLE
and line_corp.OWNRSHP_ID IN
(
SELECT Cast(token AS INT) AS OWNRSHP_ID, tokennum
FROM TABLE (StrTok_Split_To_Table(1, :OWNRSHP_IDs, ',')
RETURNS (outkey INTEGER,
tokennum INTEGER,
token VARCHAR(20) CHARACTER SET Unicode)
) AS d
)
If you move this into a Derived Table you can even order by the position of the id within the input string:
...
Join IWR_VIEWS.MN_PROD_TYPE ptype
ON ptype.tsr_prd_typ = prodet.tsr_prd_typ
JOIN
(
SELECT Cast(token AS INT) AS OWNRSHP_ID, tokennum
FROM TABLE (StrTok_Split_To_Table(1, :OWNRSHP_IDs, ',')
RETURNS (outkey INTEGER,
tokennum INTEGER,
token VARCHAR(20) CHARACTER SET Unicode)
) AS d
) as dt
ON inv_corp.OWNRSHP_ID = dt.OWNRSHP_ID
...
ORDER BY tokennum;
And when you Outer Join to the Derived Table you can also return a NULL row for a missing ID, but this probably needs some additional changes to your query.

How to tune this query in Oracle 11g

I have been asked to tune the below query and would like to know if there is any better way to tune it?
SELECT req_dtl.lab_ord_occ_test_id ,
req_dtl.order_ref_no ,
req_dtl.accession_no ,
req_dtl.test_code ,
req_dtl.test_name ,
req_dtl.test_id ,
req_dtl.schedule_id ,
req_dtl.lab_ord_occ_id ,
req_dtl.order_type ,
lab_occ.facility_id ,
lab_occ.patient_id ,
lab_occ.order_draw_dt ,
hdr.source_system ,
(SELECT CORPORATION_ACRONYM
FROM corporation c,
facility f
WHERE c.corporation_id = f.corporation_id
AND f.facility_id = lab_occ.facility_id) AS corporation_acronym,
tst.container ,
lab_occ.order_duration_type ,
occ_test.mnc_yn
FROM ORDER_REQUISITION_HEADER hdr ,
ORDER_REQUISITION_DETAIL req_dtl ,
LAB_ORDER_OCC_TEST occ_test ,
LAB_ORDER_OCC lab_occ ,
TEST tst
WHERE hdr.requisition_hdr_id = in_requisition_hdr_id
AND hdr.msg_sent_to_lab_yn = 'Y'
AND req_dtl.requisition_hdr_id = hdr.requisition_hdr_id
AND occ_test.lab_order_occ_test_id = req_dtl.lab_ord_occ_test_id
AND req_dtl.test_id = tst.test_id
AND tst.accession_type NOT LIKE 'CMP%'
AND occ_test.status != 'R'
AND occ_test.lab_order_occ_id = lab_occ.lab_order_occ_id
AND lab_occ.status = 'A'
AND occ_test.created_dt >= hdr.msg_sent_to_lab_dt
AND NVL(occ_test.test_sent_to_lab_yn,'N') = 'N'
AND NOT EXISTS
(SELECT orddata.*
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
AND orddata.lab_order_occ_test_id=occ_test.lab_order_occ_test_id
)
ORDER BY req_dtl.accession_no;
In the execution plan no tables are going for full table scan.Only nested loops are more.
*Suggest better way to tune this query *
AND NOT EXISTS
(SELECT orddata.*
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
AND orddata.lab_order_occ_test_id=occ_test.lab_order_occ_test_id
)
could be moved to FROM
FROM
...
LEFT JOIN (SELECT DISTINCT orddata.lab_order_occ_test_id
FROM MISSING_ORDER_DATA orddata,
TEST_CONFIG_HOLD_AOE tcha
WHERE orddata.test_id = tcha.test_id
AND tcha.active_yn = 'Y'
AND orddata.status_flag = 'A'
AND orddata.answer IS NULL
AND orddata.msg_sent_to_lab_yn = 'N'
) missing ON missing.lab_order_occ_test_id = occ_test.lab_order_occ_test_id
WHERE missing.lab_order_occ_test_id IS NULL
Also you should move the acronym
FROM
...
INNER JOIN (SELECT CORPORATION_ACRONYM, f.facility_id
FROM corporation c,
facility f
WHERE c.corporation_id = f.corporation_id) acr ON
acr.facility_id = lab_occ.facility_id)
...Additionally, the TEST object must have an index on accession_type otherwise the tst.accession_type not like 'CMP%' clause will be slower than necessary.
Also, the clause: NVL(occ_test.test_sent_to_lab_yn,'N') = 'N' is essentially an outer join on partially-validated data. Does the test_sent_to_lab_yn column in occ_test contain nulls? If not, consider using an IN clause along with a valid list. [it looks like a yes/no column, maybe this should be equality on 'Y' and get someone to clean up the nulls?]
Please post the explain plan so we can suggest a re-ordering of the predicates in order to minimize the row-returns in first clause....and make HINT suggestions.

SQL Server / T-SQL : query optimization assistance

I have this QA logic that looks for errors into every AuditID within a RoomID to see if their AuditType were never marked Complete or if they have two complete statuses. Finally, it picks only the maximum AuditDate of the RoomIDs with errors to avoid showing multiple instances of the same RoomID, since there are many audits per room.
The issue is that the AUDIT table is very large and takes a long time to run. I was wondering if there is anyway to reach the same result faster.
Thank you in advance !
IF object_ID('tempdb..#AUDIT') is not null drop table #AUDIT
IF object_ID('tempdb..#ROOMS') is not null drop table #ROOMS
IF object_ID('tempdb..#COMPLETE') is not null drop table #COMPLETE
IF object_ID('tempdb..#FINALE') is not null drop table #FINALE
SELECT distinct
oc.HotelID, o.RoomID
INTO #ROOMS
FROM dbo.[rooms] o
LEFT OUTER JOIN dbo.[hotels] oc on o.HotelID = oc.HotelID
WHERE
o.[status] = '2'
AND o.orderType = '2'
SELECT
t.AuditID, t.RoomID, t.AuditDate, t.AuditType
INTO
#AUDIT
FROM
[dbo].[AUDIT] t
WHERE
t.RoomID IN (SELECT RoomID FROM #ROOMS)
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
SELECT
o.HotelID, o.RoomID,
a.AuditID, a.RoomID, a.AuditDate, a.AuditType, a.CompleteStatus,
c.ClientNum
INTO
#FINALE
FROM
#ROOMS O
LEFT OUTER JOIN
#COMPLETE a on o.RoomID = a.RoomID
LEFT OUTER JOIN
[dbo].[clients] c on o.clientNum = c.clientNum
SELECT
t.*,
Complete_Error_Status = CASE WHEN t.CompleteStatus = 0
THEN 'Not Complete'
WHEN t.CompleteStatus > 1
THEN 'Complete More Than Once'
END
FROM
#FINALE t
INNER JOIN
(SELECT
RoomID, MAX(AuditDate) AS MaxDate
FROM
#FINALE
GROUP BY
RoomID) tm ON t.RoomID = tm.RoomID AND t.AuditDate = tm.MaxDate
One section you could improve would be this one. See the inline comments.
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
COUNT(1) AS CompleteStatus
-- Use the above along with the WHERE clause below
-- so that you are aggregating fewer records and
-- avoiding a CASE statement. Remove this next line.
--SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
WHERE
AuditType = 'Complete'
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
Just a thought. Streamline your code and your solution. you are not effectively filtering your datasets smaller so you continue to query the entire tables which is taking a lot of your resources and your temp tables are becoming full copies of those columns without the indexes (PK, FK, ++??) on the original table to take advantage of. This by no means is a perfect solution but it is an idea of how you can consolidate your logic and reduce your overall data set. Give it a try and see if it performs better for you.
Note this will return the last audit record for any room that has either not had an audit completed or completed more than once.
;WITH cte AS (
SELECT
o.RoomId
,o.clientNum
,a.AuditId
,a.AuditDate
,a.AuditType
,NumOfAuditsComplete = SUM(CASE WHEN a.AuditType = 'Complete' THEN 1 ELSE 0 END) OVER (PARTITION BY o.RoomId)
,RowNum = ROW_NUMBER() OVER (PARTITION BY o.RoomId ORDER BY a.AuditDate DESC)
FROm
dbo.Rooms o
LEFT JOIN dbo.Audit a
ON o.RoomId = a.RoomId
WHERE
o.[Status] = 2
AND o.OrderType = 2
)
SELECT
oc.HotelId
,cte.RoomId
,cte.AuditId
,cte.AuditDate
,cte.AuditType
,cte.NumOfAuditsComplete
,cte.clientNum
,Complete_Error_Status = CASE WHEN cte.NumOfAuditsComplete > 1 THEN 'Complete More Than Once' ELSE 'Not Complete' END
FROM
cte
LEFT JOIN dbo.Hotels oc
ON cte.HotelId = oc.HotelId
LEFT JOIN dbo.clients c
ON cte.clientNum = c.clientNum
WHERE
cte.RowNum = 1
AND cte.NumOfAuditsComplete != 1
Also note I changed your
WHERE
o.[status] = '2'
AND o.orderType = '2'
TO
WHERE
o.[status] = 2
AND o.orderType = 2
to be numeric without the single quotes. If the data type is truely varchar add them back but when you query a numeric column as a varchar it will do data conversion and may not take advantage of indexes that you have built on the table.

Select from multiple tables with multiple where clauses

I am trying to write a stored procedure that will give a count of all the cases in a table that are not deleted, grouped by a CaseStatusID in another table, but only the cases that have a CaseStatusID that also isn't deleted. I also want it to return any CaseStatusID that does not have case related to it (i.e. a count of 0)
So far I have tried
Create Table #tCaseStatus (CaseStatusID int,CaseStatusDesc varchar(200) )
declare #NofCases int
declare #CaseStatusID int
declare #CaseStatusDesc varchar(200)
BEGIN
INSERT #tCaseStatus
Select CaseStatusID, CaseStatusDesc From dbo.CaseStatus Where IsDeleted = 0
Select #NofCases = Count(*) From #tCaseStatus
While (#NofCases > 0)
Begin
Select Top (1) #CaseStatusID = CaseStatusID, #CaseStatusDesc = CaseStatusDesc from #tCaseStatus
SELECT CaseStatusDesc, Count(CaseID) AS CountCases
FROM Cases inner join #tCaseStatus on Cases.CaseStatusID = #tCaseStatus.CaseStatusID
WHERE (IsDeleted = 0) AND Cases.CaseStatusID = #CaseStatusID
Group by #tCaseStatus.CaseStatusDesc
Set #NofCases = #NofCases - 1
Delete Top(1) from #tCaseStatus
End
END
AND
This returns the correct cases but excludes any of the CaseStatusDesc that have a count of 0
SELECT CaseStatus.CaseStatusDesc, COUNT(Cases.CaseID) AS CaseCount
FROM Cases FULL OUTER JOIN
CaseStatus ON Cases.CaseStatusID = CaseStatus.CaseStatusID
WHERE (CaseStatus.IsDeleted = 0) AND
(Cases.IsDeleted = 0)
GROUP BY CaseStatus.CaseStatusDesc, CaseStatus.CaseStatusID
ORDER BY CaseStatus.CaseStatusID
AND
this returns all the CaseStatusDesc's even the ones that are deleted
SELECT CaseStatus.CaseStatusDesc, COUNT(CASE
WHEN CaseStatus.IsDeleted = 0 THEN 'ok'
WHEN Cases.IsDeleted = 0 THEN 'ok'
Else null
END) AS [Case]
FROM Cases FULL OUTER JOIN CaseStatus ON Cases.CaseStatusID = CaseStatus.CaseStatusID
GROUP BY CaseStatus.CaseStatusDesc, CaseStatus.CaseStatusID
Order By CaseStatus.CaseStatusID asc
But I cant seem to get the desired results
Is this what you're after?
select
casestatus.casestatusid,
casestatusdesc,
COUNT(caseid)
from casestatus
left join cases
on casestatus.casestatusid = cases.casestatusid
and cases.isdeleted=0
where
casestatus.isdeleted=0
group by
casestatus.casestatusid,
casestatusdesc

From Procedure to View

Code below works perfect as procedure.
How can I transform or change the same code below so that it can work in View or as View code or View?
Can I drop View?
ALTER proc [dbo].[NewOne_1]
as
begin
set nocount on
if object_ID('TEMPDB..#TableA') <> ''
drop table # TableA
select
*
into # TableA
from vd_View po
if object_ID('TEMPDB..#FirstSDate') is not null
drop table #FirstSDate
select
Pt_id = Pat_Id,
Date_of_First_Shipment = min(DeliveryDate)
into #FSDate
from # TableA po
group by Pat_Id
if object_ID('TEMPDB..#LastSDate') is not null
drop table #LastShipDate
select
Pt_id = Pat_Id,
Date_of_Last_Shipment = max(DeliveryDate)
into #LastShipDate
from # TableA po
group by Pat_Id
SELECT PtData.Pat_No Progress_Pat_ID
,C_S = case when dbo.fn_GetBusinessDays(firstship.Date_of_First_Shipment,LastShip.Date_of_Last_Shipment) > 80 then 'Yes'
when dbo.fn_GetBusinessDays(firstship.Date_of_First_Shipment,LastShip.Date_of_Last_Shipment) <= 80 then 'No'
else ''
end
,P_Last_Name = PtData.P_LName
,PtData.DReg Reg
FROM dbo.tbld_PatSum PtData
inner join vd_PSum ps
on PtData.P = ps.P_ID
inner join S_M.dbo.Pat__c ps1
on PtData.Pt_ID = ps1.Id
left join #FirstShipDate firstship
on PtData.Pt_ID = firstship.Pt_Id
left join #LastShipDate LastShip
on PtData.Pt_ID = LastShip.Pt_Id
WHERE PtData.Pat_No IS NOT NULL
AND PtData.ActiveStatus<>'Gen Info'
set nocount off
end
I'm guessing that you're wanting to be able to use this to join with something else. You cannot put this into a view. However you may be able to put this in a table-valued function which would allow you to accomplish what I think you're after.
--just took your code (it's quite messy), the dbo.fn_GetBusinessDays function must be deterministic in order to work in a view
create view test as
SELECT
PtData.Pat_No Progress_Pat_ID
,C_S = case when dbo.fn_GetBusinessDays(firstship.Date_of_First_Shipment,LastShip.Date_of_Last_Shipment) > 80 then 'Yes'
when dbo.fn_GetBusinessDays(firstship.Date_of_First_Shipment,LastShip.Date_of_Last_Shipment) <= 80 then 'No'
else ''
end
,P_Last_Name = PtData.P_LName
,PtData.DReg Reg
FROM dbo.tbld_PatSum PtData
inner join vd_PSum ps
on PtData.P = ps.P_ID
inner join S_M.dbo.Pat__c ps1
on PtData.Pt_ID = ps1.Id
left join (
select
Pt_id = Pat_Id,
Date_of_First_Shipment = min(DeliveryDate)
from vd_View po
group by Pat_Id ) firstship
on PtData.Pt_ID = firstship.Pt_Id
left join (select
Pt_id = Pat_Id,
Date_of_Last_Shipment = max(DeliveryDate)
from vd_View po
group by Pat_Id ) LastShip
on PtData.Pt_ID = LastShip.Pt_Id
WHERE PtData.Pat_No IS NOT NULL
AND PtData.ActiveStatus<>'Gen Info'