#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:
Похоже, вы хотите найти общую произведенную сумму и соединить ее с первой строкой в таблице заказов для каждого заказа и идентификатора продукта. Если это так, вам следует:
- суммируйте производственные строки перед их объединением
- определите первую строку в таблице заказов для каждого заказа и идентификатор продукта, что можно сделать с помощью
row_number()
аналитической функции - соедините оба вместе, что приведет к внешнему соединению суммированных производственных строк с таблицей заказов
Вы можете сделать это вот так:
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. О, мне очень жаль. Я неправильно прочитал последний абзац. Мне было интересно, почему многие люди используют это в ответах. Классно!