Динамический SQL-запрос с разделителями-запятыми
[Обновление: Использование SQL Server 2005]
Привет, что я хочу сделать, это запросить мою хранимую процедуру с разделенным запятыми списком значений (идентификаторов), чтобы получить строки данных.
Проблема, которую я получаю, - ошибка преобразования:
Conversion failed when converting the varchar value ' +
@PassedInIDs + ' to data type int.
Утверждение в моем предложении where и error:
...
AND (database.ID IN (' + @PassedInIDs + '))
Примечание: database.ID имеет тип int.
Я следил за статьей по адресу:
http://www.sql-server-helper.com/functions/comma-delimited-to-table.aspx
но не завершено из-за ошибки.
В моем сценарии выполнения у меня есть:
...
@PassedInIDs= '1,5'
Я что-то здесь не так делаю? Спасибо за помощь.
9 ответов
Я хотел бы создать табличную функцию CLR:
http://msdn.microsoft.com/en-us/library/ms131103.aspx
В нем вы разберете строку на части и выполните преобразование в набор строк. Затем вы можете присоединиться к результатам этой таблицы или использовать IN, чтобы увидеть, есть ли идентификатор в списке.
Например, вы передаете строку в функцию IN в SQL. Если вы оглянетесь на исходную статью, то увидите, что вместо прямого оператора SQL вместо этого создается string
который является оператором SQL для выполнения.
В SQL нет строковой оценки. Это:
database.ID IN (' + @PassedInIDs + ')
не будет обращено к:
database.ID IN (1,2,3)
только потому, что @PassedInIDs
параметр содержит '1,2,3'
, The parameter is not even looked at, because all you have is a string containing " + @PassedInIDs + "
, Syntactically, this is equivalent to:
database.ID IN ('Bob')
To make it short, you can't do what you attempt here in SQL. But there are four other possibilities:
- вы создаете строку SQL на языке вызова и вообще отказываетесь от хранимой процедуры
- вы используете динамический подготовленный оператор с таким количеством параметров в предложении IN, сколько вы собираетесь использовать
- Вы используете фиксированный подготовленный оператор, скажем, с 10 параметрами:
IN (?,?,?,?,?,?,?,?,?,?)
, заполняя столько, сколько вам нужно, устанавливая остальные в NULL - вы создаете хранимую процедуру, скажем, с 10 параметрами и передаете столько, сколько вам нужно, устанавливая остальные в NULL:
IN (@p1, @p2, ..., @p10)
,
Я настоятельно рекомендую вам использовать второй метод из этой ссылки. Создайте пользовательскую функцию, которая превращает вашу строку с разделителями-запятыми в таблицу, которую вы можете легко выбрать.
Если вы используете Google на Erland и "Динамический SQL", у него есть хорошее описание ловушек, которые это влечет за собой.
Вам нужно обращаться с ufn_CSVToTable как с таблицей. Таким образом, вы можете присоединиться к функции:
JOIN ufn_CSVToTable(@PassedInIDs) uf ON database.ID = uf.[String]
Try this:
DECLARE @Ids varchar(50);
SET @Ids = '1,2,3,5,4,6,7,98,234';
SELECT *
FROM sometable
WHERE ','+@Ids+',' LIKE '%,'+CONVERT(VARCHAR(50),tableid)+',%';
Это может быть решено 6 способами, как упомянуто в статье Нараяны. Передача списка / массива в хранимую процедуру SQL Server.
И моя самая прямолинейная реализация
объявить @statement nvarchar(256)
set @statement = 'select * from Persons, где Persons.id в (' + @PassedInIDs + ')'
exec sp_executesql @statement
- -
Вот что я нашел и протестировал:
SET QUOTED_IDENTIFIER ON
SET ANSI_NULLS ON
GO
CREATE FUNCTION [dbo].[SplitStrings] ( @IDsList VARCHAR(MAX) )
RETURNS @IDsTable TABLE ( [ID] VARCHAR(MAX) )
AS
BEGIN
DECLARE @ID VARCHAR(MAX)
DECLARE @Pos VARCHAR(MAX)
SET @IDsList = LTRIM(RTRIM(@IDsList)) + ','
SET @Pos = CHARINDEX(',', @IDsList, 1)
IF REPLACE(@IDsList, ',', '') <> ''
BEGIN
WHILE @Pos > 0
BEGIN
SET @ID = LTRIM(RTRIM(LEFT(@IDsList, @Pos - 1)))
IF @ID <> ''
BEGIN
INSERT INTO @IDsTable
( [ID] )
VALUES ( CAST(@ID AS VARCHAR) )
END
SET @IDsList = RIGHT(@IDsList, LEN(@IDsList) - @Pos)
SET @Pos = CHARINDEX(',', @IDsList, 1)
END
END
RETURN
END
GO
Вот как функция Call:
SELECT * FROM dbo.SplitStrings('123,548,198,547,965')
Я предлагаю использовать XML для этого в SQL 2005. Несколько объемнее, но это может быть проще. Это позволяет вам выбрать XML в таблицу, которую затем можно соединить или вставить и т. Д.
Посмотрите на OPENXML() сервера SQL, если вы еще этого не сделали.
Например, вы можете передать что-то вроде: "12..."
а затем используйте:
exec sp_xml_preparedocument @doc OUTPUT, @xmlParam
SELECT element
FROM OPENXML (@doc, 'Array/Value', 2) WITH (element varchar(max) 'text()')
Это должно быть началом