パラメータとしてストアドプロシージャに渡される一部のユーザーIDについて、ユーザーテーブルからユーザーレコードを選択して返すSQL Server 2005ストアドプロシージャを記述したいと思います。
これを行う方法 ?
ユーザーIDをカンマで区切られた文字列として渡すことができます。使用できるように
select *
from users
where userid in (userids)
例えば。 :id 5、6、7、8、9のレコードを選択したい
ストアドプロシージャの記述方法
SQL Server 2005については、Erland Sommarskogの優れた SQL Server 2005の配列とリスト の記事をご覧ください。SQLServer 2005でリストと配列を処理するいくつかの手法が示されています(SQL Server 2000に関する別の記事もあります) )。
SQL Server 2008にアップグレードできる場合は、「テーブル値パラメーター」と呼ばれる新機能を使用できます。
まず、ユーザー定義のテーブルタイプを作成します
CREATE TYPE dbo.MyUserIDs AS TABLE (UserID INT NOT NULL)
次に、ストアドプロシージャでそのテーブルタイプをパラメーターとして使用します。
CREATE PROC proc_GetUsers @UserIDTable MyUserIDs READONLY
AS
SELECT * FROM dbo.Users
WHERE userid IN (SELECT UserID FROM @UserIDTable)
詳細はこちら こちら 。
マーク
このように使用するだけで機能します
Create procedure sp_DoctorList
@userid varchar(100)
as
begin
exec ('select * from doctor where userid in ( '+ @userid +' )')
end
動的SQLを使用できます。 inステートメントを変数を介してSql SPに渡し、SQLのクエリに連結して、sp_execute sqlを使用して実行します。
create procedure myproc(@clause varchar(100)) as
begin
exec sp_executesql 'select * from users where userid in ( ' + @clause +' )'
end
これは最高の情報源です:
http://www.sommarskog.se/arrays-in-sql.html
分割関数を作成し、次のように使用します。
SELECT
*
FROM YourTable y
INNER JOIN dbo.splitFunction(@Parameter) s ON y.ID=s.Value
この方法を機能させるには、次の1回のタイムテーブル設定を行う必要があります。
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Numbersテーブルを設定したら、次の関数を作成します。
CREATE FUNCTION [dbo].[FN_ListToTable]
(
@SplitOn char(1) --REQUIRED, the character to split the @List string on
,@List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT @SplitOn + @List + @SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = @SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
これで、CSV文字列をテーブルに簡単に分割して結合できます。
select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,')
出力:
ListValue
-----------------------
1
2
3
4
5
6777
(6 row(s) affected)
CSV文字列をプロシージャに渡し、指定されたIDの行のみを処理できます。
SELECT
y.*
FROM YourTable y
INNER JOIN dbo.FN_ListToTable(',',@GivenCSV) s ON y.ID=s.ListValue
T-SQLを想定すると、このNice関数(テーブルを返す)を使用できます。
DROP FUNCTION sp_ConvertStringToTable
GO
CREATE FUNCTION sp_ConvertStringToTable(@list ntext)
RETURNS @tbl TABLE (Position INT IDENTITY(1, 1) NOT NULL,
Value INT NOT NULL) AS
BEGIN
DECLARE @pos int,
@textpos int,
@chunklen smallint,
@str nvarchar(4000),
@tmpstr nvarchar(4000),
@leftover nvarchar(4000)
SET @textpos = 1
SET @leftover = ''
WHILE @textpos <= datalength(@list) / 2
BEGIN
SET @chunklen = 4000 - datalength(@leftover) / 2
SET @tmpstr = ltrim(@leftover + substring(@list, @textpos, @chunklen))
SET @textpos = @textpos + @chunklen
SET @pos = charindex(' ', @tmpstr)
WHILE @pos > 0
BEGIN
SET @str = substring(@tmpstr, 1, @pos - 1)
INSERT @tbl (Value) VALUES(convert(int, @str))
SET @tmpstr = ltrim(substring(@tmpstr, @pos + 1, len(@tmpstr)))
SET @pos = charindex(' ', @tmpstr)
END
SET @leftover = @tmpstr
END
IF ltrim(rtrim(@leftover)) <> ''
INSERT @tbl (Value) VALUES(convert(int, @leftover))
RETURN
END
GO
この方法では:
SELECT * FROM Users
WHERE userid IN
( SELECT Value FROM sp_ConvertStringToTable('1 2 3') )
ストアドファンクションを変更して、スペースで区切られた文字列ではなく、コンマで区切られた文字列を処理できます。
ストアドファンクションが不要/使用できない場合は、必要に応じてストアドプロシージャ内にそのコードを含めることができます。
編集:これは文字列連結よりも信じられないほどパフォーマンスが優れています。
これを試してみてください
DECLARE @InClause NVARCHAR(100)
SET @InClause = 'tom,dick,harry'
DECLARE @SafeInClause NVARCHAR(100)
SET @SafeInClause = ',' + @InClause + ','
SELECT * FROM myTable WHERE PATINDEX(',' + myColumn + ',', @SafeInClause) > 0
早くて汚い.
CREATE PROCEDURE SelectUsers (@UserIds VARCHAR(8000))
AS
SELECT * FROM Users
WHERE userid IN (SELECT CONVERT(VARCHAR(8000), value) FROM STRING_SPLIT(@UserIds, ','))
EXEC SelectUsers @UserIds = 'a1b2,c3d4,e5f6'