Использование параметра where sub select в основной инструкции выбора открытого запроса

#sql #sql-server #tsql

Вопрос:

Я пытаюсь использовать таблицу SQL server в открытом запросе к базе данных Oracle с использованием связанного сервера.

Мой код выглядит следующим образом.

 select *  INTO #customer from openquery(  [Linkedserver],  'select   *   from  customer c  left join customer_contact cc ON c.main_contact_id = cc.contact_id  where   c.customer_account in ('   (select customer_id from [database].[dbo].   [ChangeCustomers])  ')   '  )  SELECT  * FROM   #customer   

Однако ошибка, которую я получаю, заключается в

Msg 102, Уровень 15, Состояние 1, Проверка клиента процедуры, Строка 24 [Строка Запуска пакета 7] Неправильный синтаксис рядом с» «. Msg 102, Уровень 15, Состояние 1, Проверка клиента процедуры, Строка 24 [Строка Запуска пакета 7] Неправильный синтаксис рядом с» «.

Любая помощь будет признательна.

Комментарии:

1.Запрос OPENQUERY должен быть буквальным. Вы должны использовать динамический SQL, и ввести списка поддержки кодов безопасно в заявление, хотя вы не сможете использовать SELECT...INTO потом, но я не уверен, почему вы используете это (и если список длинный, это может иметь очень плохую работу или даже привести к сбою запроса) или поставить WHERE вне связаны запрос, который может означать, что запрос идет медленно из-за объема данных, необходимых для передаться от одного экземпляра к другому.

2. Спасибо @Larnu, я изучу динамический SQL.

Ответ №1:

У вас есть две проблемы

  • Вы не можете использовать OPENQUERY с переменной или выражением. Это должен быть литерал, поэтому вам нужен динамический SQL.
  • Вам нужно объединить подзапрос, иначе он будет ожидать только один результат.
 DECLARE @sql nvarchar(max) = N' select *  INTO #customer from openquery(  [Linkedserver],  ''select   *   from  customer c  left join customer_contact cc ON c.main_contact_id = cc.contact_id  where   c.customer_account in (  '   (  select STRING_AGG(QUOTENAME(QUOTENAME(customer_id, ''''), ''''), ',')  from [database].[dbo].[ChangeCustomers]  )   '  )  ''  );  SELECT  * FROM   #customer; ';  PRINT @sql; --for testing  EXEC sp_executesql @sql;  

Обратите внимание, как OPENQUERY часть дважды экранируется, потому что она динамична в динамике.

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

Комментарии:

1. Обратите внимание, как я уже упоминал в своем комментарии под вопросом, что SELECT...INTO здесь это в значительной степени бессмысленно. Я действительно не вижу пользы от вставки данных в таблицу и их выбора; особенно когда таблица затем будет неявно удалена, когда она выйдет за рамки

2. Именно это я и сказал внизу: я не думаю, что это хорошая идея, но, возможно, OP сделал это из-за другого кода, который они не показывают. «Я не комментирую»-это британский пассивно-агрессивный способ в основном сказать: я даю комментарии, но это не имеет прямого отношения к рассматриваемому вопросу

3. Да, я просто удивлен, что вы просто не удалили временную таблицу из решения полностью.

4. Спасибо, да будет выполнять некоторые преобразования в выводимых данных. @Charlieface единственная проблема, которую я нахожу в данный момент, заключается в том, что string_agg не помещает значения в «» для передачи в Oracle, что затем приводит к сбою идентификатора. Если я попытаюсь выбрать STRING_AGG(concat(«‘,customer_id,»‘),’,’), произойдет сбой в Msg 189, уровень 15, Состояние 1, строка 14. Для функции concat требуется от 2 до 254 аргументов. Msg 137, Уровень 15, Состояние 2, Строка 27 Должна объявить скалярную переменную «@sql». Msg 137, Уровень 15, Состояние 2, Строка 29 Должна объявить скалярную переменную «@sql».

5. Хорошо, изменили, я предположил, что это целые числа. Must declare the scalar variable "@sql" вы получаете, потому что выполняете команды по отдельности, а не в пакетном режиме.