SQL Server не позволяет выполнять подзапрос как динамический SQL - PullRequest
0 голосов
/ 15 марта 2012

Я пытался создать динамический SQL, который получает все задачи для некоторых пользователей

Процедура [GetAllSubExecutorsByUserId] возвращает идентификаторы всех подчиненных текущего пользователя. Я записываю эти идентификаторы во временную таблицу, и после этого хочу создать динамический SQL, чтобы получить все задачи из таблицы [tasks], где столбец «Executor» имеет значение IN во этой временной таблице

Запрос, который я написал, следующий:

DECLARE @UserId VARCHAR(10) = 72;

DECLARE @tmp TABLE  ( Id VARCHAR(10));
INSERT @tmp exec [dbo].[GetAllSubExecutorsByUserId] @Source = @UserId;

DECLARE @SQL VARCHAR(max);

SELECT @SQL = 'SELECT * FROM tasks ';
SELECT @SQL = @SQL + 'WHERE Executor IN (' + (select Id from @tmp) + ')';

EXEC(@SQL);

Но когда я его запускаю, выдает ошибку:

Подзапрос возвратил более 1 значения. Это недопустимо, если подзапрос следует =,! =, <, <=,>,> = Или когда подзапрос используется в качестве выражения.

И я не могу понять, как это исправить, потому что, если я запускаю тот же запрос (который не является динамическим SQL, он отлично работает)

запрос, который работает, является статическим:

DECLARE @UserId VARCHAR(10) = 72;

DECLARE @tmp TABLE  ( Id VARCHAR(10));
INSERT @tmp exec [dbo].[GetAllSubExecutorsByUserId] @Source = @UserId;

SELECT * FROM tasks WHERE Executor IN (select Id from @tmp)

Но мне нужен диаминский SQL ... Помогите мне, пожалуйста, решить эту проблему.

Спасибо.

Ответы [ 2 ]

2 голосов
/ 15 марта 2012

Это потому, что вы пытаетесь установить строковое значение из выбора, который возвращает более одного значения.SQL не знает, как превратить этот список в разделенный запятыми.В подготовленном операторе он работает как true IN для возвращенной «таблицы», поэтому он может запускать операторы SET для этой таблицы подзапроса.В динамическом запросе вы, по сути, пытаетесь создать что-то вроде этого, хотя:

...IN (1,2,3)

Вы должны переписать динамический запрос, как показано ниже, чтобы он работал так же, как подготовленный оператор:

'WHERE Executor IN (select Id from @tmp)'

Если вы сделаете это, вам придется передать переменную таблицы в exec, но вам придется использовать sp_executesql .Таким образом, ваш код становится следующим:

DECLARE @UserId VARCHAR(10) = 72;

DECLARE @tmp TABLE  ( Id VARCHAR(10));
INSERT @tmp exec [dbo].[GetAllSubExecutorsByUserId] @Source = @UserId;

DECLARE @SQL VARCHAR(max);

SELECT @SQL = 'SELECT * FROM tasks ';
SELECT @SQL = @SQL + 'WHERE Executor IN (select Id from @tmp)';

DECLARE @SQLParamSetup VARCHAR(150);
SET @SQLParamSetup = '@tmp TABLE  ( Id VARCHAR(10))'


EXEC sp_executesql @SQL, @SQLParamSetup, @tmp ;

Однако, другой, более понятный вариант будет использовать временную таблицу (не переменную), поскольку она будет сохраняться в течение всего вашего соединения (даже вдочерние запросы)

DECLARE @UserId VARCHAR(10) = 72;

CREATE TABLE #tmp  ( Id VARCHAR(10));
INSERT INTO #tmp exec [dbo].[GetAllSubExecutorsByUserId] @Source = @UserId;

DECLARE @SQL VARCHAR(max);

SELECT @SQL = 'SELECT * FROM tasks ';
SELECT @SQL = @SQL + 'WHERE Executor IN (select Id from #tmp)';

EXEC @SQL ;
0 голосов
/ 15 марта 2012

Используйте sp_executesql , и вы можете передать параметр.

...