Как работает левое внешнее объединение на SQl Сервере? - PullRequest
0 голосов
/ 27 февраля 2020

Во-первых: я знаю, что использовать все типы объединения, но Я не знаю, почему это так работает для этого запроса

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

Мои таблицы :

--------------------
   Item 
--------------------
ID      |  Code
--------------------
1       |  7502

SQL > select * from Item where id = 1
---------------------

   Item_Order
---------------------------
Item   |  Box   |   Quantity
---------------------------
1      | 30     |  15000
1      | 12     |  6000
SQL > select * from Item_Order where Item = 1
--------------------------

   Invoice_Item
-------------------
Item  |  Num  |  Quantity
-------------------------
1     | 1.64  | 10
1     | 2.4   | 8
SQL > select * from Invoice_Item where Item = 1

Я хочу этот вывод:

Item  | OrderQ  | OrderB | SellN | SellQ
-----------------------------------------
1     | 1500    | 30     |  1.64 | 10
1     | 6000    | 12     |  2.4  | 8

Мой SQL код:

SELECT  Item.ID, Item_Order.Box As OrderB, Item_Order.Quantity As OrderQ, Invoice_Item.Num As SellN, Invoice_Item.Quantity As SellQ
FROM Item LEFT OUTER JOIN 
     Invoice_Item ON Item.ID = Invoice_Item.Item LEFT OUTER JOIN 
     Item_Order ON Item_Order.Item = Item.ID  
where Item.ID = 1

Out put My Code

Почему мой вывод 2х? или почему мой вывод возвращает 4 записи?

Ответы [ 4 ]

1 голос
/ 27 февраля 2020

Ваш результат может быть достигнут с помощью row_number:

select a.ID
       , a.OrderB
       , a.OrderQ
       , b.Quantity SellQ
       , b.Num SellN
from 
(SELECT Item.ID
       , Item_Order.Box As OrderB
       , Item_Order.Quantity As OrderQ
       , row_number () over (order by Item.ID) rn
FROM Item 
left outer JOIN Item_Order ON Item.ID = Item_Order.Item) a
left outer join (select Item
                        , Num
                        , Quantity
                        , row_number () over (order by Item) rn 
                 from Invoice_Item ) b
on a.ID = b.Item
and a.rn = b.rn

Вот демоверсия

Вы можете добавить больше таблиц, таких как:

left outer join (select Item
                            , Num
                            , Quantity
                            , row_number () over (order by Item) rn 
                     from Invoice_Item ) b
0 голосов
/ 27 февраля 2020

Вы объединяете по одному ключу - две строки с одним и тем же ключом в одной таблице, умноженные на две строки во второй таблице = 4 строки.

Вам нужен отдельный ключ. Вы можете сгенерировать его, используя row_number():

SELECT i.ID, io.Box As OrderB, io.Quantity As OrderQ,
       ii.Num As SellN, ii.Quantity As SellQ
FROM Item i LEFT OUTER JOIN 
     ((SELECT ii.*,
              ROW_NUMBER() OVER (PARTITION BY ii.item ORDER BY ii.item) as seqnum
       FROM Invoice_Item ii
      ) FULL JOIN
      (SELECT io.*, 
              ROW_NUMBER() OVER (PARTITION BY io.item ORDER BY io.item) as seqnum
       FROM Item_Order io
      ) io
      ON io.Item = ii.ID AND io.seqnum = ii.seqnum
     )
     ON i. = ii.Item 
where i.ID = 1;

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

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

0 голосов
/ 27 февраля 2020

Поскольку при первом присоединении Item к Item_Order выводятся две записи, поскольку в Item_Order есть две записи. Теперь этот результирующий запрос будет объединен с Invoice_Item, а две записи будут объединены со всеми записями Invoice_Item

. Вы можете лучше понять это следующим образом:

SELECT  Item.ID, Item_Order.Box As OrderB, Item_Order.Quantity As OrderQ, Invoice_Item.Num As SellN, Invoice_Item.Quantity As SellQ
FROM Item LEFT OUTER JOIN 
Invoice_Item ON Item.ID = Invoice_Item.Item LEFT OUTER JOIN 
where Item.ID = 1 into table4 //Only to explain

Теперь результат первого запроса table4 будет объединен с Items_Order

0 голосов
/ 27 февраля 2020

Это дублирование, потому что у вас нет вторичной связи между Invoice_Item и Item_Order. Для каждой записи в Invoice_Item она соответствует Item_Order (известному как декартовой результат), основываясь ТОЛЬКО на ID элемента. Таким образом, ваш заказ qty, по-видимому, будет ссылкой 1: 1, так что первый элемент Qty of Invoice из 10 MEANT будет связан с Item_Order Box = 30. и Qty 8 будет MEANT быть связанным с Item_Order Box = 12.

Item_Order
Item   Box   Quantity
1      30    15000
1      12    6000


Invoice_Item
Item  Num    Quantity
1     1.64   10
1     2.4    8

Вам, вероятно, нужно прикрепить ссылку "Box", чтобы Item_Order и Invoice_Item соответствовали 1: 1.

То, что происходит для каждого элемента в Invoice Item, объединяется с Item_Order на основе на элементе ID. Итак, вы получаете два. Если бы у вас было 3 элемента счета с 1 и 6 из Item_Order, вы бы получили 18 строк.

ОБРАТНАЯ СВЯЗЬ

Даже если у вас есть принятый ответ, основанный на OVER / PARTITION / NOWBER NOWBER, этот процесс принудительно устанавливает суррогатный вторичный идентификатор для каждой строки. Полагаться на этот подход не лучше для общей ассоциации структуры данных. Что произойдет, если вы удалите второй элемент в заказе. Вы уверены, что удаляете второй элемент в invoice_items?

Что касается возврата 2 записей в исходном сценарии, вы можете с помощью суррогатного процесса, но я думаю, что было бы лучше для вас в долгосрочной перспективе понять, что происходит на соединении. Возвращаясь к вашим образцам данных Item_Order и Invoice_Item. Итак, давайте начнем с таблицы Item_Order. Движок SQL будет обрабатывать каждую строку индивидуально.

Первая строка SQL захватывает Item = 1, Box = 30, Qty = 15000.

Так что теперь он присоединяется к Invoice Элемент таблицы, и так как ваши критерии он присоединяется только на основе элемента. Итак, он видит первую строку и говорит ... да, это элемент 1, так что включите его с записью порядка элементов (возвращается первая строка). Теперь он переходит ко второй строке таблицы элементов счета-фактуры ... да, это тоже тот же элемент 1, поэтому он возвращает его снова (возвращается вторая строка).

Теперь SQL захватывает вторую Строка Item = 1, Box = 12, Кол-во = 6000.

Возвращается к таблице «Счет-фактура» и выполняет точно такой же тест ... и для каждой строки в Порядке элементов, у которой есть Item = 1, и 3-я и 4-я строки, следовательно, ваше удвоение ... Если бы в любой таблице было больше записей с одинаковым идентификатором элемента, она вернула бы столько же записей ... 3 и 3 записи вернули бы 9 строк. Записи 4 и 4 вернут 16 строк и т. Д. c. Выполнение суррогата будет работать, но я не думаю, что это так безопасно, как улучшенная / обновленная структура дизайна.

...