2017-05-19 59 views
0

我有兩個存儲過程,當前選擇從Users (U)其中U有一個預訂匹配一些條件(IsPaid = 1和MonthNo匹配傳遞給存儲過程)。動態IN與SQL

--users(U) -

UserID  Name 
1   John 
2   Bill 
3   Tom 

--Bookings(B) -

BookingID  UserID   MonthNo  IsPaid 
5    1    2   1 
6    1    3   1 
7    1    4   0 
8    2    2   1 
9    2    3   1 
10    2    4   1 
11    3    4   1 

ALTER PROCEDURE FindUsers... 
    @MonthNo 
AS 
    ... 
    WHERE B.IsPaid = 1 AND B.MonthNo = @MonthNo 

所以目前,如果@MonthId = 3,用戶#2和#3返回

我現在需要通過一個列表過程來返回用戶的預訂範圍匹配。即:

ALTER PROCEDURE FindUsers... 
    @MonthNosCsv 
AS 
    ... 
    -- split month numbers somehow, then check whether all matching `Booking` rows match. 

僞代碼....

WHERE ALL(B.IsPaid = 1 AND B.MonthNo IN(CsvSplit(@MonthNoCsv))) 

所以,如果@MonthNoCsv是 '2,3,4',只有用戶2返回,因爲他們已經在2,3個月內支付預訂和4.

這可能在SQL中,還是最好在消費應用程序中進行二次處理?

+0

此鏈接http://www.sommarskog.se/arrays-in-sql-2008.html可能讓你開始 - 但我懷疑它需要技巧的水平超出了你的實施能力。在http://www.sommarskog.se/arrays-in-sql.html – SMor

回答

0

每個人都應該有一個好的分離器。有很多選項可用。然而,我確實提供了我使用的那個。

下面列出兩個選項,第一個是內嵌版本,第二個使用解析函數。兩者都會返回相同的結果。

選項1 - 如果沒有一個解析函數

Declare @MonthNoCsv varchar(50) = '2,3,4' 

;with cte as (
    Select RetSeq = Row_Number() over (Order By (Select null)) 
      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
    From (Select x = Cast('<x>' + replace((Select replace(@MonthNoCsv,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i) 
) 
Select U.* 
from cte M 
Join Bookings B on M.RetVal=B.MonthNo and B.IsPaid=1 
Join Users U on U.UserID=B.UserID 
Group By U.UserID,U.Name 
Having Count(Distinct B.MonthNo)=(Select max(RetSeq) from cte) 

選項2 - 對於parse函數

Declare @MonthNoCsv varchar(50) = '2,3,4' 
;with cte as (
    Select * from [dbo].[udf-Str-Parse](@MonthNoCsv,',') 
) 
Select U.* 
from cte M 
Join Bookings B on M.RetVal=B.MonthNo and B.IsPaid=1 
Join Users U on U.UserID=B.UserID 
Group By U.UserID,U.Name 
Having Count(Distinct B.MonthNo)=(Select max(RetSeq) from cte) 

都返回

UserID Name 
2  Bill 

的UDF如果有興趣

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10)) 
Returns Table 
As 
Return ( 
    Select RetSeq = Row_Number() over (Order By (Select null)) 
      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
    From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i) 
); 
--Thanks Shnugo for making this XML safe 
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ') 
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',') 
+2

上,Erland也使用CSV字符串(這是您開始下載的路徑)進行了更簡單的討論「每個人都應該擁有一個好的分離器」 - 我不同意。我寧願所有人都轉而使用數據類型*設計*來保存多個值(表格,xml,json,如果在2016或更高版本中),而不是繼續亂七八糟的字符串。 –

+0

@Damien_The_Unbeliever很難去爭辯......但是,我相信你必須從超出你的控制範圍的來源消費數據。考慮到這一點,即使MS「加油」,並在2016年添加了Sting_Split() –