SQL Query produces duplicates with "Where IN" query - sql-server

I have a large SQL statement which does a whole load of joins on my tables. I have converted some of my table relationships to many-to-many relationships so that it is more efficient. I have therefore decided to convert my SQL to do a WHERE IN statement (on location).
The following query is the one that currently returns the desired results:
ALTER PROCEDURE [dbo].[GetMemberListing]
#Locations nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select
Member.Id,
AspNetUsers.Salutation,
AspNetUsers.FirstName,
AspNetUsers.PhotoUrl,
AspNetUsers.LastName,
AspNetUsers.Birthday,
AspNetUsers.Gender,
Member.IDType,
Member.JoinDate,
CONCAT (AspNetUsers.FirstName, ' ', AspNetUsers.LastName) as FullName,
AspNetUsers.CountryCode,
AspNetUsers.Email,
Location.Name as LocationName,
AspNetUsers.HomePhone as HomePhone,
coalesce(Package.Name,'No Package') as PackageName,
PackageTerm = case when Package.PackageIsReoccuring = 1 then 'Recurring' when Package.PackageIsSession = 1 then 'Paid In Full' when membership.TotalPrice = 0 then 'Free' when Package.PackagePayInFull = 1 then 'Paid In Full' end,
PackageType.Name as PackageType,
MembershipId = case when membership.id IS NULL THEN '' ELSE 0 end,
coalesce(membershipstate.name, 'N/A') as MembershipState,
MembershipStartDate = case when membership.StartDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.StartDate) end,
MembershipEndDate = case when membership.EndDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.EndDate) end
from
(
select
member.id as memberid,
(
select top 1 id
from membership
where memberid = member.id
and membership.StartDate <= getdate()
order by membership.enddate desc
) as membershipid
from member
) as LatestMembership
left join membership
on latestmembership.membershipid = membership.id
join member
on latestmembership.memberid = member.id
join AspNetusers
on member.AspNetUserId = AspNetUsers.Id
join Location
on member.HomeLocationId = Location.Id
left join Package
on membership.packageid = package.Id
left join PackageType
on package.packagetypeid = packagetype.Id
left join MembershipState
on membership.membershipstateid = membershipstate.Id
Order By aspNetusers.LastName desc
END
Below is what i have tried to do; however, it is duplicating the otherwise correct results based on the number of values in the WHERE IN join.
This on member.HomeLocationId = Location.Id
becomes on member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))
As seen below:
ALTER PROCEDURE [dbo].[GetMemberListing]
#Locations nvarchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
select
Member.Id,
AspNetUsers.Salutation,
AspNetUsers.FirstName,
AspNetUsers.PhotoUrl,
AspNetUsers.LastName,
AspNetUsers.Birthday,
AspNetUsers.Gender,
Member.IDType,
Member.JoinDate,
CONCAT (AspNetUsers.FirstName, ' ', AspNetUsers.LastName) as FullName,
AspNetUsers.CountryCode,
AspNetUsers.Email,
Location.Name as LocationName,
AspNetUsers.HomePhone as HomePhone,
coalesce(Package.Name,'No Package') as PackageName,
PackageTerm = case when Package.PackageIsReoccuring = 1 then 'Recurring' when Package.PackageIsSession = 1 then 'Paid In Full' when membership.TotalPrice = 0 then 'Free' when Package.PackagePayInFull = 1 then 'Paid In Full' end,
PackageType.Name as PackageType,
MembershipId = case when membership.id IS NULL THEN '' ELSE 0 end,
coalesce(membershipstate.name, 'N/A') as MembershipState,
MembershipStartDate = case when membership.StartDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.StartDate) end,
MembershipEndDate = case when membership.EndDate IS NULL THEN '' ELSE CONVERT(varchar(50),membership.EndDate) end
from
(
select member.id as memberid,
(
select top 1 id
from membership
where memberid = member.id
and membership.StartDate <= getdate()
order by membership.enddate desc
) as membershipid
from member
) as LatestMembership
left join membership
on latestmembership.membershipid = membership.id
join member
on latestmembership.memberid = member.id
join AspNetusers
on member.AspNetUserId = AspNetUsers.Id
join Location
on member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))
left join Package
on membership.packageid = package.Id
left join PackageType
on package.packagetypeid = packagetype.Id
left join MembershipState
on membership.membershipstateid = membershipstate.Id
Order By aspNetusers.LastName desc
END

