Sql how to change query based on parameters - sql

Sorry I don't know how to put it in title, I have this query on an aspx page with 2 datepickers (let's say data and data2)
select utenti.nome as tecnico, Richieste.IDRic as idchia, richieste.descr as rdescr, ISNULL(richieste.assistremota,0) as assremota, Clienti.RagSociale as ragsoc, richieste.descr as descr, richieste.priorita as prior, richieste.tipo as tipo, richieste.rforologio as rforo, ISNULL(statoric.appuntamento,0) as app, ISNULL(statoric.oradalle,0) as dalle, ISNULL(statoric.oraalle,0) as alle, statoric.ID as idstato
from clienti
inner join richieste on clienti.idcliente = richieste.rfcliente
inner join statoric on statoric.rfric = richieste.idric
inner join stati on stati.idstato = statoric.rfstato
inner join utenti on utenti.idutente=statoric.rftecnico
where statoric.attuale = 1 and statoric.rfstato < 14 and statoric.dataass = #data and statoric.rftecnico = 8 order by app desc, oraalle asc, prior desc
I need to change the "statoric.dataass = #data" part to do this (pseudocode):
if data 2 is null then
"statoric.dataass = #data"
else
"statoric.dataass between #data and #data2"
end if
How can I do it? I tried case and If but I'm doing something wrong... thanks

Try coalesce
... statoric.dataass between #data and coalesce(#data2, #data) ...

