Оракул делает соединение один к одному

#oracle #join #oracle11g

Вопрос:

Я хочу, чтобы один ко многим присоединился из многих ко многим. Два образца таблиц:

производство:

приказ ПРОИЗВЕДЕНО_СЧЕТ PRODUCT_ID
Заказ1 1000 ProductID1
Заказ1 1000 ProductID1
Заказ1 5000 ProductID2

заказы:

приказ СУММА, ПОДЛЕЖАЩАЯ ПРОИЗВОДСТВУ продукт PRODUCT_ID
Заказ1 600 Продукт 1 — примечание 1 ProductID1
Заказ1 600 Продукт 1 — примечание 2 ProductID1
Заказ1 600 Продукт 1 — примечание 3 ProductID1
Заказ1 5000 Продукт 2 ProductID2

Если я напишу примерный запрос, например

 SELECT ORDERS.ORDER, ORDER.AMOUNT_TO_PRODUCE, SUM(PRODUCTION.PRODUCED_AMOUNT), ORDERS.PRODUCT
FROM ORDERS JOIN PRODUCTION ON ORDERS.PRODUCT_ID = PRODUCTION.PRODUCT_ID
GROUP BY ORDERS.ORDER, ORDER.AMOUNT_TO_PRODUCE, ORDERS.PRODUCT
 

Я получаю

приказ СУММА, ПОДЛЕЖАЩАЯ ПРОИЗВОДСТВУ ПРОИЗВЕДЕНО_СЧЕТ продукт
Заказ1 600 2000 Продукт 1 — примечание 1
Заказ1 600 2000 Продукт 1 — примечание 2
Заказ1 600 2000 Продукт 1 — примечание 3
Заказ1 5000 5000 Продукт 2

Но я хочу

приказ СУММА, ПОДЛЕЖАЩАЯ ПРОИЗВОДСТВУ ПРОИЗВЕДЕНО_СЧЕТ продукт
Заказ1 600 2000 Продукт 1 — примечание 1
Заказ1 600 0 Продукт 1 — примечание 2
Заказ1 600 0 Продукт 1 — примечание 3
Заказ1 5000 5000 Продукт 2

Ответ №1:

Похоже, вы хотите найти общую произведенную сумму и соединить ее с первой строкой в таблице заказов для каждого заказа и идентификатора продукта. Если это так, вам следует:

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

Вы можете сделать это вот так:

 WITH production AS (SELECT 'Order1' order_num, 1000 produced_amount, 'ProductID1' product_id FROM dual UNION ALL
                    SELECT 'Order1' order_num, 1000 produced_amount, 'ProductID1' product_id FROM dual UNION ALL
                    SELECT 'Order1' order_num, 5000 produced_amount, 'ProductID2' product_id FROM dual),
         orders AS (SELECT 'Order1' order_num, 600 amount_to_produce, 'Product1 - note1' product, 'ProductID1' product_id FROM dual UNION ALL
                    SELECT 'Order1' order_num, 600 amount_to_produce, 'Product1 - note2' product, 'ProductID1' product_id FROM dual UNION ALL
                    SELECT 'Order1' order_num, 600 amount_to_produce, 'Product1 - note3' product, 'ProductID1' product_id FROM dual UNION ALL
                    SELECT 'Order1' order_num, 5000 amount_to_produce, 'Product2' product, 'ProductID2' product_id FROM dual),
    -- end of mimicking your tables; main query below
    prdctn_amts AS (SELECT order_num,
                           SUM(produced_amount) total_produced_amount,
                           product_id
                    FROM   production
                    GROUP BY order_num,
                             product_id),
     order_dets AS (SELECT order_num,
                           amount_to_produce,
                           product,
                           product_id,
                           row_number () OVER (PARTITION BY order_num, product_id ORDER BY product) rn
                    FROM   orders)
SELECT o.order_num,
       o.amount_to_produce,
       NVL(p.total_produced_amount, 0)
       total_produced_amount,
       o.product
FROM   order_dets o
       LEFT OUTER JOIN prdctn_amts p ON o.order_num = p.order_num
                                        AND o.product_id = p.product_id
                                        AND o.rn = 1
ORDER BY o.order_num,
         o.product_id,
         o.rn;
 

что приводит к следующему результату:

 ORDER_NUM AMOUNT_TO_PRODUCE TOTAL_PRODUCED_AMOUNT PRODUCT
--------- ----------------- --------------------- ----------------
Order1                  600                  2000 Product1 - note1
Order1                  600                     0 Product1 - note2
Order1                  600                     0 Product1 - note3
Order1                 5000                  5000 Product2
 

N. B. Вам не понадобились бы первые два подзапроса в предложении with; Я добавил их, чтобы я мог имитировать ваши две таблицы, в то время как вы просто ссылались бы на две таблицы напрямую. Кроме того, как ORDER зарезервированное слово в Oracle, я избежал необходимости использовать " для инкапсуляции имя столбца каждый раз, когда мне нужно было ссылаться на него, изменив имя столбца на ORDER_NUM .

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

1. Что именно делает имитация таблиц? Требуется ли это? Я подумал, что мне понадобится аналогичный подход. Спасибо!

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

3. О, мне очень жаль. Я неправильно прочитал последний абзац. Мне было интересно, почему многие люди используют это в ответах. Классно!