Change to using your split function in the where clause. Don't use that function in the join.
In addition you don't really have a valid join condition on the locations table go back to this
on member.HomeLocationId = Location.Id
And later
Where member.HomeLocationId IN (SELECT Value FROM fn_Split(#Locations, ','))

Related

Stored procedure takes more than 30 seconds to execute

I am optimizing the stored procedure in which I get list of more than 10K user ids in one table variable as a parameter. I am setting flag #ContainsUserIds if there is any data into the table variable. In main query selecting the all the users that are present in table variable or all the users if no data found in table variable (There are more condition in where clause).
The problem is here that the statement in where clause takes more than 30 second which has OR condition. If I removed the first condition to check #ContainsUserIds = 0 then it will execute within a second. Can someone please help me to optimize this query.
This Stored procedure is called from different position so the User ids may not pass.
CREATE PROCEDURE [core].[spGetUsersByFilter]
(
#ClientId nvarchar(38) = NULL,
#UserIds [UserIdList] readonly
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #ContainsUserIds BIT = 0,
SET #ContainsUserIds = CASE
WHEN EXISTS(SELECT TOP 1 1 FROM #UserIds)
THEN 1
ELSE 0
END;
SELECT DISTINCT ES.Id
FROM [db].[Users] E
JOIN [db].[UserDetails] ES ON ES.UserId = E.Id
WHERE E.[Active] = 1
AND (#ContainsUserIds = 0 OR E.UserId IN(SELECT Item FROM #UserIds))
AND ES.ClientId = #ClientId
END
SQL notoriously dislikes OR, the optimizer sometimes works around it but in most cases it's a good idea to convert things to a UNION [ALL] syntax. If there's just 1 OR that's often easy to do, if there are multiple things explode fast.
Anyway, you could thus convert your stored procedure to:
CREATE PROCEDURE [core].[spGetUsersByFilter]
(
#ClientId nvarchar(38) = NULL,
#UserIds [UserIdList] readonly
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #ContainsUserIds BIT = 0,
SET #ContainsUserIds = CASE
WHEN EXISTS(SELECT * FROM #UserIds)
THEN 1
ELSE 0
END;
SELECT DISTINCT ES.Id
FROM [db].[Users] E
JOIN [db].[UserDetails] ES ON ES.UserId = E.Id
WHERE E.[Active] = 1
AND (#ContainsUserIds = 0)
AND ES.ClientId = #ClientId
UNION ALL
SELECT DISTINCT ES.Id
FROM [db].[Users] E
JOIN [db].[UserDetails] ES ON ES.UserId = E.Id
WHERE E.[Active] = 1
AND (#ContainsUserIds = 1)
AND E.UserId IN (SELECT Item FROM #UserIds))
AND ES.ClientId = #ClientId
END
That said, you might just as well split things up here and do 2 separate SELECTs. Also, if the table-variable contains more than a couple of records you may prefer to use a temp-table as the latter allows for indexing and most importantly has statistics handling which WILL result in a better execution plan. I also prefer JOIN over IN (), just make sure there are no doubled values when JOINing.
CREATE PROCEDURE [core].[spGetUsersByFilter]
(
#ClientId nvarchar(38) = NULL,
#UserIds [UserIdList] readonly
)
AS
BEGIN
SET NOCOUNT ON
SELECT DISTINCT Item
INTO #UserIds
FROM #UserIds
IF ##ROWCOUNT = 0
BEGIN
SELECT DISTINCT ES.Id
FROM [db].[Users] E
JOIN [db].[UserDetails] ES ON ES.UserId = E.Id
WHERE E.[Active] = 1
AND ES.ClientId = #ClientId;
END
ELSE
BEGIN
CREATE UNIQUE INDEX uq0_UserIds ON #UserIds ( Item ) WITH (FILLFACTOR = 100);
SELECT DISTINCT ES.Id
FROM [db].[Users] E
JOIN [db].[UserDetails] ES ON ES.UserId = E.Id
JOIN #UserIds T ON T.Item = E.UserId
WHERE E.[Active] = 1
AND ES.ClientId = #ClientId
END
END
PS: all above written in notepad and untested, some assembly may be required =)

Use IN operator in THEN Statement in SQL

I am writing a SQL statement which will get the information from table valued parameter based on the input given in stored procedure. The condition should work if the input value row count greater than zero. Please guide me with the below query.
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
INSERT INTO #DivisionIds Values (1)
INSERT INTO #DivisionIds Values (1)
INSERT INTO #StateIds Values (1)
INSERT INTO #StateIds Values (3)
INSERT INTO #StateIds Values (31)
INSERT INTO #StateIds Values (43)
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT * FROM MedInv inv INNER JOIN Location loc ON inv.MedInvID = loc.MedInvID
WHERE CustomerID = 210
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)
The above code works fine, if I provide value for #DivisionIds and #StateIds. In some scenario #DivisionIds and StateIds does not have any values. So row count will be zero. I want to run the above condition only if the row count is greater than zero. How to do that?
My actual code contains the CASE statement for other conditions, I want to include the above condition in CASE statement, I tried the below approach but I am getting error.
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT CustomerName, InvEstValue, Status FROM MedInv inv
INNER JOIN Location loc ON loc.MedInvID = inv.MedInvID
INNER JOIN Division div ON div.DivisionID = loc.DivisionID
INNER JOIN State st ON st.StateID = loc.StateID
WHERE inv.CustomerID = 210
AND
inv.CustomerName Like
CASE WHEN #CustomerName = '' THEN '%%' ELSE '%' + #CustomerName + '%' END
AND
inv.AssetDescription Like
CASE WHEN #AssetDescription = '' THEN '%%' ELSE '%' + #AssetDescription + '%' END
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)
AND
loc.DivisionID =
CASE WHEN (#DivsionRowCount > 0) THEN loc.DivisionID IN (SELECT ID FROM #DivisionIds) ELSE loc.DivisionID END
from the above, I am getting error near to IN and ELSE keywords saying that Incorrect Syntax near IN, Incorrect syntax near ELSE . Expecting END OR THEN.
Please guide me how to use IN operator in THEN statement.
I am expecting the condition should run only if the input value parameter count is greater than zero.
I'm not sure that you take the right approach with you case when in your condition but
The problem is that you with your last condition you'll have something like :
loc.DivisionID = in(...)
And "= in" is incorrect syntax
Maybe you can add your condition directly in the join
INNER JOIN Division div ON loc.DivisionID IN (SELECT ID FROM #DivisionIds)
Is that what you expected ?
But I think that you need also to put these 2 conditions in the join
AND
#DivsionRowCount > 0 AND loc.DivisionID IN (SELECT ID FROM #DivisionIds)
AND
#StateRowCount > 0 AND loc.StateID IN (SELECT ID FROM #StateIds)
Here's how I would write it:
DECLARE #DivisionIds [dbo].[IDList]
DECLARE #StateIds [dbo].[IDList]
SET #DivsionRowCount = (SELECT COUNT(ID) FROM #DivisionIds)
SET #StateRowCount = (SELECT COUNT(ID) FROM #StateIds)
SELECT CustomerName, InvEstValue, Status
FROM MedInv inv
INNER JOIN Location loc
ON loc.MedInvID = inv.MedInvID
INNER JOIN Division div
ON div.DivisionID = loc.DivisionID
INNER JOIN State st
ON st.StateID = loc.StateID
WHERE inv.CustomerID = 210
AND (#CustomerName = '' OR inv.CustomerName Like '%' + #CustomerName + '%')
AND (#AssetDescription = '' OR inv.AssetDescription LIKE '%' + #AssetDescription + '%')
AND (#DivsionRowCount = 0 OR loc.DivisionID IN (SELECT ID FROM #DivisionIds))
AND (#StateRowCount = 0 OR loc.StateID IN (SELECT ID FROM #StateIds))
You might want to add option(recompile) if you get performance problems.
Check out revisiting catch-all queries on SQL in the wild blog for details.

Pivot with Dynamic sql as Parameter

I am not sure if this is the way to go though but I would like to know if there is someway to have a stored procedure and pass in a queries to get the values to pivot. I'm not sure if this is a good idea, so sorry if this is a stupid question, but it would be great to pass in a query instead of hard coding every single pivot you want. I have an example of the pivot Stored Procedure that I have coded. This also includes the grand totals for rows and columns.
Don't know if I should add the code as well?
Hope this makes sense.
Please see my stored procedure code below:
CREATE PROCEDURE [dbo].[PivotNoAgentPerc_SP]
AS
DECLARE #columnHeaders VARCHAR (MAX)
SELECT #columnHeaders = COALESCE(#columnHeaders + ', ','')+ QUOTENAME(granteddate)
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
) AS B
ORDER BY B.granteddate
/* GRAND TOTAL COLUMN */
DECLARE #GrandTotalCol NVARCHAR (MAX)
SELECT #GrandTotalCol =
COALESCE (#GrandTotalCol + 'ISNULL ([' + CAST (granteddate AS VARCHAR) +'],0) + ', 'ISNULL([' + CAST(granteddate AS VARCHAR)+ '],0) + ')
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
) AS B
ORDER BY B.granteddate
SET #GrandTotalCol = LEFT (#GrandTotalCol, LEN (#GrandTotalCol)-1)
/* GRAND TOTAL ROW */
DECLARE #GrandTotalRow NVARCHAR(MAX)
SELECT #GrandTotalRow =
COALESCE(#GrandTotalRow + ',ISNULL(SUM([' + CAST(granteddate AS VARCHAR)+']),0)', 'ISNULL(SUM([' + CAST(granteddate AS VARCHAR)+']),0)')
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
)AS B
ORDER BY B.granteddate
/* MAIN QUERY */
DECLARE #FinalQuery NVARCHAR (MAX)
SET #FinalQuery = 'SELECT *, ('+ #GrandTotalCol + ')
AS [Grand Total] INTO #temp_MatchesTotal
FROM
(SELECT
ISNULL(ConsultantUser.user_name,''Total'') AS [Consultant],
EOMONTH(BondSales.granteddate,0) AS [Month Granted],
COALESCE(CAST(CAST(SUM(CASE WHEN accounts_1.name = ''No Agent Channel'' THEN 1 ELSE 0 END) AS DECIMAL)/COUNT(BondSales.name) AS decimal(5,2)), 0) AS NoAgentPerc
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = ''Coastal''
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
GROUP BY EOMONTH(BondSales.granteddate, 0), ConsultantUser.user_name
) A
PIVOT
(
SUM(NoAgentPerc)
FOR [Month Granted]
IN ('+#columnHeaders +')
) B
ORDER BY [Consultant]
SELECT * FROM #temp_MatchesTotal
UNION ALL
SELECT ''Grand Total'','+ #GrandTotalRow +', ISNULL (SUM([Grand Total]),0)
FROM #temp_MatchesTotal
DROP TABLE #temp_MatchesTotal'
EXECUTE(#FinalQuery)
Sorry if the code is long but I just wanted to show you exactly what I an talking about
I have done this is in procedure and it is working fine. Compare your example to below code
You have to write Dynamic sql query
Example :
declare #s date
declare #e date
declare #dates varchar(MAX)
set #s=DATEADD(DAY,-1,#startdate)
set #e=#enddate
IF OBJECT_ID('tempdb.#DATES') IS NOT NULL
DROP TABLE #DATES
CREATE TABLE #DATES
(
ID INT PRIMARY KEY IDENTITY(1,1),
Date VARCHAR(MAX)
)
WHILE (#s<#e)
BEGIN
INSERT INTO #DATES (Date)
select CONCAT( '[',DATEADD(DAY ,1, #s),']')
set #s=DATEADD(DAY ,1, #s)
END
SELECT #dates= STUFF((
SELECT ',' + SPACE(1) + Date
FROM #DATES
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '')
--AS [Dates]
------------------------Getting RDW Datewise--------------------------------------
declare #queryRDW VARCHAR(MAX)
set #queryRDW='
select * from (
SELECT SUM(RecordValue)/60 RecordValue,RecordType ,Computationdate ,t2.ProjectResourceId,t1.ResourceCode,t1.ResourceName
FROM tblProjectResource t1 INNER JOIN tblDeploymentWorkbook t2 on t1.ProjectResourceId=t2.ProjectResourceId
WHERE
RecordType=''RDW'' and t2.SubCategoryId IN (1)
GROUP BY
RecordType, Computationdate,t2.ProjectResourceId,t1.resourceCode,t1.ResourceName
HAVING
Computationdate >= '''+Cast(#startdate as varchar)+''' and Computationdate <= '''+Cast(#enddate as varchar)+'''
)tab
PIVOT(
SUM(RecordValue) for ComputationDate in ( '+#dates+')
)t
Order By ResourceName
'
exec (#queryRDW)

T-SQL ERROR - Subquery returned more than 1 value

I am getting the following error in SQL Server:
Msg 512, Level 16, State 1, Line 18 Subquery returned more than 1
value. This is not permitted when the subquery follows =, !=, <, <= , > >, >= or when the subquery is used as an expression.
My code is as follows:
DECLARE
#personNumber varchar(20),
#itemNumber varchar(20)
SET #personNumber = 'null'
SET #itemNumber = 'null'
SELECT
OU.UserID
,OU.Name
,IGWQ.itemNumber
,IG.itemName
,IGWQ.QuantityOnHand
FROM dbo.Table1 IGWQ
INNER JOIN Table2 OU ON IGWQ.UserId = OU.UserId
INNER JOIN Table3 IG ON IGWQ.itemNumber = IG.itemNumber
WHERE IGWQ.userid IN (CASE WHEN #personNumber = 'null'
THEN ( SELECT DISTINCT
UserID
FROM Table2 WITH(NOLOCK)
WHERE [Role] = '01')
ELSE #personNumber
END)
AND IGWQ.itemNumber IN (CASE WHEN #itemNumber = 'null'
THEN ( SELECT DISTINCT
itemNumber
FROM dbo.Table1 WITH(NOLOCK))
ELSE #itemNumber
END)
Can anyone suggest a solution to this problem? I thought using 'IN' would have fixed the issue.
use this to fix the rest:
WHERE ((#personNumber <> 'null' AND #personNumber = IGWQ.userid)
OR (#personNumber = 'null' AND IGWQ.userid IN ( SELECT UserID
FROM Table2 WITH(NOLOCK)
WHERE [Role] = '01')
))
You don't need the DISTINCT as the IN statement only handles distinct values.
WHERE (IGWQ.userid = #personNumber OR
#personNumber = 'NULL' and
EXISTS (SELECT *
FROM Table2 t WITH (NOLOCK)
WHERE t.[Role] = '01' AND t.UserID = IGWQ.userid)
)
AND (IGWQ.itemNumber = #itemNumber OR
#itemNumber = 'NULL' and
EXISTS (SELECT *
FROM dbo.Table1 t WITH (NOLOCK)
WHERE t.itemNumber = IGWQ.itemNumber)
)
Notes:
CASE returns a scalar, it cannot return a subquery (i.e. set).
WITH (NOLOCK) is deprecated. change the connection isolation to READ UNCOMMITTED or SNAPSHOT instead.

SQL how to get an equality comparator on a list of ints

I'm writing an SQL query as follows:
ALTER proc [dbo].[Invoice_GetHomePageInvoices] (
#AreaIdList varchar(max)
, #FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
) as
set nocount on
select *
from Invoice i
left outer join Organisation o on i.OrganisationId = o.Id
left outer join Area a on i.AreaId = a.Id
where i.InvoiceDate BETWEEN #FinancialYearStartDate AND #FinancialYearEndDate
The #AreaIdList parameter is going to be in the format "1,2,3" etc.
I'm wanting to add a line which will only return invoices who have area id equal to any of the ids in #AreaIdList.
I know how to do a statement if it was on areaId to search on ie. where i.AreaId == areaId problem is now I have this list I got to compare for every area Id in #AreaIdList.
Can anybody tell me how you would go about this?
Unpack your ID list to a table and use where AreadID in (select ID from ...)
ALTER proc [dbo].[Invoice_GetHomePageInvoices] (
#AreaIdList varchar(max)
, #FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
) as
set nocount on
set #AreaIdList = #AreaIdList+','
declare #T table(ID int primary key)
while len(#AreaIdList) > 1
begin
insert into #T(ID) values (left(#AreaIdList, charindex(',', #AreaIdList)-1))
set #AreaIdList = stuff(#AreaIdList, 1, charindex(',', #AreaIdList), '')
end
select *
from Invoice i
left outer join Organisation o on i.OrganisationId = o.Id
left outer join Area a on i.AreaId = a.Id
where i.InvoiceDate BETWEEN #FinancialYearStartDate AND #FinancialYearEndDate and
i.AreadID in (select ID from #T)

Resources