Here is one method:
where statoric.attuale = 1 and
statoric.rfstato < 14 and
( (#data2 is null and statoric.dataass = #data) or
statoric.dataass between #data and #data2
) and
statoric.rftecnico = 8
However, you might consider this:
where statoric.attuale = 1 and
statoric.rfstato < 14 and
statoric.dataass >= #data and
statoric.dataass <= coalesce(#data2, #data) and
statoric.rftecnico = 8
The advantage of this approach is that it can take advantage of an index on (attuale, rftecnico, dataass).

Related

How to use If Else if and Else in stored procedures | SQL Server

I have created the following stored procedure where user passes input parameters to get the data. The input parameters are optional i.e. passing just one parameter should produce some data.
Here is my code.
ALTER PROC [dbo].[SPR_ECRM_CASE_INFORMATION]
#ID_APPLICATION_NO NVARCHAR(20),
#TX_ID_NO NVARCHAR(20)
AS
BEGIN
SET NOCOUNT ON
IF (#ID_APPLICATION_NO IS NOT NULL ) OR (LEN(#ID_APPLICATION_NO) > 0) AND ((#TX_ID_NO IS NOT NULL) OR (LEN(#TX_ID_NO) > 0))
BEGIN
SELECT DISTINCT
[A].[ID_APPLICATION_NO]
,[A].[TX_APPLICATION_STATUS]
FROM [VW_T_APPLICATION] As [A]
INNER JOIN [CT_L1_APPLICATION_STATUS] [L] ON [L].[TX_L1_APPLICATION_STATUS_CODE] = [A].[TX_APPLICATION_STATUS_CODE]
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [I] WITH(NOLOCK) ON [I].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[II].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [II] WITH(NOLOCK)
WHERE [II].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [II].[CD_APPLICANT_TYPE] = 81
AND [II].[IN_ACTIVE] = 1
ORDER BY
[II].[ID_APPLICATION_APPLICANT] DESC)
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [J] WITH(NOLOCK) ON [J].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[JJ].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [JJ] WITH(NOLOCK)
WHERE [JJ].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [JJ].[CD_APPLICANT_TYPE] = 82
AND [JJ].[IN_ACTIVE] = 1
ORDER BY
[JJ].[ID_APPLICATION_APPLICANT] DESC)
WHERE
[I].[TX_ID_NO] = #TX_ID_NO AND [J].[TX_ID_NO] = #TX_ID_NO
AND
[A].[TX_APPLICANT_ID_NO] = #ID_APPLICATION_NO
AND
[A].[IN_ACTIVE] = 1
END
ELSE IF (#ID_APPLICATION_NO IS NOT NULL) OR (LEN(#ID_APPLICATION_NO) > 0)
BEGIN
SELECT DISTINCT
[A].[ID_APPLICATION_NO]
,[A].[TX_APPLICATION_STATUS]
FROM [VW_T_APPLICATION] As [A]
INNER JOIN [CT_L1_APPLICATION_STATUS] [L] ON [L].[TX_L1_APPLICATION_STATUS_CODE] = [A].[TX_APPLICATION_STATUS_CODE]
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [I] WITH(NOLOCK) ON [I].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[II].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [II] WITH(NOLOCK)
WHERE [II].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [II].[CD_APPLICANT_TYPE] = 81
AND [II].[IN_ACTIVE] = 1
ORDER BY
[II].[ID_APPLICATION_APPLICANT] DESC)
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [J] WITH(NOLOCK) ON [J].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[JJ].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [JJ] WITH(NOLOCK)
WHERE [JJ].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [JJ].[CD_APPLICANT_TYPE] = 82
AND [JJ].[IN_ACTIVE] = 1
ORDER BY
[JJ].[ID_APPLICATION_APPLICANT] DESC)
WHERE
[A].[TX_APPLICANT_ID_NO] = #ID_APPLICATION_NO
AND
[A].[IN_ACTIVE] = 1
END
ELSE IF (#TX_ID_NO IS NOT NULL) OR (LEN(#TX_ID_NO) > 0)
BEGIN
SELECT DISTINCT
[A].[ID_APPLICATION_NO]
,[A].[TX_APPLICATION_STATUS]
FROM [VW_T_APPLICATION] As [A]
INNER JOIN [CT_L1_APPLICATION_STATUS] [L] ON [L].[TX_L1_APPLICATION_STATUS_CODE] = [A].[TX_APPLICATION_STATUS_CODE]
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [I] WITH(NOLOCK) ON [I].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[II].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [II] WITH(NOLOCK)
WHERE [II].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [II].[CD_APPLICANT_TYPE] = 81
AND [II].[IN_ACTIVE] = 1
ORDER BY
[II].[ID_APPLICATION_APPLICANT] DESC)
LEFT JOIN [VW_ST_APPLICATION_APPLICANT] [J] WITH(NOLOCK) ON [J].[ID_APPLICATION_APPLICANT] = (SELECT TOP 1
[JJ].[ID_APPLICATION_APPLICANT]
FROM
[ST_APPLICATION_APPLICANT] [JJ] WITH(NOLOCK)
WHERE [JJ].[ID_APPLICATION_GUID] = [A].[ID_APPLICATION_GUID]
AND [JJ].[CD_APPLICANT_TYPE] = 82
AND [JJ].[IN_ACTIVE] = 1
ORDER BY
[JJ].[ID_APPLICATION_APPLICANT] DESC)
WHERE
[I].[TX_ID_NO] = #TX_ID_NO OR [J].[TX_ID_NO] = #TX_ID_NO
AND
[A].[IN_ACTIVE] = 1
END
ELSE
BEGIN
RETURN NULL
END
END
I have used if else if and else condition but it fails to return the data.
DECLARE #A NVARCHAR(30)
DECLARE #B NVARCHAR(20)
SET #A = 'C192'
SET #B = 'ABC'
EXEC SPR_ECRM_CASE_INFORMATION #A, ''
EXEC SPR_ECRM_CASE_INFORMATION '', #B
EXEC SPR_ECRM_CASE_INFORMATION '', ''
Firstly, the else if condition fails and my code here is redundant. Is there any better way to optimize this. Your help is appreciated.
If you want to optimize for performance, you can create a single procedure for each query. Each will get it's own query plan. You can call each in this procedure.
Looking at each query, I see the sub-query in the ON clause. I also see NOLOCK which I normally consider a bad sign. Also see the DISTINCT. These are all clues that the query can be simplified. SQL Server will then be more likely to optimize the query. (You can ask for the same thing in more than one way. The more complex the logic, the less likely SQL will find the best plan.)
If the data in [VW_T_APPLICATION] is already distinct, then get rid of DISTINCT and use EXISTS instead of LEFT JOINS - one EXISTS for 81 and one for 82. (I'm assuming you are not going to need columns from these.)
The use of "VW" implies the use of views. The view can hide a lot of logic that gets in the way of a simple query.
Is this part (your first IF) correct in terms of bracketing? It will run if #ID_Application_No is NOT NULL, regardless of whether #TX_ID_No has a value.
IF (#ID_APPLICATION_NO IS NOT NULL ) OR (LEN(#ID_APPLICATION_NO) > 0) AND ((#TX_ID_NO IS NOT NULL) OR (LEN(#TX_ID_NO) > 0))
I'm guessing you want either
a) brackets around the ID_Application_No part e.g.,
IF ((#ID_APPLICATION_NO IS NOT NULL ) OR (LEN(#ID_APPLICATION_NO) > 0)) AND ((#TX_ID_NO IS NOT NULL) OR (LEN(#TX_ID_NO) > 0))
or b) want it to be an AND (this is my most likely guess) e.g.,
IF (#ID_APPLICATION_NO IS NOT NULL ) AND (LEN(#ID_APPLICATION_NO) > 0) AND ((#TX_ID_NO IS NOT NULL) OR (LEN(#TX_ID_NO) > 0))
Note you can simplify some things e.g., when you have IF (#ID_APPLICATION_NO IS NOT NULL) OR (LEN(#ID_APPLICATION_NO) > 0), the first part will always be true if the second part is true. In those cases, you can use only IF (#ID_APPLICATION_NO IS NOT NULL) and it will give the same results.

multiple errors in using with function in select statement

I'm having some problems with my select statement. When I try to execute it, it gives 3 errors
Must specify table to select from
An object or column name is missing or empty for SELECT INFO statements. verify each column
has a name. For other statements, look for empty alias names. Aliases defined...
Column name or number of supplied values does not match table definition.
WITH A AS
(SELECT ROW_NUMBER() OVER (ORDER BY
CASE
WHEN #pOrderBy = 'SortByName' THEN colPortAgentVendorNameVarchar
WHEN #pOrderBy = 'SortByCOuntry' THEN colCountryNameVarchar
WHEN #pOrderBy = 'SortByCity' THEN colCityNameVarchar
END,
colPortAgentVendorNameVarchar
) xRow, A.*
FROM
(
SELECT DISTINCT
V.colPortAgentVendorIDInt,
colPortAgentVendorNameVarchar = RTRIM(LTRIM(V.colPortAgentVendorNameVarchar)),
C.colCountryNameVarchar,
Y.colCityNameVarchar,
V.colContactNoVarchar,
V.colFaxNoVarchar,
V.colEmailToVarchar,
V.colWebsiteVarchar,
BR.colBrandIdInt,
PR.colPriorityTinyint,
colBrandCodeVarchar = RTRIM(LTRIM(BR.colBrandCodeVarchar))
FROM dbo.TblVendorPortAgent V
LEFT JOIN TblCountry C ON C.colCountryIDInt = V.colCountryIDInt
LEFT JOIN TblCity Y ON Y.colCityIDInt = V.colCityIDInt
LEFT JOIN tblBrandAirportPortAgent PR ON PR.colPortAgentVendorIDInt = V.colPortAgentVendorIDInt
AND PR.colIsActiveBit = 1
LEFT JOIN TblBrand BR ON BR.colBrandIdInt = PR.colBrandIdInt
AND BR.colIsActiveBit = 1
WHERE V.colIsActiveBit = 1
AND V.colPortAgentVendorNameVarchar LIKE '%'+ #pPortAgentVendor +'%'
AND (PR.colBrandIdInt = #pBrandID OR #pBrandID = 0)
) A
)
INSERT INTO #tempPortAgent
SELECT A.*, IsWithContract = CASE WHEN colContractIdInt IS NULL THEN CAST(0 AS BIT) ELSE CAST(1 AS BIT) END FROM A LEFT JOIN TblContractPortAgent B ON A.colPortAgentVendorIDInt = B.colPortAgentVendorIDInt
AND B.colIsActiveBit = 1
;WITH QQ AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY Q.colPortAgentVendorIDInt ORDER BY xRow,
ContractStatusOrder,
colDateCreatedDate DESC
)ContractRow,*
FROM
(
SELECT DISTINCT GG.*, B.colContractIdInt, B.colContractStatusVarchar, B.colDateCreatedDate ,
ContractStatusOrder = CASE WHEN B.colContractStatusVarchar = 'Approved' THEN 1 ELSE '2' END
FROM #tempPortAgent GG LEFT JOIN TblContractPortAgent B ON GG.colPortAgentVendorIDInt = B.colPortAgentVendorIDInt
AND B.colIsActiveBit = 1
) Q
)SELECT * INTO #tempPortAgentWithContract
SELECT * FROM #tempPortAgentWithContract
I don't really know where its showing, because the errors are saying that these are inside the select statements inside.
1- Use Select Into instead of Insert into select
SELECT A.*, IsWithContract = CASE WHEN colContractIdInt IS NULL THEN CAST(0 AS BIT) ELSE CAST(1 AS BIT) END
Into #tempPortAgent
FROM A
LEFT JOIN TblContractPortAgent B ON A.colPortAgentVendorIDInt = B.colPortAgentVendorIDInt
AND B.colIsActiveBit = 1
2- SELECT * INTO #tempPortAgentWithContract is incorrect syntax. you must use following format:
SELECT * INTO #tempPortAgentWithContract From QQ

Sql in sql server with convert

I am trying to use convert in an where clause in the select statement. My query looks like this:
SELECT DISTINCT TOP 10 [SurveyResult].*
,[Ticket].[RefNumber]
FROM [SurveyResult]
LEFT JOIN [Ticket] ON [SurveyResult].[TicketID] = [Ticket].[TicketID]
JOIN [SurveyResponse] AS SurveyResponse1 ON [SurveyResult].[ResultID] = SurveyResponse1.[ResultID]
JOIN [QuestionAnswer] AS QuestionAnswer1 ON SurveyResponse1.[AnswerID] = QuestionAnswer1.[AnswerID]
JOIN [SurveyQuestion] AS SurveyQuestion1 ON QuestionAnswer1.[QuestionID] = SurveyQuestion1.[QuestionID]
WHERE SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CONVERT(INT, SurveyResponse1.[Response]) >= 1
AND CONVERT(INT, SurveyResponse1.[Response]) <= 5
The problem is that I get some errors when converting the values to integer in the where statement.
I know I have some rows that don't contain numbers in the Response column but I filter those so without the convert part in the where clause I get only numbers so it works like this:
SELECT TOP 1000 [ResponseID]
,[ResultID]
,[Response]
FROM [WFSupport].[dbo].[SurveyResponse]
JOIN QuestionAnswer ON SurveyResponse.AnswerID = QuestionAnswer.AnswerID
WHERE QuestionAnswer.QuestionID = 'C10BF42E-5D51-46BC-AD89-E57BA80EECFD'
And in the results I get numbers but once I add the convert part in the statement I I get an error that it can't convert some text to numbers.
Either do like Mark says or just have NULL values default to something numerical, this would give you a where statement like:
WHERE SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CONVERT(INT, ISNULL(SurveyResponse1.[Response],0)) BETWEEN 1 AND 5
The important part is the ISNULL() function and I also used BETWEEN to avoid duplicate converts.
Try:
SELECT DISTINCT TOP 10
[SurveyResult].*,
[Ticket].[RefNumber]
FROM
[SurveyResult]
LEFT JOIN [Ticket] ON [SurveyResult].[TicketID] = [Ticket].[TicketID]
JOIN [SurveyResponse] AS SurveyResponse1
ON [SurveyResult].[ResultID] = SurveyResponse1.[ResultID]
JOIN [QuestionAnswer] AS QuestionAnswer1
ON SurveyResponse1.[AnswerID] = QuestionAnswer1.[AnswerID]
JOIN [SurveyQuestion] AS SurveyQuestion1
ON QuestionAnswer1.[QuestionID] = SurveyQuestion1.[QuestionID]
where SurveyQuestion1.[SurveyID] = [SurveyResult].[SurveyID]
AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CASE SurveyQuestion1.[QuestionID]
WHEN 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
THEN Convert(int, SurveyResponse1.[Response])
ELSE 0
END BETWEEN 1 AND 5
(The AND SurveyQuestion1.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016' is retained in case the query is using an index on QuestionID - if not, it can be removed, as the same condition is implicit in the subsequent CASE condition.)
Try this one -
SELECT DISTINCT TOP 10 sr.*, t.[RefNumber]
FROM dbo.SurveyResult sr
JOIN dbo.SurveyResponse sr2 ON sr.[ResultID] = sr2.[ResultID]
JOIN dbo.QuestionAnswer sa ON sr2.[AnswerID] = sa.[AnswerID]
JOIN dbo.SurveyQuestion sq ON sa.[QuestionID] = sq.[QuestionID] AND sq.[SurveyID] = sr.[SurveyID]
LEFT JOIN dbo.Ticket t ON sr.[TicketID] = t.[TicketID]
WHERE sq.[QuestionID] = 'C86CB39A-8FE0-4FE8-B38F-17F1BE611016'
AND CAST(ISNULL(sr2.[Response], 0) AS INT) BETWEEN 1 AND 5

SQL SP runs Slow

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

How to Optimize this SQL Query?

I have 3 tables:
CRSTasks (ID,parentID)
CRSTaskReceivers (ID,tskID,receiverID)
UserNames (id,name)
...relation between CRSTasks and CRSTaskReceivers one-to-many
between UserNames and CRSTaskReceivers one-to-one
tasks
ID parent
1 null
10 1
50 1
taskReceivers
id taskID receiverID
1 1 4(john)
1 10 2(mike)
1 50 3(brand)
I need result like that:
taskid Receivers
-------------------
1 jone,mike,brand
ONLY FOR PARENT TASKS IT WILL CONCATE RECEIVERS
SQL Server 2005+:
SELECT t.id AS taskid,
STUFF((SELECT ','+ x.name
FROM (SELECT COALESCE(pu.[ArabicName], aut.Name) AS name
FROM CRSTaskReceivers tr
JOIN AD_USER_TBL aut ON aut.id = tr.receiverid
LEFT JOIN PORTAL_USERS pu ON pu.id = aut.id
WHERE tr.crstaskid = t.id
AND tr.receivertype = 1
UNION
SELECT agt.name
FROM CRSTaskReceiver tr
JOIN AD_GROUP_TBL sgt ON agt.id = tr.receiverid
WHERE tr.receivertype = 3
AND tr.crstaskid = t.id) x
FOR XML PATH('')), 1, 1, '')
FROM CRSTasks t
Don't need the function.
Besides the odd string concatenation going on it sure looks like all that could be done in one query instead of four. It's perfectly fine to have more than one criteria in a join. Something along:
FROM CRSTaskReceiver
INNER JOIN CRSTask
ON CRSTaskReceiver.CRSTaskID = CRSTask.ID
INNER JOIN CRS_BuiltinGroup
ON CRSTaskReceiver.ReceiverID = CRS_BuiltinGroup.ID AND CRSTaskReceiver.ReceiverType = 4
WHERE CRSTask.ParentTask = #TaskID
Also the below part of the function seems to do absolutely nothing. What is it meant to do?
DECLARE #tmpLength INT
SET #tmpLength = 0
SET #tmpLength = LEN(#tmp)
IF #tmpLength > 0
BEGIN
SET #tmp = SUBSTRING(#tmp, 0, #tmpLength)
END