Вставка SQL из DB1 в DB2 с использованием JOIN в другой таблице и избегание указания имен столбцов

Я искал раньше и не мог найти никаких ответов.

Давайте представим сценарий, в котором у нас есть 2 таблицы:
- Customer
- Order

И 2 базы данных:
- DB1
- DB2

Клиент:

  • ID внутр.
  • Имя varchar

Заказ :

  • ID внутр.
  • идентификатор клиента,

DB1 и DB2 имеют одинаковую структуру таблиц и содержат разные данные.
Теперь предположим, что я хочу выполнить этот запрос:

 INSERT INTO
    DB1.dbo.Order
 SELECT
    ID, CustomerID
 FROM 
    DB2.dbo.Order AS db2Order
    LEFT JOIN
    DB2.dbo.Customer AS db2Cust
 ON 
    db2Order.CustomerID = db2Cust.ID

Этот запрос работает так, как ожидалось. Теперь давайте представим сценарий, в котором у вас есть более 20 столбцов в таблице, и вы не хотите проходить и указывать их все, я хочу сделать что-то вроде этого:

INSERT INTO
    DB1.dbo.Order
 SELECT
 (
    SELECT COLUMN_NAME
    FROM DB1.INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = N'Order'
 )
 FROM 
    DB2.dbo.Order AS db2Order
    LEFT JOIN
    DB2.dbo.Customer AS db2Cust
 ON 
    db2Order.CustomerID = db2Cust.ID

Поскольку мы ПРИСОЕДИНЯЕМ таблицы, мы должны указать столбцы, поскольку они не будут соответствовать структуре таблицы Order, так как мы пытаемся вставить, мы должны удовлетворить это исключение:
Column name or number of supplied values does not match table definition.

Есть ли обходной путь через это? Я был бы рад услышать, если у кого-нибудь есть какие-либо идеи, пожалуйста. Спасибо за ваше время, читая это!


person Community    schedule 27.01.2018    source источник
comment
Зависит от диалекта SQL. Некоторые диалекты поддерживают естественные соединения. Они могут быть опасны, поэтому прежде чем использовать их, подумайте о последствиях, даже если ваш диалект их поддерживает.   -  person Aluan Haddad    schedule 27.01.2018
comment
Привет, Алуан, в таком случае я использую MSSQL. Я на 100% уверен, что они идентичны, просто другая таблица содержит определенные данные, которые мне нужны из старой резервной копии базы данных. Я могу пройти путь вручную, но я скорее узнаю что-то новое и посмотрю, как можно будет пройти этот путь.   -  person    schedule 27.01.2018
comment
Вы имеете в виду T-SQL? Тогда нет, естественные соединения не поддерживаются,   -  person Aluan Haddad    schedule 27.01.2018


Ответы (2)


Благодаря тому, что @GordonLinoff указал мне на динамический SQL, вот мое решение:

DECLARE @CustomerID SMALLINT = 201,
        @ID         SMALLINT = 14007

DECLARE @columns AS NVARCHAR(1500) = '',
        @params  AS NVARCHAR(1000),
        @query   AS NVARCHAR(2000)

SELECT @columns += COLUMN_NAME + ',' FROM DB1.dbo.Order.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'Order'
SELECT @columns = SUBSTRING(@columns, 0, LEN(@columns))

SET @params = '@CustomerID smallint, @ID smallint'
SET @query = 'INSERT INTO 
    DB1.dbo.Order
SELECT
    %s
FROM 
    DB2.dbo.Order AS db2Order
    LEFT JOIN
    DB2.dbo.Customer AS db2Cust
ON 
    db2Order.CustomerID = db2Cust.ID
WHERE 
    db2Order.CustomerID = @CustomerID AND db2Cust.ID = @ID'
EXEC sp_addmessage 50001, 16, @query, NULL, NULL, 'replace'
SET @query = FORMATMESSAGE(50001, @columns)
EXEC sp_executesql @query, @params, @CustomerID=@CustomerID, @ID=@ID

Здесь я использую sp_addmessage, поэтому я могу использовать функцию FORMATMESSAGE, поскольку в версии SQL ‹ 2012 функция formatmessage не поддерживает непосредственное использование строк. Надеюсь, это поможет кому-то!

person Community    schedule 29.01.2018

Сначала при написании вставки перечислите все столбцы. И когда у вас есть более одного столбца в запросе, используйте таблицу alises:

INSERT INTO DB1.dbo.Order(Id, CustomerId)
    SELECT c.ID, c.CustomerID
    FROM DB2.dbo.Order o LEFT JOIN
         DB2.dbo.Customer c
         ON o.CustomerID = c.ID;

Тогда кажется маловероятным, что в этом случае вам нужен INSERT (я имею в виду, что JOIN, вероятно, даже не нужен), но это другой вопрос.

Таблицы и столбцы в SQL-запросе необходимо выбирать явно. Если вы хотите обрабатывать запрос как строку, где вы можете просто заменить части строки, вы можете это сделать. Это называется динамическим SQL, и в SQL Server вы должны выполнить его, используя sp_executesql.

Вместо этого просто запросите базу данных для столбцов и поместите их в запрос самостоятельно. Убедитесь, что вы очень хорошо разбираетесь в SQL, прежде чем изучать динамический SQL.

person Gordon Linoff    schedule 27.01.2018
comment
Спасибо за ответ Гордон. В примере оператора JOIN не используется, но я использую его, когда я устанавливаю условие после. Постарался сделать как можно короче и меньше читать. Теперь, что касается sp_executesql, я кое-что прочитал об этом, но я до сих пор не понимаю, как я мог бы использовать его в конкретном примере, который я привел в исходном сообщении. Я исхожу из опыта ООП, поэтому я пытаюсь пройти этот путь. Интересно, есть ли способ сделать это неявно, а не явно? - person ; 27.01.2018
comment
@ГиладРейх. . . ООП не поможет. Все эти прекрасные абстракции и упрощения, обеспечиваемые объектными моделями, могли быть включены в более чистый язык доступа к базе данных, но они были изобретены позже, а SQL довольно широко распространен. Научитесь делать это с помощью SQL; а затем не применяйте эти уроки к другому программированию. - person Gordon Linoff; 27.01.2018
comment
Я думаю, что я должен был сфокусировать заголовок сообщения на более похожем на: как мне отформатировать SELECT COLUMN_NAME FROM DB1.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'Order', чтобы рассматривать его как строку, чтобы я мог использовать его как подзапрос вместо *. Это вообще возможно? - person ; 27.01.2018
comment
@ГиладРейх. . . Как я утверждаю в этом ответе, это возможно с использованием динамического SQL. Прежде чем изучать динамический SQL, я бы порекомендовал вам иметь прочную основу для SQL-запросов. - person Gordon Linoff; 27.01.2018
comment
Я не минусовал. На самом деле я не могу даже из-за моей репутации в stackoverflow ограничиваться публикацией в определенных темах в качестве ответа, поскольку для этого требуется более 50+. Я проверю больше о динамическом SQL. Спасибо. - person ; 27.01.2018
comment
@ГиладРейх. . . Я знаю, что ты этого не сделал. Я думаю, что это точно отвечает на ваш вопрос, и не понимаю, почему это может вызвать отрицательный голос. - person Gordon Linoff; 27.01.2018
comment
спасибо за ваши советы. Поиграв с динамическими функциями sql, я опубликовал решение. - person ; 29.01.2018