выбрать из пропущенной таблицы ошибку в подзапросе (после, когда существует в случае) - PullRequest
1 голос
/ 25 марта 2019

** отредактировано для инвертирования логики в тесте EXISTS

Мне нужно выбрать поле из таблицы, которая может не существовать.Мне также нужно сделать это в подзапросе.

Существует инженерный релиз кода, который добавит таблицу в базу данных, которую я очищаю для отчетов.Если таблица существует, выберите поле.Если это не так, дайте общий сбой.

** Да, есть множество примеров того, как использовать EXISTS.Это выходит за рамки тех, которые имеют дело с чем-то, что может не существовать.

Новая версия кода будет развернута на нескольких сайтах, некоторые могут не иметь таблицы сразу, как другие.Мои материалы должны быть готовы к Day Zero - aka: развернуты заранее (день -1?).

Вот мой код (таблицы и столбцы переименованы), который я пытаюсь заставить работать в SQL Server Management Studio.(SQL 2016) (SSMS 17.4)

select 'Cern' as  SiteName, 
(
select 
case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
 then
   (select top 1 isnull(SecurityID,'Not on file') from [ProtonAcceleratorSecurity] with (nolock) )  
 else
   (select 'No Security Table Found')
end  
 as SecurityID 

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

Цель состоит в том, чтобы вернуть имя сайта и первый идентификатор безопасности (случайным образом - не имеет значения - согласованность не требуется) - но только если таблица действительно существует.

Проблема заключается в том, чточто SSMS выдает ошибку, сообщающую, что таблица является недопустимым объектом, который я уже знаю.

"Неверное имя объекта 'ProtonAcceleratorSecurity'"

Окончательный ответ от @TabAlleman с незначительной поправкой:


SET @sql = '
select ''Cern'' as  SiteName, ' +
( select 
    case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
 then
   '(select top 1 isnull(SecurityID,''Not on file'') from [ProtonAcceleratorSecurity] with (nolock) )'
 else
   '''No Security Table Found'''
end  ) 
+ ' as SecurityID ';

EXEC (@sql); ```

Ответы [ 3 ]

2 голосов
/ 25 марта 2019

Причина вашей ошибки в том, что SQL Server проанализирует и скомпилирует весь ваш оператор, прежде чем он выполнит его.Таким образом, ваш запрос не может содержать ссылки на недопустимые объекты, даже если сам запрос проверяет, является ли объект действительным, прежде чем ссылаться на него.Парсер не достаточно умен, чтобы знать, что подзапрос не будет вызван, если объект не существует, поэтому он вообще не позволит выполнить запрос.

Один из способов обмануть парсер:через динамический sql, который не подвергается предварительному анализу:

DECLARE @sql varchar(max);

SET @sql = '
select ''Cern'' as  SiteName, '

+
select 
case when exists (select 1 from sys.tables where name like 'ProtonAcceleratorSecurity')
 then
   '(select top 1 isnull(SecurityID,''Not on file'') from [ProtonAcceleratorSecurity] with (nolock) )'
 else
   '''No Security Table Found'''
end  
+

' as SecurityID 
';

EXEC (@sql);

РЕДАКТИРОВАТЬ, потому что я не тестирую на ходу, а просто чтобы прояснить идею:

Вам нужнопроверьте наличие таблицы во внешнем запросе, но затем создайте только динамический запрос, который использует таблицу, если она существует.Чтобы сделать это по-настоящему простым, игнорируя исходную структуру CASE, вы хотите логически сделать это:

IF EXISTS({SELECT query to test for MyTable})
  @SQL = 'query that references MyTable';
ELSE
  @SQL = 'query that doesn't reference MyTable';

EXECUTE (@SQL);

PS: я думаю, что только что исправил синтаксис в моем первом примере.

0 голосов
/ 26 марта 2019

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

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

IF OBJECT_ID('ProtonAcceleratorSecurity', 'U') IS NULL
  SELECT 'Cern'                    AS SiteName,
         'No Security Table Found' AS SecurityID 
ELSE
  SELECT TOP 1 'Cern' AS SiteName,
               isnull(SecurityID, 'Not on file') AS SecurityID 
  FROM   [ProtonAcceleratorSecurity] WITH (nolock)
  ORDER BY ....
0 голосов
/ 25 марта 2019

Я не думаю, что есть какой-либо способ сделать это в одном запросе. Одно из предложений - скрыть это в виде:

IF OBJECT_ID('ProtonAcceleratorSecurity') IS NULL
BEGIN
    CREATE VIEW ProtonAcceleratorSecurity
        SELECT 'Not on file' as SecurityID
END;

Тогда ваш запрос может работать просто как:

select 'Cern' as SiteName, 
       (select top 1 coalesce(SecurityID, 'Not on file')
        from ProtonAcceleratorSecurity 
       ) as SecurityID 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...