Есть ли способ указать имя таблицы в виде строки? - PullRequest
6 голосов
/ 29 июля 2011

Допустим, у меня есть запрос, подобный следующему:

SELECT * FROM 
(
  SELECT * FROM 
  (
    SELECT * FROM DB.dbo.Table
  )
  INNER JOIN DB.dbo.Table ON ...

Я выполняю этот запрос несколько раз с разными таблицами, вручную изменяя строку везде.Я попытался объявить следующее:

DECLARE @tablename AS VARCHAR(255)
SET @tablename = 'DB.dbo.Table'

Но это, похоже, не работает, так как выдает ошибку, говорящую, что мне нужно объявить @tablename как переменную таблицы, прежде чем я смогу ее использовать.Как я могу шаблонизировать мое имя таблицы и, если это возможно, Intellisense все еще будет работать?

Ответы [ 3 ]

7 голосов
/ 29 июля 2011

Вы можете заключить его в выражение EXEC, например:

declare @my_tablename nvarchar(100) = 'mytable';
exec('
SELECT * FROM 
(
  SELECT * FROM 
  (
    SELECT * FROM ' + @my_tablename + '
  )
  INNER JOIN ' + @my_tablename + ' ON ...'
);

Но нет, intellisense не будет работать в этом сценарии.

Если вы заранее знаете, как будут выглядеть ваши выходные данные, вы можете объявить временную таблицу для хранения результатов, а затем получить к ней доступ без EXEC. Вы будете иметь intellisense на временную таблицу.

Например:

  --this must match whatever your SELECT is going to return
  CREATE TABLE #results(
    FIELD1 INT
   ,FIELD2 NVARCHAR(100)
   ,FIELD3 BIT
   );

EXEC('
  INSERT INTO #results(field1,field2,field3)
  SELECT FIELD1,FIELD2,FIELD3 FROM ' + @my_tablename
);

select * from #results  --you will have intellisense on #results
4 голосов
/ 29 июля 2011

Нет.Так же, как вы не можете указать имя функции в вашей программе на c # в виде строки.Предполагается, что при компиляции T-SQL будет составлен точный план доступа, то есть, какие индексы нужно открыть и использовать для удовлетворения запроса.Было бы невозможно придумать план для «строки», так же как было бы невозможно в C # сгенерировать код для вызова «строки» в качестве метода.

Решением является динамический SQL:

declare @sql NVARCHAR(MAX) = N'SELECT ... FROM ' +
   quotename(@dbname) + N'.' + quotename(@schema) + N'.' + quotename(@table) + 
   N' WHERE ...';
exec sp_executesql @sql;

... так же, как в C #, вы бы использовали отражение для динамического вызова во время выполнения.

Для получения дополнительной информации см. Проклятие и благословения динамического SQL .

PS.разделение @tablename на компоненты и использование QUOTENAME абсолютно необходимо, оно защищает от SQL-инъекций.Используйте PARSENAME, чтобы разделить вас.

3 голосов
/ 29 июля 2011

Вы используете динамический SQL.Не уверен, почему вам нужно так много вложенных SELECT, но это будет что-то вроде:

DECLARE @sql NVARCHAR(MAX) = N'SELECT ... FROM ' + @tablename + '...';
EXEC sp_executeSQL @sql;

Однако, пожалуйста, помните о внедрении SQL.И нет, IntelliSense не имеет возможности анализировать строку для имен объектов (или даже знать при редактировании, какое имя объекта будет там).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...