How to Avoid dynamic sql - sql

Can I get some help, I am trying to avoid dynamic sql, the dynamic sql works but its there any other way to build this without dynamic sql, I am trying a lot of stuff but getting errors, your help will be appreciated.
declare #strSQL varchar(8000)
set #strSQL = 'Select
ParentFName, ParentLName, ParentMiddleName,
MailingAddressLine1, MailingAddressLine2, City, State, ZipCode,
PS.SchoolID, PS.SchoolName, FirstName, LastName, MiddleName,
CONVERT(varchar(12), SE.Birthday, 101) AS [Birthday],
SE.GTID, SystemID,Grade, Report_Type, Race, Sex, NON_Funded_Flag,
DATEDIFF(YY,Birthday , getdate()) -
CASE
WHEN(
(MONTH(BirthDay)*100 + DAY(BirthDay)) >
(MONTH(getdate())*100 + DAY(getdate()))
) THEN 1
ELSE 0 END AS Age,
KG, GR01_03, GR04_05, GR06_08_Middle_Grade, GR06_08_middle_school,
GR09_12, EIP_KG, EIP_01_03,EIP_04_05,LEVEL_1,LEVEL_2,LEVEL_3,LEVEL_4,LEVEL_5,GIFTED, REMEDIAL,VOCATIONAL_HS_LAB, SED, --STUDY_HALL,
NON_FUNDED, --POST_SECOND_OPTION,
ESOL_ITINERANT, ESOL_NON_ITINERANT, TOTAL_ESOL_SEGMENTS,
FiscalYear, TOTAL_FTE_SEGMENTS, AnnualTuition,
CONVERT(varchar(12), SE.EnrollmentDate,101) AS [Enrollment Date],
CONVERT(varchar(12), SE.WithdrawalDate,101) AS [Withdrawal Date],
WD.LookupValueDescription as WithdrawalReason,
FREE_REDUCED_LUNCH, PRIMARY_AREA, GNET_FLAG,
EstAwardAmount--, previous_year
From
StudentEnrollment SE
inner join (
select * from openquery([FINANCE], ''select * from scholarship.sp_eligible_students Where Fiscal_Year = ''''' + convert(varchar, #FiscalYear) + ''''' '') ) ES ON
SE.GTID = ES.GTID Inner Join
(select FP.FiscalYear, PrivateSchool.* from PrivateSchool
INNER JOIN FiscalYearPrivateSchool FP ON PrivateSchool.PrivateSchoolID = FP.PrivateSchoolID AND FP.FiscalYear = ' + #FiscalYear + ') PS
ON SE.PrivateSchoolID = PS.PrivateSchoolID AND ES.Fiscal_Year = PS.FiscalYear Left outer Join
vLookUps WD ON SE.WithdrawalreasonId = WD.LookUpID
WHERE SE.isActive = 1 AND PS.isactive = 1
AND (' + #SchoolID + ' = -1 or SchoolID = ' + #SchoolID + ' )
AND (' + #FiscalYear + ' = -1 OR FiscalYear = ' + #FiscalYear + ')
ORDER BY SchoolName, LastName, Firstname, GTID'
--print (#strSQL)
exec (#strSQL)
END

SET NOCOUNT ON
declare #oq varchar(200)
set #og = 'select * from scholarship.sp_eligible_students Where Fiscal_Year ='+ convert(varchar, #FiscalYear)
select * into #a from openquery([FINANCE], #oq)
Select
ParentFName, ParentLName, ParentMiddleName,
MailingAddressLine1, MailingAddressLine2, City, State, ZipCode,
PS.SchoolID, PS.SchoolName, FirstName, LastName, MiddleName,
CONVERT(varchar(12), SE.Birthday, 101) AS [Birthday],
SE.GTID, SystemID,Grade, Report_Type, Race, Sex, NON_Funded_Flag,
DATEDIFF(YY,Birthday , getdate()) -
CASE
WHEN(
(MONTH(BirthDay)*100 + DAY(BirthDay)) >
(MONTH(getdate())*100 + DAY(getdate()))
) THEN 1
ELSE 0 END AS Age,
KG, GR01_03, GR04_05, GR06_08_Middle_Grade, GR06_08_middle_school,
GR09_12, EIP_KG, EIP_01_03,EIP_04_05,LEVEL_1,LEVEL_2,LEVEL_3,LEVEL_4,LEVEL_5,GIFTED, REMEDIAL,VOCATIONAL_HS_LAB, SED,
NON_FUNDED,
ESOL_ITINERANT, ESOL_NON_ITINERANT, TOTAL_ESOL_SEGMENTS,
FiscalYear, TOTAL_FTE_SEGMENTS, AnnualTuition,
CONVERT(varchar(12), SE.EnrollmentDate,101) AS [Enrollment Date],
CONVERT(varchar(12), SE.WithdrawalDate,101) AS [Withdrawal Date],
WD.LookupValueDescription as WithdrawalReason,
FREE_REDUCED_LUNCH, PRIMARY_AREA, GNET_FLAG,
EstAwardAmount
From
StudentEnrollment SE
inner join #a ES ON
SE.GTID = ES.GTID Inner Join
(select FP.FiscalYear, PrivateSchool.* from PrivateSchool
INNER JOIN FiscalYearPrivateSchool FP ON PrivateSchool.PrivateSchoolID = FP.PrivateSchoolID AND FP.FiscalYear = #FiscalYear) PS
ON SE.PrivateSchoolID = PS.PrivateSchoolID AND ES.Fiscal_Year = PS.FiscalYear Left outer Join
vLookUps WD ON SE.WithdrawalreasonId = WD.LookUpID
WHERE SE.isActive = 1 AND PS.isactive = 1
AND (#SchoolID = -1 or SchoolID = #SchoolID )
AND (#FiscalYear = -1 OR FiscalYear = #FiscalYear)
ORDER BY SchoolName, LastName, Firstname, GTID
drop table #a
If and when this fails. Try fixing it.

Related

When make concatenation sql string query , error has occurred because single quote

SET #InventoryQuery = N'SELECT * FROM
(
SELECT Inven.Inventory_ID As ID,Inven.Inventory_ID As Number, Inventory_Date As ActionDate, ''Inventory'' AS [ActionType], IsNull(Sum(Product_Qty),0) Product_Qty, P.Product_Desc_ENG + '' ('' + P.Product_Weight + '')'' Product_Desc_ENG
FROM CRM.Product P
INNER JOIN [crm].[InventoryDetail] InvenDet ON P.Product_ID = InvenDet.Product_ID
INNER JOIN [crm].[Inventory] Inven ON Inven.Inventory_ID = InvenDet.Inventory_ID
WHERE Inven.Customer_Id = ' + CAST(#CustomerID AS VARCHAR(10)) +
' AND ( Inven.Inventory_Date BETWEEN ' + CONVERT(VARCHAR(20), #StartDate, 121) + '
AND ' + CONVERT(VARCHAR(20), #EndDate, 121) + ' ) GROUP BY Inven.Inventory_ID, Inventory_Date,P.Product_Desc_ENG,P.Product_Weight
) y
pivot
(
sum(Product_Qty)
for Product_Desc_ENG in (' + #cols + N')
) p2 '

cast list of strings as int list in sql query / stored procedure

I have this stored procedure:
exec SearchResume #KeywordSearch=N'', #GreaterThanDate='2013-09-22 00:00:00',
#CityIDs=N'0,56,31,271,117,327,3,328,228',
#ProvinceIDs=N'0,1,12,13',
#CountryIDs=N'1',
#IndustryIDs=N'0,2,3,4,38,113,114,115,116,117'
Which doesn't return any results because the ids are in nvarchar but the actual values are integer.
Now, when I test the actual SP with a manual list of int values I'm able to get the results, this is the example:
SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN 'Confidential' ELSE LastName + ',' + FirstName END as 'Name',
a.Description 'ResumeTitle',
CurrentTitle,
ModifiedDate,
CASE ISNULL(b.SalaryRangeID, '0') WHEN '0' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END 'Salary',
h.Description 'Relocate',
i.Description + '-' + j.Description + '-' + k.Description 'Location'
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE (b.CityID IN (0,56,31,125,229,5,219,8,228))
AND (b.StateProvinceID IN (0,1,13))
AND (b.CountryID IN (1))
AND (b.IndustryPreferenceID IN (0,2,3,4,5,6,115,116,117))
I would like to know what can I do to send a list of int values, not a list of nvarchar values since as you can see the query doesn't work properly.
Update
Original SP:
ALTER PROCEDURE [dbo].[SearchResume]
#KeywordSearch nvarchar(500),
#GreaterThanDate datetime,
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
AS
BEGIN
DECLARE #sql as nvarchar(4000)
SET #sql = 'SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CurrentEmployerName,
PersonalDescription,
CareerObjectives,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
e.Description ''EducationLevel'',
f.Description ''CareerLevel'',
g.Description ''JobType'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE ( (ModifiedDate > ''' + CAST(#GreaterThanDate as nvarchar(55)) + ''')
'
IF (LEN(#CityIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.CityID IN (' + #CityIDs + '))'
END
IF (LEN(#ProvinceIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.StateProvinceID IN (' + #ProvinceIDs + '))'
END
IF (LEN(#CountryIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.CountryID IN (' + #CountryIDs + '))'
END
IF (LEN(#IndustryIDs) >0)
BEGIN
SET #sql = #sql + 'AND (b.IndustryPreferenceID IN (' + #IndustryIDs + '))'
END
IF (LEN(#KeywordSearch) > 0)
BEGIN
SET #sql = #sql + ' AND (' + #KeywordSearch + ')'
END
SET #sql = #sql + ') ORDER BY ModifiedDate desc'
--select #sql
exec sp_executesql #sql
END
You can create a Table-Valued Function which takes the nVarChar and creates a new record for each value, where you tell it the delimiter. My example here returns a table with a single Value column, you can then use this as a sub query for your IN Selection :
Create FUNCTION [dbo].[fnSplitVariable]
(
#List nvarchar(2000),
#delimiter nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Variable varchar(15),
Value nvarchar(100)
)
AS
BEGIN
Declare #Count int
set #Count = 1
While (Charindex(#delimiter,#List)>0)
Begin
Insert Into #RtnValue (Value, Variable)
Select
Value = ltrim(rtrim(Substring(#List,1,Charindex(#delimiter,#List)-1))),
Variable = 'V' + convert(varchar,#Count)
Set #List = Substring(#List,Charindex(#delimiter,#List)+len(#delimiter),len(#List))
Set #Count = #Count + 1
End
Insert Into #RtnValue (Value, Variable)
Select Value = ltrim(rtrim(#List)), Variable = 'V' + convert(varchar,#Count)
Return
END
Then in your where statement you could do the following:
WHERE (b.CityID IN (Select Value from fnSplitVariable(#CityIDs, ','))
I have included your original Procedure, and updated it to use the function above:
ALTER PROCEDURE [dbo].[SearchResume]
#KeywordSearch nvarchar(500),
#GreaterThanDate datetime,
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
AS
BEGIN
DECLARE #sql as nvarchar(4000)
SET #sql = N'
DECLARE #KeywordSearch nvarchar(500),
#CityIDs nvarchar(500),
#ProvinceIDs nvarchar(500),
#CountryIDs nvarchar(500),
#IndustryIDs nvarchar(500)
SET #KeywordSearch = '''+#KeywordSearch+'''
SET #CityIDs = '''+#CityIDs+'''
SET #ProvinceIDs = '''+#ProvinceIDs+'''
SET #CountryIDs = '''+#CountryIDs+'''
SET #IndustryIDs = '''+#IndustryIDs+'''
SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CurrentEmployerName,
PersonalDescription,
CareerObjectives,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
e.Description ''EducationLevel'',
f.Description ''CareerLevel'',
g.Description ''JobType'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE ( (ModifiedDate > ''' + CAST(#GreaterThanDate as nvarchar(55)) + ''')
'
IF (LEN(#CityIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.CityID IN (Select Value from fnSplitVariable(#CityIDs,'','') ))'
END
IF (LEN(#ProvinceIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.StateProvinceID IN (Select Value from fnSplitVariable(#ProvinceIDs,'','') ))'
END
IF (LEN(#CountryIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.CountryID IN (Select Value from fnSplitVariable(#CountryIDs,'','') ))'
END
IF (LEN(#IndustryIDs) >0)
BEGIN
SET #sql = #sql + N'AND (b.IndustryPreferenceID IN (Select Value from fnSplitVariable(#IndustryIDs,'','') ))'
END
IF (LEN(#KeywordSearch) > 0)
BEGIN
SET #sql = #sql + N' AND (' + #KeywordSearch + ')'
END
SET #sql = #sql + N') ORDER BY ModifiedDate desc'
--select #sql
exec sp_executesql #sql
END
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL = 'SELECT DISTINCT
UserID,
ResumeID,
CASE a.Confidential WHEN 1 THEN ''Confidential'' ELSE LastName + '','' + FirstName END as ''Name'',
a.Description ''ResumeTitle'',
CurrentTitle,
ModifiedDate,
CASE ISNULL(b.SalaryRangeID, ''0'') WHEN ''0'' THEN CAST(SalarySpecific as nvarchar(8)) ELSE c.Description END ''Salary'',
h.Description ''Relocate'',
i.Description + ''-'' + j.Description + ''-'' + k.Description ''Location''
FROM dbo.Resume a JOIN dbo.Candidate b ON a.CandidateID = b.CandidateID
LEFT OUTER JOIN SalaryRange c ON b.SalaryRangeID = c.SalaryRangeID
JOIN EducationLevel e ON b.EducationLevelID = e.EducationLevelID
JOIN CareerLevel f ON b.CareerLevelID = f.CareerLevelID
JOIN JobType g ON b.JobTypeID = g.JobTypeID
JOIN WillingToRelocate h ON b.WillingToRelocateID = h.WillingToRelocateID
JOIN City i ON b.CityID = i.CityID
JOIN StateProvince j ON j.StateProvinceID = b.StateProvinceID
JOIN Country k ON k.CountryID = b.CountryID
WHERE (b.CityID IN (' + #CityIDs + '))
AND (b.StateProvinceID IN (' + #ProvinceIDs + '))
AND (b.CountryID IN (' + #CountryIDs + '))
AND (b.IndustryPreferenceID IN (' + #IndustryIDs + '))'
EXEC #SQL
You could do a split on the id's that are coming in to the store procedure. So consider this split function:
CREATE FUNCTION [dbo].[Split]
(
#String NVARCHAR(4000),
#Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(#Delimiter,#String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(#Delimiter,#String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(#String,stpos,COALESCE(NULLIF(endpos,0),LEN(#String)+1)-stpos)
FROM Split
)
Then you could write your where statement like this:
WHERE
EXISTS(SELECT NULL FROM dbo.Split(#CityIDs,',') AS city
WHERE city.Data=b.CityID)
AND EXISTS(SELECT NULL FROM dbo.Split(#ProvinceIDs,',') AS Province
WHERE Province.Data=b.StateProvinceID)
AND EXISTS(SELECT NULL FROM dbo.Split(#CountryIDs,',') AS Country
WHERE Country.Data=b.CountryID)
AND EXISTS(SELECT NULL FROM dbo.Split(#IndustryIDs,',') AS Industry
WHERE Industry.Data=b.IndustryPreferenceID)

Need to speed up this SQL query

My query has this structure:
SELECT DISTINCT (CO.CateringOrderId),
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS "CustomerName",
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
(SELECT Sum (Amount)
FROM Catering_Order_Payment_Trans
WHERE CateringOrderId = CO.CateringOrderId) AS AmountReceived
FROM Catering_Orders CO,
Master_Customer MC,
Customer_Address_Trans CAT,
Catering_Order_Employee_Trans COET
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND (CO.CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%')
AND (CO.EventDate >= CONVERT (DATETIME, #p_FromDate) OR #p_FromDate = '')
AND (CO.EventDate <= CONVERT (DATETIME, #p_ToDate) OR #p_ToDate = '')
AND (CO.IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND (COET.EmployeeId = #p_CatererId OR #p_CatererId = -1)
AND MC.CustomerId = CO.CustomerId
AND MC.PersonalAddressId = CAT.CustomerAddressId
AND (COET.CateringOrderId = CO.CateringOrderId
OR CO.CateringOrderId NOT IN
(SELECT CateringOrderId FROM Catering_Order_Employee_Trans))
AND (CAT.Mobile like '%' + #p_ContactNumber + '%' )
AND (CO.IsActive is null or CO.IsActive=1)
ORDER BY CO.CateringOrderId DESC
I think the SUM sub-query is slowing it. Please suggest me on how to speed it up.
Currently its execution time is around 7 - 10 seconds.
Try something like this -
SELECT DISTINCT
CO.CateringOrderId,
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS CustomerName,
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
AmountReceived = (
SELECT SUM(t.Amount)
FROM dbo.Catering_Order_Payment_Trans t
WHERE t.CateringOrderId = CO.CateringOrderId
)
FROM (
SELECT *
FROM dbo.Catering_Orders
WHERE ISNULL(IsActive, 1) = 1
AND (IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%'
AND EventDate BETWEEN
CONVERT(DATETIME, ISNULL(NULLIF(#p_FromDate, ''), '18000101'))
AND
CONVERT(DATETIME, ISNULL(NULLIF(#p_ToDate, ''), '30000101'))
) CO
JOIN dbo.Master_Customer MC ON MC.CustomerId = CO.CustomerId
JOIN dbo.Customer_Address_Trans CAT ON MC.PersonalAddressId = CAT.CustomerAddressId
LEFT JOIN (
SELECT *
FROM dbo.Catering_Order_Employee_Trans
WHERE EmployeeId = #p_CatererId
OR #p_CatererId = -1
) COET ON COET.CateringOrderId = CO.CateringOrderId
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND CAT.Mobile LIKE '%' + #p_ContactNumber + '%'
The main problems in
AND (COET.CateringOrderId = CO.CateringOrderId
OR CO.CateringOrderId NOT IN
(SELECT CateringOrderId FROM Catering_Order_Employee_Trans))
and
(SELECT Sum (Amount)
FROM Catering_Order_Payment_Trans
WHERE CateringOrderId = CO.CateringOrderId) AS AmountReceived
Try:
SELECT CO.CateringOrderId,
CO.CateringOrderNumber,
MC.FirstName + ' ' + MC.LastName AS "CustomerName",
CO.EventDate AS EventDate,
CO.IsCompleted,
CO.IsVerified,
MC.EmailId,
CAT.OfficePhone,
CAT.Mobile,
CAT.Fax,
CO.TotalInvoiceAmount,
CO.BarterCharityId,
COPT.AmountReceived
FROM Catering_Orders CO
JOIN Master_Customer MC ON MC.CustomerId = CO.CustomerId
JOIN Customer_Address_Trans CAT ON MC.PersonalAddressId = CAT.CustomerAddressId
LEFT JOIN (SELECT CateringOrderId, Sum(Amount) AS AmountReceived
FROM Catering_Order_Payment_Trans
GROUP BY CateringOrderId) COPT
ON COPT.CateringOrderId = CO.CateringOrderId
WHERE MC.CompanyId = #p_CompanyId
AND (MC.CustomerId = #p_CustomerId OR #p_CustomerId = -1)
AND (CO.CateringOrderNumber LIKE '%' + #p_CateringOrderNumber + '%')
AND (CO.EventDate >= CONVERT (DATETIME, #p_FromDate) OR #p_FromDate = '')
AND (CO.EventDate <= CONVERT (DATETIME, #p_ToDate) OR #p_ToDate = '')
AND (CO.IsCompleted = #p_IsCompleted OR #p_IsCompleted = -1)
AND EXISTS
(SELECT NULL
FROM Catering_Order_Employee_Trans COET
WHERE COET.CateringOrderId = CO.CateringOrderId AND
(COET.EmployeeId = #p_CatererId OR #p_CatererId = -1) )
AND (CAT.Mobile like '%' + #p_ContactNumber + '%' )
AND (CO.IsActive is null or CO.IsActive=1)
ORDER BY CO.CateringOrderId DESC
To optimize your query you should edit the OR condition inserted inside AND conditions which really slow down your query
AND ( CO.EventDate <= CONVERT (DATETIME, #p_ToDate)
OR #p_ToDate = '')
should become something like
AND ( CO.EventDate <= CASE WHEN #p_ToDate = '' THEN
GETDATE()
ELSE
CONVERT (DATETIME,#p_ToDate)
END)
Also try to remove one by one the innested select both in select and in where to see which one most slows down the query

Stored Procedure with dynamic SQL returns wrong data

For the fiscal year parameter I have 2010, 2011 and 2012 as an option but no matter what year I select the "submitted On" column still shows 2011 dates. I want for example if I select 2010, only data submitted on 2010 should show and likewise for all the years. Any help?
set #sqlstr = '
Select
[SchoolName] As [School Name],
Status= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID THEN ''Submitted''
ELSE ''Not Submitted''END,
[Submitted By]= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID
THEN [FirstName] + '' '' + [LastName] ELSE NULL END,
[Submitted On]= CASE WHEN PS.PrivateSchoolID = Ed.PrivateSchoolID
THEN Convert( Varchar(10), Ed.CreatedDate, 101 ) ELSE NULL END
From EnrollmentDateSchool Ed Right Outer Join
(select FP.FiscalYear, PrivateSchool.* from PrivateSchool
INNER JOIN FiscalYearPrivateSchool FP
ON PrivateSchool.PrivateSchoolID = FP.PrivateSchoolID) PS
ON Ed.PrivateSchoolID = PS.PrivateSchoolID Left Outer Join
Finance.dbo.Person P ON Ed.CreatedBy = P.PersonID
Where (FiscalYear = '+convert(varchar, #FiscalYear)+') AND (PS.IsActive = 1)'
IF (#SchoolID != -1)
set #sqlstr = #sqlstr + ' AND SchoolID ='+ convert(varchar, #SchoolID)
IF (#Status = -1)
set #sqlstr = #sqlstr + ' AND (PS.PrivateSchoolID = PS.PrivateSchoolID' + ')'
ELSE IF (#Status = 1)
set #sqlstr = #sqlstr + ' AND (PS.PrivateSchoolID = Ed.PrivateSchoolID' + ')'
ELSE
set #sqlstr = #sqlstr + 'AND (Ed.PrivateSchoolID is null' + ')'
SET #sqlstr = #sqlstr + 'ORDER BY SchoolName'
EXEC(#sqlstr)
END
There is no need at all for dynamic sql here.
SELECT
...
FROM ...
WHERE FiscalYear=#FiscalYear AND PS.IsActive=1
AND (#SchoolID = -1 OR SchoolID=#SchoolID)
AND ( (#Status = -1)
OR (#Status=1 AND PS.PrivateSchoolID = Ed.PrivateSchoolID)
OR (Ed.PrivateSchoolID is null) )
ORDER BY SchoolName

Alternative TSQL

This query works well as you can see I have to put split between between #SearchCriteria and the rest of the query due to it's varchar. If I forced, the syntax works well BUT it return nothing when you query possible because extra '
Can you help?
ALTER PROCEDURE [dbo].[sp_rte_GetRateList]
(
#TenantID INT,
#CustomerID BIGINT = -1,
#SearchCriteria VARCHAR(64) = '',
#SortBy VARCHAR(16) = '',
#SortType VARCHAR(16) = '',
#Debug BIT = 0
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(4000),
#paramlist nvarchar(4000)
IF (#SearchCriteria = '')
BEGIN
SELECT #sql = 'SELECT r.TenantID, r.RateID, r.RateGUID, r.RateCode, r.RateName, r.RateDescription, r.ValidityUTCDate, r.CreatedUTCTimeStamp,
r.CreatedIP, r.CreatedBy, r.LastModifiedUTCTimeStamp, r.LastModifiedIP, r.LastModifiedBy, r.IsActive,
c.CustomerID, c.CustomerName, rt.RateTypeID, rt.RateTypeName, s.SupplierID, s.SupplierName, r.FixedLineAmount, r.MobileAmount, r.DataAmount, r.OtherAmount,
(r.FixedLineAmount + r.MobileAmount + r.DataAmount + r.OtherAmount) AS TotalAmount,
r.CreatedUTCTimeSTamp,
STUFF((SELECT '', '' + ct.CustomerTypeName
FROM glb_CustomerTypes ct JOIN glb_CustomerCustomerTypes cct ON cct.CustomerTypeID = ct.CustomerTypeID
WHERE cct.CustomerID = C.CustomerID
GROUP BY ct.CustomerTypeName FOR XML PATH('''')), 1, 2, '''') AS CustomerTypeName
FROM dbo.rte_Rates r
INNER JOIN dbo.rte_RateTypes rt ON r.RateTypeID = rt.RateTypeID
INNER JOIN dbo.glb_Suppliers s ON r.SupplierID = s.SupplierID
INNER JOIN dbo.glb_Customers c ON r.CustomerID = c.CustomerID
INNER JOIN dbo.glb_Addresses a ON c.CustomerID = a.CustomerID
INNER JOIN dbo.glb_AddressTypes at ON a.AddressTypeID = at.AddressTypeID
WHERE at.AddressTypeCode = ''GLB_ADT_PHYSCLDDRS'' AND
r.TenantID = #xTenantID AND
rt.TenantID = #xTenantID AND
s.TenantID = #xTenantID AND
r.IsActive = 1 AND
rt.IsActive = 1 AND
c.IsActive = 1 AND
c.CustomerID = #xCustomerID '
END
ELSE
BEGIN
SELECT #sql = 'SELECT r.TenantID, r.RateID, r.RateGUID, r.RateCode, r.RateName, r.RateDescription, r.ValidityUTCDate, r.CreatedUTCTimeStamp,
r.CreatedIP, r.CreatedBy, r.LastModifiedUTCTimeStamp, r.LastModifiedIP, r.LastModifiedBy, r.IsActive,
c.CustomerID, c.CustomerName, rt.RateTypeID, rt.RateTypeName, s.SupplierID, s.SupplierName, r.FixedLineAmount, r.MobileAmount, r.DataAmount, r.OtherAmount,
(r.FixedLineAmount + r.MobileAmount + r.DataAmount + r.OtherAmount) AS TotalAmount,
r.CreatedUTCTimeSTamp,
STUFF((SELECT '', '' + ct.CustomerTypeName
FROM glb_CustomerTypes ct JOIN glb_CustomerCustomerTypes cct ON cct.CustomerTypeID = ct.CustomerTypeID
WHERE cct.CustomerID = C.CustomerID
GROUP BY ct.CustomerTypeName FOR XML PATH('''')), 1, 2, '''') AS CustomerTypeName
FROM dbo.rte_Rates r
INNER JOIN dbo.rte_RateTypes rt ON r.RateTypeID = rt.RateTypeID
INNER JOIN dbo.glb_Suppliers s ON r.SupplierID = s.SupplierID
INNER JOIN dbo.glb_Customers c ON r.CustomerID = c.CustomerID
INNER JOIN dbo.glb_Addresses a ON c.CustomerID = a.CustomerID
INNER JOIN dbo.glb_AddressTypes at ON a.AddressTypeID = at.AddressTypeID
WHERE at.AddressTypeCode = ''GLB_ADT_PHYSCLDDRS'' AND
r.TenantID = #xTenantID AND
rt.TenantID = #xTenantID AND
s.TenantID = #xTenantID AND
r.IsActive = 1 AND
rt.IsActive = 1 AND
c.IsActive = 1 AND
c.CustomerID = #xCustomerID AND
(r.RateCode LIKE ''%' + #SearchCriteria + '%'' OR
r.RateName LIKE ''%' + #SearchCriteria + '%'' OR
rt.RateTypeName LIKE ''%' + #SearchCriteria + '%'' OR
r.RateDescription LIKE ''%' + #SearchCriteria + '%'' OR
s.SupplierCode LIKE ''%' + #SearchCriteria + '%'' OR
s.SupplierName LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerCode LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerName LIKE ''%' + #SearchCriteria + '%'' OR
c.CustomerDescription LIKE ''%' + #SearchCriteria + '%'' ) '
END
SELECT #sql = #sql + 'ORDER BY ' + #SortBy + ' ' + #SortType
IF (#Debug = 1) PRINT #sql
SELECT #paramlist = '#xTenantID INT, #xCustomerID BIGINT'
EXEC sp_executesql #sql, #paramlist, #TenantID, #CustomerID
END
You could just double any quotes in #SearchCriteria, but that won't protect you against all forms of SQL injection - which you can only do by getting away from dynamic SQL.
I'm not 100% sure you need dynamic SQL for this particular problem in the first place.
I think you'd be better off initializing the #SearchCriteria to NULL:
ALTER PROCEDURE [dbo].[sp_rte_GetRateList]
( ...
#SearchCriteria VARCHAR(64), --inits as NULL
....
)
IF #SearchCriteria IS NOT NULL
BEGIN
SET #SearchCriteria = REPLACE(#SearchCriteria, '''', '''''')
...
END
ELSE
...
I get why you setup the dynamic SQL the way you did - I noticed the paramlist doesn't have #SearchCriteria in it, so you don't have to define the param instances of #SearchCriteria. Might consider full text searches when you have 2+ columns from the same table - likely faster, and less complicated SQL.