SQL: in в хранимой процедуре: как передать значения

Я хочу написать хранимую процедуру SQL Server 2005, которая будет выбирать и возвращать записи пользователя из таблицы пользователей для некоторых пользователей, которые передаются в хранимую процедуру как параметр.

Как это сделать?

Я могу передать идентификаторы пользователя в виде строки, разделенной запятой. Чтобы я мог использовать

select * 
from users 
where userid in (userids)

например.: Я хочу выбрать записи для id 5,6,7,8,9

Как записать хранимую процедуру?

Ответы

Ответ 1

Для SQL Server 2005 проверьте Erland Sommarskog превосходную Массивы и списки в SQL Server 2005, в которой показаны некоторые методы, как справляться со списками и массивов в SQL Server 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)

Подробнее здесь.

Марк

Ответ 2

Просто используйте его, как это будет работать

Create procedure sp_DoctorList 
@userid varchar(100)
as 
begin
exec ('select * from doctor where userid in ( '+ @userid +' )')
end

Ответ 3

вы можете использовать динамический 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

Ответ 4

см. мой предыдущий ответ на этот вопрос

это лучший источник:

http://www.sommarskog.se/arrays-in-sql.html

создайте функцию разделения и используйте ее как:

SELECT
    *
    FROM YourTable  y
    INNER JOIN dbo.splitFunction(@Parameter) s ON y.ID=s.Value

Я предпочитаю подход с числовой таблицей

Чтобы этот метод работал, вам нужно выполнить эту настройку в один раз:

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 в процедуру и обработать только строки для заданных идентификаторов:

SELECT
    y.*
    FROM YourTable y
        INNER JOIN dbo.FN_ListToTable(',',@GivenCSV) s ON y.ID=s.ListValue

Ответ 5

Предполагая T-SQL, вы можете использовать эту приятную функцию (которая возвращает таблицу).

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') )

Вы можете изменить сохраненную функцию, чтобы работать с разделенными запятыми строками вместо разделенных пробелами.

Если вы не хотите/не можете использовать сохраненную функцию, вы можете включить ее код в хранимую процедуру там, где это необходимо.

EDIT: это невероятно более результативно, чем конкатенация строк.

Ответ 6

попробуйте это, это работает для меня

DECLARE @InClause NVARCHAR(100)
SET @InClause = 'tom,dick,harry'
DECLARE @SafeInClause NVARCHAR(100)
SET @SafeInClause = ',' + @InClause + ',' 
SELECT * FROM myTable WHERE PATINDEX(',' + myColumn + ',', @SafeInClause) > 0

Ответ 7

Вы также можете использовать Find_IN_SET вместо IN. См. Запрос ниже

create procedure myproc(IN in_user_ids varchar(100)) 
begin
   select * from users where FIND_IN_SET(userid, in_user_ids);
end