How to rectify this query in SQL Server 2005 - sql

I have the a query which is union of two queries, the resulting query is returning duplicate records, I don't want duplicate records. I tried using DISTINCT but still getting the same result, can anybody help me fix this query?
I also want to know whether this query is safe from SQL injection... I'll be pasting my query below:
ALTER PROCEDURE [dbo].[sp_GetTrashListWithSorting] --'6dbf9a01-c88f-414d-8dd9-696749258cef', '6dbf9a01-c88f-414d-8dd9-696749258cef','DateTime ASC','0','30'
(
#p_CreatedBy UNIQUEIDENTIFIER,
#p_ToReceipientID UNIQUEIDENTIFIER,
#p_SortExpression NVARCHAR(100),
#p_StartIndex INT,
#p_MaxRows INT
)
AS
SET NOCOUNT ON;
IF LEN(#p_SortExpression) = 0
SET #p_SortExpression ='DateTime DESC'
DECLARE #Sql NVARCHAR(4000)
SET #sql = 'SELECT ID, DateTime, Subject, CreatedBy, ToReceipientID, Status
FROM (SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
Status,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM (SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
SenderStatus AS Status
FROM ComposeMail
WHERE (CreatedBy = #p)
AND (SenderStatus = 7 OR SenderStatus = 8)
UNION
SELECT ID,
DateTime,
Subject,
CreatedBy,
ToReceipientID,
ReceiverStatus As Status
FROM ComposeMail
WHERE (ToReceipientID = #p1)
AND (ReceiverStatus = 7 OR ReceiverStatus = 8)) AS NewDataTable
) AS IndexTable
WHERE
Indexing > #p2 AND Indexing<= (#p2+#p3)'
DECLARE #paramDefinition NVARCHAR(500)
SET #paramDefinition = N'#p UNIQUEIDENTIFIER ,#p1 UNIQUEIDENTIFIER, #p2 INT, #p3 INT'
EXEC sp_executesql #sql, #paramDefinition,
#p = #p_CreatedBy,
#p1 = #p_ToReceipientID,
#p2 = #p_StartIndex ,
#p3 = #p_MaxRows

1) I re-wrote your SQL as:
WITH trash_list AS (
SELECT cm.id,
cm.datetime,
cm.subject,
cm.createdby,
cm.toreceipientid,
cm.senderstatus AS Status
FROM COMPOSEMAIL cm
WHERE cm.createdBy = #p
AND cm.enderStatus IN(7, 8)
UNION
SELECT cm.id,
cm.datetime,
cm.subject,
cm.createdby,
cm.toreceipientid,
cm.receiverstatus AS Status
FROM COMPOSEMAIL cm
WHERE cm.toreceipientid = #p1
AND cm.receiverstatus IN (7, 8))
SELECT t.id,
t.datetime,
t.subject,
t.createdby,
t.toreceipientid,
t.status
FROM (SELECT tl.id,
tl.datetime,
tl.subject,
tl.createdby,
tl.toreceipientid,
tl.status,
ROW_NUMBER() OVER(ORDER BY '+ #p_SortExpression +') AS Indexing
FROM trash_list tl
GROUP BY tl.id,
tl.datetime,
tl.subject,
tl.createdby,
tl.toreceipientid,
tl.status) t
WHERE t.indexing BETWEEN #p2 AND (#p2+#p3)
...but if you still get duplicates, review the logic in the SELECT/UNION in the WITH clause.
Get it to work as normal SQL before turning it into dynamic SQL.
2) The query is not safe from injection attacks because you aren't handling single quotes when users can provide text:
IF LEN(#p_SortExpression)=0
SET #p_SortExpression ='DateTime DESC'
...should be:
IF LEN(#p_SortExpression)=0
SET #p_SortExpression ='DateTime DESC'
ELSE
SET #p_SortExpression = REPLACE(#p_SortExpression, '''', '''''')

You do not need to queries and a union. Instead of these 2 lines (one per subquery)
WHERE (CreatedBy = #p)
WHERE (ToReceipientID = #p1)
do this (in one query)
WHERE CreatedBy IN (#p, #p1)
Like this:
SELECT
ID
, DateTime
, Subject
, CreatedBy
, ToReceipientID
, Status
FROM (
SELECT
ID
, DateTime
, Subject
, CreatedBy
, ToReceipientID
, SenderStatus AS Status
, ROW_NUMBER() OVER (ORDER BY ' + #p_SortExpression + ') AS Indexing
FROM ComposeMail
WHERE CreatedBy IN (#p, #p1)
AND (SenderStatus = 7
OR SenderStatus = 8)
) AS IndexTable
WHERE Indexing > #p2
AND Indexing <= (#p2 + #p3)
HOWEVER I am not sure I understand how you pass in values for #p or #p1

Related

How to shorten SQL script

According to my code below, I was using cursor to get all information in WInstance table. However, my query may have a problem with performance due to cursor. Is there any way to use nested-select instead of cursor? Please share me your idea.
My business here is to get only 1 of the same ItemID, SequenceID, TaskStatus, ListID, WebID, SiteID.
Technically, there are lots of the same ItemID, SequenceID, TaskStatus, ListID, WebID, SiteID in the joining tables of WInstance and WProgress with AssignTask = 'Assign task'. Therefore, I used distinct and cursorto loop through to get only the top 1 with order by.
Here is my code:
CREATE PROCEDURE dbo.CustomTasksHistory
(
#Username NVARCHAR(255)
)
AS
DECLARE #TempTableStatus TABLE
(
ItemID INT ,
SequenceID INT ,
TaskStatus NVARCHAR(25) ,
ListID UNIQUEIDENTIFIER ,
WebID UNIQUEIDENTIFIER ,
SiteID UNIQUEIDENTIFIER
);
DECLARE #ItemID INT;
DECLARE #SequenceID INT;
DECLARE #ListID UNIQUEIDENTIFIER;
DECLARE #WebID UNIQUEIDENTIFIER;
DECLARE #SiteID UNIQUEIDENTIFIER;
DECLARE #AssignTask VARCHAR(25);
SET #AssignTask = 'Assign task';
-- Select final TaskStatus of each ItemID with its SequenceID --
DECLARE cursor_ItemID CURSOR FAST_FORWARD READ_ONLY FOR
SELECT DISTINCT
WI.ItemID ,
WP.SequenceID ,
WI.ListID ,
WI.WebID ,
WI.SiteID
FROM dbo.WInstance WI
INNER JOIN dbo.WProgress WP ON WI.InstanceID = WP.InstanceID
WHERE WP.CurrentActivityTitle = #AssignTask;
OPEN cursor_ItemID;
FETCH NEXT FROM cursor_ItemID INTO #ItemID, #SequenceID, #ListID, #WebID, #SiteID;
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #TempTableStatus
( ItemID ,
SequenceID ,
TaskStatus ,
ListID ,
WebID ,
SiteID
)
SELECT TOP 1
WI.ItemID ,
WP.SequenceID ,
CASE WHEN WP.ActivityComplete = 0
THEN 'Not Started'
ELSE 'Completed'
END AS 'TaskStatus' ,
WI.ListID ,
WI.WebID ,
WI.SiteID
FROM dbo.WInstance WI
INNER JOIN dbo.WProgress WP ON WI.InstanceID = WP.InstanceID
WHERE WP.CurrentActivityTitle = #AssignTask
AND WI.ItemID = #ItemID
AND WP.SequenceID = #SequenceID
AND WI.ListID = #ListID
AND WI.WebID = #WebID
AND WI.SiteID = #SiteID
ORDER BY TimeStamp DESC;
FETCH NEXT FROM cursor_ItemID INTO #ItemID, #SequenceID, #ListID, #WebID, #SiteID;
END;
CLOSE cursor_ItemID;
DEALLOCATE cursor_ItemID;
SELECT *
FROM #TempTableStatus;
You don't need to use cursor. Replace it with below query
SELECT ItemID, SequenceID, TaskStatus, ListID, WebID, SiteID
FROM
(
SELECT RN = ROW_NUMBER() OVER (PARTITION BY WP.CurrentActivityTitle,
WI.ItemID, WP.SequenceID,
WI.ListID, WI.WebID, WI.SiteID
ORDER BY TimeStamp DESC),
WI.ItemID ,
WP.SequenceID ,
CASE WHEN WP.ActivityComplete = 0
THEN 'Not Started'
ELSE 'Completed'
END AS 'TaskStatus' ,
WI.ListID ,
WI.WebID ,
WI.SiteID
FROM dbo.WInstance WI
INNER JOIN dbo.WProgress WP ON WI.InstanceID = WP.InstanceID
WHERE WP.CurrentActivityTitle = #AssignTask
) D
WHERE RN = 1;

Parameter Sniffing Not working

I am using MSSQL. I have a stored procedure which works fine for couple of days and later on it becomes slow. I came to know that Parameter Sniffing will work for it. How ever after implementing it it became slow for ever. I also tried to Recompiling job. I faced the same slowness issue immediately.
Can some one please help me with this ?
Below is the structure of my Stored Procedure.
#START_VALUE int=null,
#END_VALUE int=null
#UID NVARCHAR(MAX)=null,
AS
BEGIN
SELECT
dbo.TABLE1.ID,
ROW_NUMBER() OVER (ORDER BY TABLE1.UPDATED_ON desc) AS RN,
CONVERT(VARCHAR(10), dbo.TABLE1.DATE, 101) AS TDATE,
CATEGORY = (
SELECT TOP 1 COLUMN1
FROM TABLE5 CT1
WHERE TABLE1.CATEGORY = CT1.CATEGORY_ID
),
TYPETEXT = (
SELECT TOP 1 COLUMN1
FROM TABLE6 CT1
WHERE TABLE1.TYPE = CT1.TYPE_ID
),
IMAGE = STUFF(( SELECT DISTINCT ',' + CAST(pm.C1 AS varchar(12))
FROM TABLE2 pm
WHERE pm.ID = TABLE1.ID AND pm.C1 IS NOT NULL AND pm.C1 <> ''
FOR XML PATH('')),
1, 1, '' ) INTO #tempRecords
FROM dbo.TABLE1
WHERE ((#UID is null OR dbo.TABLE1.ID = #UID )
ORDER BY TABLE1.UPDATED DESC
SELECT #count = COUNT(*) FROM #tempRecords;
SELECT *, CONVERT([int],#count) AS 'TOTAL_RECORDS'
FROM #tempRecords
WHERE #tempRecords.RN BETWEEN CONVERT([bigint], #START_VALUE) AND CONVERT([bigint], #END_VALUE)
END
GO
To make the query optimized for parameter sniffing, declare dummy variables and use them in your query, as opposed to using the original parameters as such.
CREATE PROCEDURE test_proc
#START_VALUE INT=NULL,
#END_VALUE INT=NULL,
#UID NVARCHAR(max)=NULL
as
BEGIN
DECLARE #START_VALUE_SNIFF INT=NULL,
#END_VALUE_SNIFF INT=NULL,
#UID_SNIFF NVARCHAR(max)=NULL
SET #START_VALUE_SNIFF = #START_VALUE
SET #END_VALUE_SNIFF = #END_VALUE
SET #UID_SNIFF = #UID
select * from
FROM dbo.TABLE1
WHERE ((#UID_SNIFF is null OR dbo.TABLE1.ID = #UID_SNIFF )
ORDER BY TABLE1.UPDATED DESC
END

Replace Cursor Next number assignment Operation with Set based equivalent

Good day all,
I have the following cursor query and would like to replace it with a set based query to address performance issues.
DECLARE #EmpIDM CHAR(21);
DECLARE #EmpName CHAR(21);
DECLARE #EMPCatID INT;
DECLARE Assign_Emp SCROLL CURSOR
FOR
SELECT DISTINCT EMP
, EMPNAME
FROM HR_EMPLOYEES
SET NOCOUNT ON
OPEN Assign_Emp;
FETCH NEXT
FROM Assign_Emp
INTO #EmpIDM
, #EmpName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #EMPCatID = (
SELECT TOP 1 CategoryID
FROM Categories
)
UPDATE Categories
SET CategoryID = (CategoryID + 1) /*Increment Category ID for next Insert*/
INSERT INTO Table1 (
EmpNumber
, EmployeeName
, EmployeeCategoryID
)
VALUES (
#EmpIDM
, #EmpName
, #EMPCatID
)
FETCH NEXT
FROM Assign_Emp
INTO #EmpIDM
, #EmpName
END
CLOSE Assign_Emp;
CLOSE Assign_Emp;
SET NOCOUNT OFF
My challenge is adapting the following code segment into a set based operation
SET #EMPCatID = (
SELECT TOP 1 CategoryID
FROM Categories
)
UPDATE Categories
SET CategoryID = (CategoryID + 1) /*Increment Category ID for next Insert*/
I humbly appreciate any insight on how I can achieve this.
Many Thanks,
Re-write using temp. table with identity column:
declare #offset int
select #offset = isnull(max(CategoryID),0) from Categories
create table #data (
EmpNumber CHAR(21),
EmployeeName CHAR(21),
EmployeeCategoryID int identity
)
INSERT INTO #data (
EmpNumber
, EmployeeName)
SELECT DISTINCT EmpIDM
, EmpName
FROM HR_EMPLOYEES
insert into Table1 (
EmpNumber
, EmployeeName
, EmployeeCategoryID
) select
EmpNumber
, EmployeeName
, EmployeeCategoryID + #offset
from #data
update Categories
set CategoryID = (select max(EmployeeCategoryID) from #data) + #offset

Delete Duplicate Records with Same Values

I have a TSQL statement that is taking several hours to run. I'm sure I need to look into the import process to avoid duplicates being inserted but for the time being I'd just like to remove all records except one with duplicate values. ParameterValueId is the primary key on the table but I have many duplicate entries that need to be deleted. I only need one record for each ParameterId, SiteId, MeasurementDateTime, and ParameterValue. Below is my current method for deleting duplicate records. It finds all values that have a count > 1. It then finds the first Id with those values and deletes all of the records with those values that don't match the first ID found by those values. Besides the print statements is there a more efficient way of doing this. Can I do a way with the cursor at all to improve performance?
BEGIN TRANSACTION
SET NOCOUNT ON
DECLARE #BeginningRecordCount INT
SET #BeginningRecordCount =
(
SELECT COUNT(*)
FROM ParameterValues
)
DECLARE #ParameterId UNIQUEIDENTIFIER
DECLARE #SiteId UNIQUEIDENTIFIER
DECLARE #MeasurementDateTime DATETIME
DECLARE #ParameterValue FLOAT
DECLARE CDuplicateValues CURSOR FOR
SELECT
[ParameterId]
,[SiteId]
,[MeasurementDateTime]
,[ParameterValue]
FROM [ParameterValues]
GROUP BY
[ParameterId]
,[SiteId]
,[MeasurementDateTime]
,[ParameterValue]
HAVING COUNT(*) > 1
OPEN CDuplicateValues
FETCH NEXT FROM CDuplicateValues INTO
#ParameterId
,#SiteId
,#MeasurementDateTime
,#ParameterValue
DECLARE #FirstParameterValueId UNIQUEIDENTIFIER
DECLARE #DuplicateRecordsDeleting INT
WHILE ##FETCH_STATUS <> -1
BEGIN
SET #FirstParameterValueId =
(
SELECT TOP 1 ParameterValueId
FROM ParameterValues
WHERE
ParameterId = #ParameterId
AND SiteId = #SiteId
AND MeasurementDateTime = #MeasurementDateTime
AND ParameterValue = #ParameterValue
)
SET #DuplicateRecordsDeleting =
(
SELECT COUNT(*)
FROM ParameterValues
WHERE
ParameterId = #ParameterId
AND SiteId = #SiteId
AND MeasurementDateTime = #MeasurementDateTime
AND ParameterValue = #ParameterValue
AND ParameterValueId <> #FirstParameterValueId
)
PRINT 'DELETING ' + CAST(#DuplicateRecordsDeleting AS NVARCHAR(50))
+ ' records with values ParameterId : ' + CAST(#ParameterId AS NVARCHAR(50))
+ ', SiteId : ' + CAST (#SiteId AS NVARCHAR(50))
+ ', MeasurementDateTime : ' + CAST(#MeasurementDateTime AS NVARCHAR(50))
+ ', ParameterValue : ' + CAST(#ParameterValue AS NVARCHAR(50))
DELETE FROM ParameterValues
WHERE
ParameterId = #ParameterId
AND SiteId = #SiteId
AND MeasurementDateTime = #MeasurementDateTime
AND ParameterValue = #ParameterValue
AND ParameterValueId <> #FirstParameterValueId
FETCH NEXT FROM CDuplicateValues INTO
#ParameterId
,#SiteId
,#MeasurementDateTime
,#ParameterValue
END
CLOSE CDuplicateValues
DEALLOCATE CDuplicateValues
DECLARE #EndingRecordCount INT
SET #EndingRecordCount =
(
SELECT COUNT(*)
FROM ParameterValues
)
PRINT 'Beginning Record Count : ' + CAST(#BeginningRecordCount AS NVARCHAR(50))
PRINT 'Ending Record Count : ' + CAST(#EndingRecordCount AS NVARCHAR(50))
PRINT 'Total Records Deleted : ' + CAST((#BeginningRecordCount - #EndingRecordCount) AS NVARCHAR(50))
SET NOCOUNT OFF
PRINT 'RUN THE COMMIT OR ROLLBACK STATEMENT AFTER VERIFYING DATA.'
--COMMIT
--ROLLBACK
Use option with CTE and OVER clause. OUTPUT.. INTO clause saves the information from rows affected by an DELETE statement into #delParameterValues table. Further, in the body of procedure, you can use this table to print the affected rows.
DECLARE #delParameterValues TABLE
(
ParameterId UNIQUEIDENTIFIER,
SiteId UNIQUEIDENTIFIER,
MeasurementDateTime DATETIME,
ParameterValue FLOAT,
DeletedRecordCount int
)
;WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY [ParameterId],[SiteId],[MeasurementDateTime],[ParameterValue] ORDER BY 1/0) AS rn,
COUNT(*) OVER (PARTITION BY [ParameterId],[SiteId],[MeasurementDateTime],[ParameterValue]) AS cnt
FROM [ParameterValues]
)
DELETE cte
OUTPUT DELETED.[ParameterId],
DELETED.[SiteId],
DELETED.[MeasurementDateTime],
DELETED.[ParameterValue],
DELETED.cnt INTO #delParameterValues
WHERE rn != 1
SELECT DISTINCT *
FROM #delParameterValues
Demo on SQLFiddle
you can do it in a single sql:
DELETE p FROM ParameterValues p
LEFT JOIN
(SELECT ParameterId, SiteId, MeasurementDateTime, ParameterValue, MAX(ParameterValueId) AS MAX_PARAM
FROM ParameterValues
GROUP BY ParameterId, SiteId, MeasurementDateTime, ParameterValue
) m
ON m.ParameterId = p.ParameterId
AND m.SiteId = p.SiteId
AND m.MeasurementDateTime = p.MeasurementDateTime
AND m.ParameterValue = p.ParameterValue
AND m.MAX_PARAM = p.ParameterValueId
WHERE m.ParameterId IS NULL
Of course it will not print the output, but you can still print the rows before and after

optimizing SQL SP

I want to optimize this SP, anyone have some idea how I can do that? Thanks in advance.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Members] (
#StartTime datetime = null
, #EndTime datetime = null
, #CustomerEmail nvarchar(255) = null
, #CustomerName nvarchar(255) = null
, #ShippingMethod nvarchar(255) = null
, #MemberOrderStatusPending int = null
, #MemberOrderProcessing int = null
, #MemberOrderComplete int = null
, #MemberOrderStatusCancelled int = null
, #MemberOrderStatusCancelledDiscontinued int = null
, #MemberOrderStatusCancelledCustomerRequest int = null
, #MemberOrderStatusCancelledPendingNeverPaid int = null
)
AS
BEGIN
SET NOCOUNT ON
SELECT DISTINCT o.OrderID
, o.OrderTotal
, o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName
, o.CreatedOn AS CreatedOn
FROM Order o
WHERE ( o.CreatedOn > #StartTime OR #StartTime IS NULL )
AND ( o.CreatedOn < #EndTime OR #EndTime IS NULL )
AND ( o.ShippingEmail = #CustomerEmail OR #CustomerEmail IS NULL)
AND ( o.BillingFirstName + ' ' + o.BillingLastName = #CustomerName OR #CustomerName IS NULL )
AND ( o.ShippingFirstName + ' ' + o.ShippingLastName = #CustomerName OR #CustomerName IS NULL )
AND ( o.ShippingMethod = #ShippingMethod OR #ShippingMethod IS NULL )
AND ( o.OrderStatusID = #MemberOrderProcessing
OR o.OrderStatusID = #MemberOrderProcessing
OR o.OrderStatusID = #MemberOrderComplete
OR o.OrderStatusID = #MemberOrderStatusCancelled
OR o.OrderStatusID = #MemberOrderStatusCancelledDiscontinued
OR o.OrderStatusID = #MemberOrderStatusCancelledCustomerRequest
OR o.OrderStatusID = #MemberOrderStatusCancelledPendingNeverPaid
OR #MemberOrderProcessing IS NULL
OR #MemberOrderProcessing IS NULL
OR #MemberOrderComplete IS NULL
OR #MemberOrderStatusCancelled IS NULL
OR #MemberOrderStatusCancelledDiscontinued IS NULL
OR #MemberOrderStatusCancelledCustomerRequest IS NULL
OR #MemberOrderStatusCancelledPendingNeverPaid IS NULL )
ORDER BY
o.OrderID
END
When you have that many OR conditions performance is bound to suffer (not to mention that this would lead to parameter sniffing). I would highly recommend using Dynamic SQL here. Something like this,
DECLARE #query VARCHAR(MAX)
SET #query =
'SELECT DISTINCT o.OrderID, o.OrderTotal, o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName, o.CreatedOn AS CreatedOn FROM Order o
WHERE 1=1 '
IF #StartTime IS NOT NULL
SET #query = #query + ' AND o.CreatedOn > #StartTime'
IF #EndTime IS NOT NULL
SET #query = #query + ' AND o.CreatedOn < #EndTime'
IF #CustomerEmail IS NOT NULL
SET #query = #query + ' AND o.ShippingEmail = #CustomerEmail'
......
......
exec sp_executesql #query,
N'#StartTime DATETIME,
#EndTime DATETIME,
...<other param definitions>',
#StartTime,
#EndTime,
.. <other param values>
best source for dynamic search conditions:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
there are a lot of subtle implications on how you do this as to if an index can be used or not. If you are on the proper release of SQL Server 2008 you can just add OPTION (RECOMPILE) to the query and the local variable's value at run time is used for the optimizations.
Consider this, OPTION (RECOMPILE) will take this code (where no index can be used with this mess of ORs):
WHERE
(#search1 IS NULL or Column1=#Search1)
AND (#search2 IS NULL or Column2=#Search2)
AND (#search3 IS NULL or Column3=#Search3)
and optimize it at run time to be (provided that only #Search2 was passed in with a value):
WHERE
Column2=#Search2
and an index can be used (if you have one defined on Column2)
if you are not on the needed release of SQL Server 2008, the linked article offers many methods with pros and cons for each. for example, if you can determine a min and a max possible range for your search column, and the search column is NOT NULL, then you can do better than the (#Search IS NULL OR Col=#Search), see this area of the above linked article. However you should read the entire article, there are so many variations that depend on your situation, you really need to learn multiple approaches and when to use them.
IF the OrderStatusID is a bit field, following might work
SELECT DISTINCT o.OrderID
, o.OrderTotal
, o.BillingFirstName + ' ' + o.BillingLastName AS CustomerName
, o.CreatedOn AS CreatedOn
FROM Order o
WHERE ( o.CreatedOn > COALESCE( #StartTime, '01-01-1899' ))
AND ( o.CreatedOn < COALESCE( #EndTime, '01-01-2099' ))
AND ( o.BillingFirstName + ' ' + o.BillingLastName = COALESCE( #CustomerName, o.BillingFirstName + ' ' + o.BillingLastName ))
AND ( o.ShippingFirstName + ' ' + o.ShippingLastName = COALESCE (#CustomerName, o.ShippingFirstName + ' ' + o.ShippingLastName ))
AND ( o.ShippingEmail = COALESCE(#CustomerEmail, o.ShippingEmail )
AND ( o.ShippingMethod = COALESCE ( #ShippingMethod, o.ShippingMethod )
AND ( o.OrderStatusID & (
COALESCE ( #MemberOrderProcessing, 1 )
| COALESCE ( #MemberOrderComplete, 2 )
| COALESCE ( #MemberOrderStatusCancelled , 4 )
| COALESCE ( #MemberOrderStatusCancelledDiscontinued , 8 )
| COALESCE ( #MemberOrderStatusCancelledCustomerRequest , 16 )
| COALESCE ( #MemberOrderStatusCancelledPendingNeverPaid , 32 )
) >= 1
)
ORDER BY
o.OrderID