Where Clause with Conditions in SQL Server - sql-server

I have a SQL stored procedure for a search page on a website where a user can search records by, and between, two date fields: initiatedDateStart and initiatedDateEnd. The logic for the SQL query should be as follows:
If the startDate has a value, but the endDate is empty, or equal to
the startDate, return records that were created ON the startDate.
If the startDate has a value, and the endDate value is greater than
the startDate, return records that were created BETWEEN the two
dates.
Since I'm not a SQL expert, my stored procedure is not very elegant or clever, but it does return the records I expect it to, except for the date fields. I have researched for this, but the syntax and logic is stumping me. Here is a snippet of my stored procedure. If a value is entered in the initStartDate texbox, but the initEndDate is empty, this returns ALL the records created AFTER the start date. I appreciate any and all help on this.
DECLARE #initStartDate datetime = NULL
DECLARE #initEndDate datetime = NULL
SELECT DISTINCT
d.[DCRId],
d.[Title],
d.[FiscalYear]
FROM [dbo].[tblDCR] d
LEFT OUTER JOIN [dbo].[tblWorkflow] orig ON (d.[DCRId] = orig.[DCRId] AND orig.StepName = 'Draft')
WHERE 1 = 1
AND (orig.BadgeDate >= #initStartDate OR #initStartDate IS NULL)
AND (orig.BadgeDate <= #initEndDate OR #initEndDate IS NULL)

The best way I can think of to handle this would be to use dynamic sql
DECLARE #initStartDate datetime = NULL;
DECLARE #initEndDate datetime = NULL;
Declare #Sql NVARCHAR(MAX);
SET #Sql = N'SELECT DISTINCT
d.[DCRId],
d.[Title],
d.[FiscalYear]
FROM [dbo].[tblDCR] d
LEFT OUTER JOIN [dbo].[tblWorkflow] orig
ON (d.[DCRId] = orig.[DCRId] AND orig.StepName = ''Draft'')
WHERE 1 = 1 '
+ CASE WHEN #initStartDate IS NOT NULL THEN
N' AND orig.BadgeDate >= #initStartDate ' ELSE N'' END
+ CASE WHEN #initEndDate IS NOT NULL THEN
N' AND orig.BadgeDate <= #initEndDate ' ELSE N'' END
Exec sp_executesql #Sql
,N'#initStartDate datetime, #initEndDate datetime'
,#initStartDate
,#initEndDate

I think a solution to your problem would be to assign the current date to the end parameter when it is left NULL. By doing this, a user can enter no parameters and get the current date values, enter just the start date and get data on the start date, or enter the end date and get data between the current date and the end date. As a final catch, you can tell the procedure to return only today's data if for some reason a user puts a higher start date than end date.
CREATE PROCEDURE test_proc
#initStartDate date = null,
#initEndDate date = null
AS
IF #initStartDate IS NULL AND #initEndDate IS NULL
BEGIN
SET #initStartDate = (SELECT GETDATE())
SET #initEndDate = #initStartDate
END
ELSE IF #initStartDate IS NULL AND #initEndDate IS NOT NULL
BEGIN
SET #initStartDate = #initEndDate
END
ELSE IF #initEndDate IS NULL AND #initStartDate IS NOT NULL
BEGIN
SET #initEndDate = #initStartDate
END
IF #initStartDate > #initEndDate
BEGIN
SET #initStartDate = (SELECT GETDATE())
SET #initEndDate = #initStartDate
END
SELECT DISTINCT
d.[DCRId],
d.[Title],
d.[FiscalYear]
FROM [dbo].[tblDCR] d
LEFT OUTER JOIN [dbo].[tblWorkflow] orig ON (d.[DCRId] = orig.[DCRId] AND orig.StepName = 'Draft')
WHERE orig.BadgeDate BETWEEN #initStartDate AND #initEndDate
GO
My modified SQL
DECLARE #initStartDate date = '10/21/15'
DECLARE #initEndDate date = NULL
IF #initStartDate IS NULL AND #initEndDate IS NOT NULL
BEGIN
SET #initStartDate = #initEndDate
END
ELSE IF #initEndDate IS NULL AND #initStartDate IS NOT NULL
BEGIN
SET #initEndDate = #initStartDate
END
SELECT DISTINCT
d.[DCRId],
d.[Title],
d.[FiscalYear]
FROM [dbo].[tblDCR] d
LEFT OUTER JOIN [dbo].[tblWorkflow] orig ON (d.[DCRId] = orig.[DCRId] AND orig.StepName = 'Draft')
WHERE 1 = 1
AND (orig.BadgeDate BETWEEN #initStartDate AND #initEndDate) OR (#initStartDate IS NULL OR #initEndDate IS NULL)

but what if the #initStartDate does not have a value ?
assuming you want it to go all the way back if no startDate criteria, then, pass the date criteria as Nullable parameters, as you are:
then, (assuming the database field is date only with no time), use the following where clause:
where orig.BadgeDate Between
Coalesce(#initStartDate, orig.BadgeDate) and
Coalesce(#initEndDate, #initStartDate, orig.BadgeDate)

Related

Multiple Condition in Where Clause for the same column

How do I write a MS SQL statement for the below condition?
I have a form that allows users to enter dates (fromDate & toDate) and ID (fromID & toID) in range. The fields can be blank for all OR enter only either from or to field OR enter both from and to fields. Selection is based on the entered values to select. Below are the conditions checking in where clause for value entered.
no value entered => skip all conditions
value entered in fromDate only => Date = frDate
value entered in toDate only => Date <= toDate
value entered in both fromDate & toDate => Date between fromDate and toDate
Condition is applied to ID field as well.
Any advice is highly appreciated.
Thanks in advance.
You can solve your problem using dynamic query. Your question is not fully clear. Here i'm giving you a solution which will help you to solve your problem. Try this:
1. Create Dynamic query in a Store Procedure
CREATE PROCEDURE sp_YourSPName
/* Input Parameters */
#FromDate DATETIME ,
#ToDate DATETIME
AS
SET NOCOUNT ON
/* Variable Declaration */
DECLARE #SQLQuery AS NVARCHAR(4000)
DECLARE #ParamDefinition AS NVARCHAR(2000)
/* Build the Transact-SQL String with the input parameters */
SET #SQLQuery = 'Select * From YourTableName where (1=1) '
/* check for the condition and build the WHERE clause accordingly */
IF (#FromDate IS NOT NULL)
AND (#ToDate IS NOT NULL)
SET #SQLQuery = #SQLQuery +
' And (YourDate BETWEEN #FromDate AND #ToDate)'
IF (#FromDate IS NULL)
AND (#ToDate IS NOT NULL)
SET #SQLQuery = #SQLQuery + ' And (YourDate <= #ToDate)'
IF (#FromDate IS NOT NULL)
AND (#ToDate IS NULL)
SET #SQLQuery = #SQLQuery + ' And (YourDate = #FromDate)'
/* Specify Parameter Format for all input parameters included
in the stmt */
SET #ParamDefinition = '#StartDate DateTime,
#EndDate DateTime'
/* Execute the Transact-SQL String with all parameter value's Using sp_executesql Command */
EXECUTE sp_Executesql #SQLQuery,
#ParamDefinition,
#FromDate,
#ToDate
IF ##ERROR <> 0
GOTO ErrorHandler
SET NOCOUNT OFF
RETURN(0)
ErrorHandler :
RETURN(##ERROR)
GO
2. Execute Store Procedure:
EXEC sp_YourSPName '01 Oct 2018', '01 Oct 2018'
For more info see this link
You can use IS NULL to check param has value
SELECT * FROM Table
WHERE (#FromDate IS NULL OR Date > #FromDate) AND (#ToDate IS NULL OR Date < #ToDate)
Same type of query will be used for Id
Below is the EXAMPLE and not the exact query you can try to put it in your way using CASE statements
SELECT values
FROM Table
WHERE CASE
WHEN fromDate = null & todate = null THEN
WHEN fromDate != null & toDate != null THEN Date between fromDate and toDate
WHEN fromDate != null THEN Date = frDate
WHEN toDate != null THEN Date = toDate

SQL Server if statement does not execute as expected

I am trying to use the following stored procedure but there are some instances WHERE only the incremental happens AND the code does not run. What I need is that, when the program enters the IF statement, either it should run both the statements or None.
Stored procedure goes like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[spflpunch]
AS
BEGIN
DECLARE #id NUMERIC(18,0)
DECLARE #studname NVARCHAR(50)
DECLARE #punchtime DATETIME
DECLARE #samedaycount NUMERIC(2)
SELECT #id = (MAX(lastid)) FROM [smartswype].[dbo].[read]
PRINT #id
SELECT #studname = studname
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id =#id
PRINT #studname
SELECT #punchtime = punchtime
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE id = #id
PRINT #punchtime
--SELECT #punchvarchar = CONVERT(VARCHAR(10),#punchtime, 103) + ' ' + CONVERT(VARCHAR(5), #punchtime, 14)
IF #id = (SELECT MAX(id) FROM [SSWYPE_WEBDB].[dbo].[attdview])
BEGIN
SELECT #samedaycount = COUNT(*)
FROM [SSWYPE_WEBDB].[dbo].[attdview]
WHERE (studname = #studname
AND CONVERT(DATE, punchtime) = CONVERT(DATE, #punchtime)) -- If firstpunch = 1 then it is the first punch
PRINT #samedaycount
IF #samedaycount =1
BEGIN
INSERT INTO [smartswype].[dbo].[firstlastpunch] ([studname], [DATE], [punch1], [punch2])
VALUES(#studname, CONVERT(DATE, #punchtime), #punchtime, NULL);
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
ELSE IF (#samedaycount > 1)
BEGIN
UPDATE [smartswype].[dbo].[firstlastpunch]
SET punch2 = #punchtime
WHERE (studname = #studname AND DATE = CONVERT(DATE, #punchtime));
UPDATE [smartswype].[dbo].[read]
SET lastid = #id + 1;
END
END
END
If you want to ensure that both or none of the statements run, you should wrap the contents of the if statement in a transaction.
By wrapping it in a transaction, you can ensure that if one statement fails, that the other statement will not run.
Here is a link to the docs on transactions in SQL Server
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/commit-transaction-transact-sql

Stored procedure Date From and Date To

I am trying to create a stored procedure for filtering orders. Basically the users have the option of filtering the order by date from and date to. So they can do search via date from, date to or use both if it makes sense?
Anyhow here is my SQL Server stored procedure so far
ALTER PROCEDURE [dbo].[CN_GetOrderItemByCustID]
#CustomerID int,
#OrderItemWRClass varchar(max) = NULL,
#OrderItemSKUName varchar(50) = NULL,
#OrderItemDateFrom Datetime,
#OrderItemDateTo Datetime
AS
BEGIN
SET NOCOUNT ON;
IF DATEDIFF(d, #OrderItemDateFrom, '01/01/1970') = 0
SET #OrderItemDateFrom = null
IF DATEDIFF(d, #OrderItemDateTo, '01/01/1970') = 0
SET #OrderItemDateTo = null
-- Insert statements for procedure here
SELECT
COM_OrderItem.OrderItemID, COM_Order.OrderID,
COM_Order.OrderDate, COM_OrderItem.OrderItemUnitCount,
COM_OrderItem.OrderItemStatus, COM_OrderItem.OrderItemSKUNAME,
COM_OrderItem.OrderItemSKUID
FROM
COM_OrderItem
INNER JOIN
COM_Order ON COM_Order.OrderID = COM_OrderItem.OrderItemOrderID
WHERE
COM_Order.OrderCustomerID = #CustomerID
OR COM_OrderItem.OrderItemWRClass LIKE #OrderItemWRClass + '%'
OR COM_OrderItem.OrderItemSKUName LIKE #OrderItemSKUName + '%'
OR CONVERT(VARCHAR, COM_Order.OrderDate, 120) LIKE #OrderItemDateFrom + '%'
ORDER BY
COM_Order.OrderDate DESC
However I am not sure on how to put the date from (OrderItemDateFrom) and date to (OrderItemDateTo) in the final SQL statement?
Should I be using OR CONVERT(VARCHAR, COM_Order.OrderDate, 120) LIKE #OrderItemDateFrom + '%' -- which gives me an error
Conversion failed when converting date and/or time from character string.
I know in a normal SQL query I would use Between OrderItemDateFrom and OrderItemDateTo
Thanks
Use this logic
ALTER PROCEDURE [dbo].[CN_GetOrderItemByCustID]
-- Add the parameters for the stored procedure here
#CustomerID int,
#OrderItemWRClass varchar(max) = NULL,
#OrderItemSKUName varchar(50) = NULL,
#OrderItemDateFrom Datetime,
#OrderItemDateTo Datetime
AS
BEGIN
SET NOCOUNT ON;
IF DATEDIFF(d,#OrderItemDateFrom,'01/01/1970')=0 SET #OrderItemDateFrom = '01/01/1970';
IF DATEDIFF(d,#OrderItemDateTo,'01/01/1970')=0 SET #OrderItemDateTo = '31/12/2199';
-- Insert statements for procedure here
SELECT COM_OrderItem.OrderItemID, COM_Order.OrderID, COM_Order.OrderDate, COM_OrderItem.OrderItemUnitCount, COM_OrderItem.OrderItemStatus, COM_OrderItem.OrderItemSKUNAME,
COM_OrderItem.OrderItemSKUID
FROM COM_OrderItem
INNER JOIN COM_Order ON COM_Order.OrderID = COM_OrderItem.OrderItemOrderID
WHERE COM_Order.OrderCustomerID = #CustomerID OR COM_OrderItem.OrderItemWRClass LIKE #OrderItemWRClass + '%' OR COM_OrderItem.OrderItemSKUName LIKE #OrderItemSKUName + '%'
OR (COM_OrderDate>=#OrderItemDateFrom && COM_OrderDate<=#OrderItemDateTo )
ORDER BY COM_Order.OrderDate DESC
Try it . It should work.
Your logic can be simplified a little by allowing NULL values for #OrderItemDateFrom and #OrderItemDateTo. Also, if filters values and column values are all DATETIMEs, you should try to compare directly to allow indexes usages (if any applied on the DATETIME column):
ALTER PROCEDURE [dbo].[CN_GetOrderItemByCustID]
#CustomerID int,
#OrderItemWRClass varchar(max) = NULL,
#OrderItemSKUName varchar(50) = NULL,
#OrderItemDateFrom Datetime = NULL, -- TODO: change caller to not provide parameter, or leave it to null
#OrderItemDateTo Datetime = NULL -- TODO: change caller to not provide parameter, or leave it to null
AS
BEGIN
SET NOCOUNT ON;
-- when working with dates try to use an unambiguous format like 'YYYY-MM-DD'
SET #OrderItemDateFrom = ISNULL(#OrderItemDateFrom, '1970-01-01')
-- assign a very large date to act like not provided
-- going one day after to catch DATETIMEs with provided time
SET #OrderItemDateTo = DATEADD(day, 1, ISNULL(#OrderItemDateTo, '3000-01-01'))
-- Insert statements for procedure here
SELECT
COM_OrderItem.OrderItemID, COM_Order.OrderID,
COM_Order.OrderDate, COM_OrderItem.OrderItemUnitCount,
COM_OrderItem.OrderItemStatus, COM_OrderItem.OrderItemSKUNAME,
COM_OrderItem.OrderItemSKUID
FROM COM_OrderItem
INNER JOIN COM_Order ON COM_Order.OrderID = COM_OrderItem.OrderItemOrderID
WHERE COM_Order.OrderCustomerID = #CustomerID
OR COM_OrderItem.OrderItemWRClass LIKE #OrderItemWRClass + '%'
OR COM_OrderItem.OrderItemSKUName LIKE #OrderItemSKUName + '%'
-- between can be used
OR (COM_OrderDate BETWEEN #OrderItemDateFrom AND #OrderItemDateTo)
ORDER BY
COM_Order.OrderDate DESC
END
Another option is to use dynamic SQL and construct it based on parameters values (i.e. insert WHERE condition if filter value is provided). This is particularly useful when filters numbers is relatively low compared to the total number of filters, as ORs are not performance friendly.
NOTE: shouldn't your filters apply in conjuction (i.e. use AND instead of OR)? It would make sense to allow the user to filter by several value in the same time.
ALTER PROCEDURE [dbo].[CN_GetOrderItemByCustID]
#CustomerID int,
#OrderItemWRClass varchar(max) = NULL,
#OrderItemSKUName varchar(50) = NULL,
#OrderItemDateFrom Datetime,
#OrderItemDateTo Datetime
AS
BEGIN
SET NOCOUNT ON;
IF DATEDIFF(d, #OrderItemDateFrom, '01/01/1970') = 0
SET #OrderItemDateFrom = null
IF DATEDIFF(d, #OrderItemDateTo, '01/01/1970') = 0
SET #OrderItemDateTo = null
-- Insert statements for procedure here
SELECT
COM_OrderItem.OrderItemID, COM_Order.OrderID,
COM_Order.OrderDate, COM_OrderItem.OrderItemUnitCount,
COM_OrderItem.OrderItemStatus, COM_OrderItem.OrderItemSKUNAME,
COM_OrderItem.OrderItemSKUID
FROM
COM_OrderItem
INNER JOIN
COM_Order ON COM_Order.OrderID = COM_OrderItem.OrderItemOrderID
WHERE
COM_Order.OrderCustomerID = #CustomerID
OR COM_OrderItem.OrderItemWRClass LIKE #OrderItemWRClass + '%'
OR COM_OrderItem.OrderItemSKUName LIKE #OrderItemSKUName + '%'
OR (#OrderItemDateFrom IS NULL OR COM_Order.OrderDate >=#OrderItemDateFrom)
OR (#OrderItemDateTo IS NULL OR COM_Order.OrderDate <=#OrderItemDateTo)
ORDER BY
COM_Order.OrderDate DESC
You should Try this.
OR (#OrderItemDateFrom IS NULL OR COM_Order.OrderDate >=#OrderItemDateFrom)
OR (#OrderItemDateTo IS NULL OR COM_Order.OrderDate <=#OrderItemDateTo)
Just Edit and try this condition..

Why does ad-hoc SQL run faster than executing the same code in a stored procedure?

I have a stored procedure that processes phones and addresses in a batch in SQL server 2005
If I execute the stored procedure in takes 2 hours. But if I run the same code and the same batch ad hoc it takes 2 seconds.
I have try the following steps to make it faster but they have not worked:
Re indexing the entire database
SET ANSI_NULLS ON;
DBCC FreeProcCache
DBCC DROPCLEANBUFFERS
Here is the basic code
USE [MyDB]
GO
/****** Object: StoredProcedure [myschema].[ProccesBatch] Script Date: 06/30/2011 10:37:33 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [myschema].[ProccesBatch]
-- Add the parameters for the stored procedure here
(#BatchId int)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SET ANSI_NULLS ON;
-- AD Hoc TESTING ONLY. This gets uncommented when running ad hoc.
-- DECLARE #BatchId Int
-- SET #BatchId = 59
DECLARE #MyList AS VARCHAR (500)
DECLARE #MySICList AS VARCHAR (500)
DECLARE #MyType AS CHAR (1)
DECLARE #MyProvider AS VARCHAR (500)
DECLARE #MyState AS VARCHAR (2)
DECLARE #MyCityList AS VARCHAR (500)
DECLARE #MyZipList AS VARCHAR (500)
DECLARE #MyStyle AS VARCHAR (1)
DECLARE #MySource AS VARCHAR (150)
DECLARE #MyStartDate AS DATETIME
DECLARE #MyEndDate AS DATETIME
DECLARE #MyCampaign AS BIT
DECLARE #CheckExist AS INT
SET #CheckExist = 0
--
-- 1. Check if Campaign Exist.
--
SELECT
#CheckExist = Id
FROM myschema.Destination
WHERE Id = #BatchId
IF #CheckExist > 0
BEGIN
RAISERROR('Creation has already been processed', 16, 1)
RETURN
END
--
-- 2. Get Header and parameters for controlling process.
--
SELECT
#MyList = ISNULL(LeadBatchHeaderList,''),
#MySICList = ISNULL(SICCodeList,''),
#MyType = ISNULL(MyType,''),
#MyProvider = ISNULL(LDCList,''),
#MyState = ISNULL([State],''),
#MyCityList = ISNULL(CityList,''),
#MyZipList = ISNULL(ZipCodeList,''),
#MyStyle = ISNULL(Commodities,''),
#MySource = ISNULL(LeadSource,''),
#MyStartDate = ISNULL(HeaderCreationStart,''),
#MyEndDate = ISNULL(HeaderCreationEnd,''),
#MyCampaign = ISNULL(AllCampaign ,'')
FROM myschema.Header
WHERE ID = #BatchId
IF ##ROWCOUNT < 1
BEGIN
RAISERROR('header id was not found', 16, 1)
RETURN
END
-- Place Commas for charindex
IF #MyList > ''
SET #MyList = ',' + #MyList + ','
IF #MySICList > ''
SET #MySICList = ',' + #MySICList + ','
IF #MyProvider > ''
SET #MyProvider = ',' + #MyProvider + ','
IF #MyCityList > ''
SET #MyCityList = ',' + #MyCityList + ','
IF #MyZipList > ''
SET #MyZipList = ',' + #MyZipList + ','
--
-- 3. Add qualifying leads.
--
INSERT INTO myschema.Destination
(Id, LeadBatchDetailId, CustomerIdOne, CustomerIdTwo, MyProviderOne, MyProviderTwo, SicCode, SicDesc, SicCode2, SicDesc2,
MyType, Company, CompanyURL, Title, Salutation, Suffix, FullName, FirstName, MiddleInitial,
LastName, Email, MyPhone, Work, Cell, Home, Fax, Ext, Address1, Address2, City, [State],
Zip5, Zip4, County, TSR, EmployeeSize, Revenue, MyProviderOne, MyProviderTwo, CustomerUsageOne, CustomerUsageTwo, MyExpenses, Remarks, Decline,
WhyLeft, PCC, RCC, PCC, SCC)
SELECT
#BatchId, d.ID, d.CustomerIdOne, d.CustomerIdTwo, d.MyProviderOne, d.MyProviderTwo, d.SicCode, d.SicDesc, d.SicCode2, d.SicDesc2,
d.MyType, d.Company, d.CompanyURL, d.Title, d.Salutation, d.Suffix, d.FullName, d.FirstName, d.MiddleInitial,
d.LastName, d.Email, d.MyPhone, d.Work, d.Cell, d.Home, d.Fax, d.Ext, d.Address1, d.Address2, d.City, d.[State],
d.Zip5, d.Zip4, d.County, d.TSR, d.EmployeeSize, d.Revenue, d.MyProviderOne, d.MyProviderTwo,d.CustomerUsageOne, d.CustomerUsageTwo, d.MyExpenses, d.Remarks, d.Decline,
d.WhyLeft, d.PCC, d.RCC, d.PCC, d.SCC
FROM myschema.Source as d
JOIN myschema.Summary as h ON d.MyId = h.ID
JOIN myschema.source AS s ON h.Id = s.ID
WHERE
-- MyId.
(#MyList = '' OR (charindex(',' + CAST(d.MyId AS VARCHAR) + ',', #MyList) > 0)) AND
-- SIC Code.
(#MySICList = '' OR (charindex(',' + CAST(d.SicCode AS VARCHAR) + ',', #MySICList) > 0)) AND
-- My Types
(#MyType = '' OR #MyType = 'A' OR d.MyType = #MyType OR h.DefaultMyType = #MyType) AND
-- MYProviders
((#MyProvider = '' OR (charindex(',' + CAST(d.MyProviderOne AS VARCHAR) + ',', #MyProvider) > 0)) OR
(#MyProvider = '' OR (charindex(',' + CAST(d.MyProviderTwo AS VARCHAR) + ',', #MyProvider) > 0))) AND
-- State.
(#MyState = '' OR d.[State] = #MyState) AND
-- City.
(#MyCityList = '' OR (charindex(',' + d.City + ',', #MyCityList) > 0)) AND
-- Zip Code.
(#MyZipList = '' OR (charindex(',' + d.Zip5 + ',', #MyZipList) > 0)) AND
-- LeadSource
(#MySource = '' OR s.MySource = #MySource) AND
-- Between Dates
(#MyStartDate = '' AND #MyEndDate = '' OR h.CreationDate BETWEEN #MyStartDate AND #MyEndDate) AND
-- Mystyle
((#MyStyle = 'A' AND (d.MyProviderOne IS NOT NULL OR d.MyProviderOne > 0 OR d.CustomerUsageOne > 0)) OR
(#MyStyle = 'B' AND (d.MyProviderTwo IS NOT NULL OR d.MyProviderTwo > 0 OR d.CustomerUsageTwo > 0)) OR
(#MyStyle = '' OR #MyStyle IS NULL)) AND
-- Source parameters are important. Only processed finished batches.
(h.UseThisRecord = 1) AND
(h.[status] = 'Finished') AND
(d.MyDuplicate IS NULL) AND
(d.DoNotUseFlag IS NULL) AND
(d.DoNotUseIFlag IS NULL) AND
(d.CustomerHome IS NULL) AND
(d.CustomerWork IS NULL) AND
(d.LeadDuplicate IS NULL) AND
(d.MyPhone >'' OR d.MyPhone <> NULL) AND
((CAST(FLOOR( CAST( h.ExpirationDate AS FLOAT ) )AS DATETIME) > CAST(FLOOR( CAST( GETDATE() AS FLOAT ) )AS DATETIME)) OR
h.ExpirationDate IS NULL)
--
-- 4. Flag Phone Duplicates inside myschema.Destination
--
UPDATE T1
SET DeleteFlag = 1
FROM myschema.Destination T1, myschema.Destination T2
WHERE
T1.MyPhone = T2.MyPhone AND
T1.FullName = T2.FullName AND
T1.Address1 = T2.Address1 AND
T1.City = T2.City AND
T1.[State] = T2.[State] AND
T1.Zip5 = T2.Zip5 AND
T1.MyPhone <> '' AND
T1.Id = T2.Id AND -- This will flag the batch itself
T1.Id = #BatchId AND
T1.Id < T2.Id -- This will leave the highest Id unflagged (latest record)
--
-- 5. Duplicate Contact Flag. All Records
--
IF #MyCampaign = 1
UPDATE T1
SET DeleteFlag = 1
FROM myschema.Destination T1, myschema.Destination T2
WHERE
T1.MyPhone = T2.MyPhone AND
T1.FullName = T2.FullName AND
T1.Address1 = T2.Address1 AND
T1.City = T2.City AND
T1.[State] = T2.[State] AND
T1.Zip5 = T2.Zip5 AND
T1.MyPhone <> '' AND
T1.Id = #BatchId AND
T1.Id <> T2.Id -- Process against other batches
--
-- 6. Active Flag
--
IF #MyCampaign <> 1
UPDATE T1
SET DeleteFlag = 1
FROM myschema.Destination T1, myschema.Destination T2
JOIN myschema.Header H ON T2.Id = H.ID
WHERE
T1.MyPhone = T2.MyPhone AND
T1.FullName = T2.FullName AND
T1.Address1 = T2.Address1 AND
T1.City = T2.City AND
T1.[State] = T2.[State] AND
T1.Zip5 = T2.Zip5 AND
T1.MyPhone <> '' AND
T1.Id = #BatchId AND
T1.Id <> T2.Id AND -- Process against other batches
H.ActiveBatch = 1 -- Only Active
--
-- 7. Delete DeleteFlag rows. Check for Id just in case
--
IF #BatchId > 0
DELETE FROM myschema.Destination
WHERE
(DeleteFlag = 1) AND (Id = #BatchId)
--
-- 8. Update header with date last run
--
UPDATE myschema.Header
SET DateLastRun = GETDATE()
WHERE ID = #BatchId
END
GO
Thanks,
Christian
This often happens when you use parameters in the proc and constants ad-hoc
SQL Server tries to generate a re-usable plan usually. With constants it doesn't need to because it can never be re-used for different constants.
There are other options such as SET options for the stored procedure or datatype mismatches.. but we have no further information to go on.
1 - Show the code.
2 - without seeing the code, I'm going to guess you have multiple parameters you are passing to the stored proc, and you are having a parameter sniffing issue.
This may be due to parameter sniffing. Have you compared the execution plans? If you grab the free Plan Explorer from http://www.sqlsentry.net/plan-explorer/sql-server-query-view.asp you can see quite clearly, among other things, the runtime vs. compiled values for the parameters to your stored procedure. Sometimes adding WITH RECOMPILE to the procedure can help prevent bad plans from sticking around (at the potential cost of slightly higher CPU usage every time the procedure is executed). But it's not always the best answer - the plan that's currently cached may be atypical and RECOMPILE every time may be overkill. Sometimes the answer is in how the parameters are defined - e.g. if you pass a parameter in you can sometimes defeat parameter sniffing by declaring a local variable and passing the input param to that and using the local variable later in the code. Sometimes the answer is turning on the optimize for ad hoc setting. Tough to say without more details.
Investigating the plan is a good first step, though. If you see that the plans are different post back with the differences and we can help guide you.
It would help to see the sproc and the query but I'm guessing something 'bad' is cached about the stored procedure. Try clearing SQL's cache (assuming SQL Server from your tags). See this
There is probably a bad query plan for the stored procedure. Try dropping and recreating the stored procedure.
it may be that you put the driving query inside the loop in a funny way - making it execute too many times.
i agree with all others - show the code.

Passing an array of ID's to a stored procedure

I have stored procedure, i want to send it an array of values. When i send more than one i'm getting an error
Error converting data type varchar to numeric.
Here is the code.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_getTransfer] #TRANSFER_ID int = null, #COMPANY VARCHAR(5),#FORMTYPE VARCHAR(30), #TRANSFER_IDS VARCHAR(500) = NULL, #SEAL_DATE datetime = NULL AS
-- Declare variables
DECLARE #rc Int
IF #SEAL_DATE IS NULL
BEGIN
SELECT
COMPANY,
FORMTYPE,
COMPANY_NAME,
COMPANY_ADDRESS1,
COMPANY_ADDRESS2,
IMID,[DESCRIPTION],AMOUNT,AMOUNT_TRANSFER,
CONSIDERATION,
TRANSFER_ID,
[DATE],
CURR,
CMF_NAME_1,
CMF_NAME_2,
CMF_ADDR_1,
CMF_ADDR_2,
CMF_ADDR_3,
CMF_ADDR_4,
CMF_POSTAL_CODE,
Cons_Curr = CASE
WHEN LTRIM(RTRIM(Cons_Curr)) <> '' THEN Cons_Curr
ELSE CURR
END,
-- Cons_Curr,
TRANSFERYEAR,
TRANSFERMONTH,
TRANSFERDAY,
dbo.CurrencyToWords(CURR) AS CURR_WORDS,
---dbo.CurrencyToWords(Cons_Curr) AS CONNS_CURR_WORDS
CONS_CURR_WORDS = CASE
WHEN LTRIM(RTRIM(CONS_CURR)) <> '' THEN dbo.CurrencyToWords(CONS_CURR)
ELSE dbo.CurrencyToWords(CURR)
END
FROM
VW_TRANSFERS
WHERE
TRANSFER_ID= #TRANSFER_ID
AND
FORMTYPE= #FORMTYPE
AND
COMPANY = #COMPANY
OR
TRANSFER_ID IN (#TRANSFER_IDS)
END
ELSE
SELECT
COMPANY,
FORMTYPE,
COMPANY_NAME,
COMPANY_ADDRESS1,
COMPANY_ADDRESS2,
IMID,[DESCRIPTION],AMOUNT,AMOUNT_TRANSFER,
CONSIDERATION,
TRANSFER_ID,
[DATE],
CURR,
CMF_NAME_1,
CMF_NAME_2,
CMF_ADDR_1,
CMF_ADDR_2,
CMF_ADDR_3,
CMF_ADDR_4,
CMF_POSTAL_CODE,
--Cons_Curr,
Cons_Curr = CASE
WHEN LTRIM(RTRIM(Cons_Curr)) <> '' THEN Cons_Curr
ELSE CURR
END,
TRANSFERYEAR,
TRANSFERMONTH,
TRANSFERDAY,
dbo.CurrencyToWords(CURR) AS CURR_WORDS,
---dbo.CurrencyToWords(Cons_Curr) AS CONNS_CURR_WORDS
CONS_CURR_WORDS = CASE
WHEN LTRIM(RTRIM(CONS_CURR)) <> '' THEN dbo.CurrencyToWords(CONS_CURR)
ELSE dbo.CurrencyToWords(CURR)
END
FROM
VW_TRANSFERS
WHERE
FORMTYPE= #FORMTYPE
AND
COMPANY = #COMPANY
AND
DATE = #SEAL_DATE
OR
TRANSFER_ID IN (#TRANSFER_IDS)
EXEC sp_getTransfer NULL, fgb, transfer, '124,444,4555,8865,24,55,69', NULL
the following code cannot work:
TRANSFER_ID IN (#TRANSFER_IDS)
Several working alternatives described here:
Arrays and Lists in SQL Server
you would have to set this up as a dynamic stored procedure or loop through the ids in code and call the stored proc each time. Do you know how to set up a dynamic procedure?
EXAMPLE
ALTER Procedure [dbo].[sp_NAME]
(#id as varchar(max)
)
as
Declare #query1 as nvarchar(max)
If #Param is null
set #Param = ''
Set #query1 = '
select whatever
from table
where id in('+#id+')'
EXECUTE sp_executesql #query1

Resources