Объединение данных из таблицы в базе данных Oracle

У меня есть две таблицы, как показано здесь:

Таблица tb_lose:

tb_lose

И таблица tb_profit:

tb_profit

Мне нужно объединить две таблицы и получить такой результат:

результат

Все таблицы, код, я например использую SQL Server. Я хочу реализовать это в базе данных Oracle.

Спасибо!

Я пытаюсь объединить таблицы, используя этот код:

with lose_tmp as
(
    select * from TB_Lose
),
profit_tmp as
(
    select * from TB_Profit
),
tmp_5 as 
(
    select a.Level, a.Lose, a.Name, b.Profit
    from lose_tmp a
    join 
        (select Level, Profit, Name from profit_tmp) b
             on a.Name = b.Name and a.Level = b.Level
    where a.Level = 5
),
tmp_10 as 
(
    select a.Level, a.Lose, a.Name, b.Profit
    from lose_tmp a
    join 
        (select Level, Profit, Name from profit_tmp) b
             on a.Name = b.Name and a.Level = b.Level
    where a.Level = 10
)
select 
    a.Name,
    v5.Lose Lose_5,
    v5.Profit Profit_5,
    v10.Lose Lose_10,
    v10.Profit Profit_10
from 
    lose_tmp a
left join 
    tmp_5 v5 on a.Name = v5.Name and a.Level = v5.Level
left join 
    tmp_10 v10 on a.Name = v10.Name and a.Level = v10.Level

И вот какой результат я получаю:

результат

Добро пожаловать в Stack Overflow. Скрипты для создания таблиц и настройки выборочных данных очень помогли бы, поскольку люди могли бы сами опробовать ваш запрос. Со снимками экрана данных сложно работать, тем более что вы на самом деле не описали точную проблему, с которой столкнулись.

William Robertson 25.05.2024 10:39

Опишите словами, что должен делать запрос. Это: join (select Level, Profit, Name from profit_tmp) b кстати, следует сократить до join profit_tmp b. Нет смысла присоединяться к подзапросу, если подзапрос выбирает все строки из таблицы. Это просто делает запрос менее читабельным.

Thorsten Kettner 25.05.2024 12:08
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
3
53
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Объедините обе таблицы, используя условное агрегирование (выражение CASE внутри функции агрегирования). Затем полное внешнее объединение результатов.

with
  lose_agg as
  (
    select
      l.name,
      sum(case when l.level = 5 then l.lose end) as lose_5,
      sum(case when l.level = 10 then l.lose end) as lose_10
    from tb_lose l
    group by l.name
  ),
  profit_agg as
  (
    select
      p.name,
      sum(case when p.level = 5 then p.profit end) as profit_5,
      sum(case when p.level = 10 then p.profit end) as profit_10
    from tb_profit p
    group by p.name
  )
select name, l.lose_5, p.profit_5, l.lose_10, p.profit_10 
from lose_agg l
full outer join profit_agg p using (name)
order by name;

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

sum(l.lose) filter (where l.level = 5) as lose_5,

SQL Server не поддерживает стандартное предложение SQL USING. В SQL Sever основной запрос должен быть:

select
  coalesce(p.name, l.name) as name,
  l.lose_5,
  p.profit_5,
  l.lose_10,
  p.profit_10
from lose_agg l
full outer join profit_agg p on p.name = l.name
order by coalesce(p.name, l.name);

Это работает как в SQL Server, так и в Oracle.

В Oracle вы можете PIVOT:

SELECT COALESCE(l.name, p.name) AS name,
       l.lose_5,
       p.profit_5,
       l.lose_10,
       p.profit_10
FROM   tb_lose
       PIVOT( SUM(lose) FOR lvl IN (5 AS Lose_5, 10 AS Lose_10) ) l
       FULL OUTER JOIN
       tb_profit
       PIVOT( SUM(profit) FOR lvl IN (5 AS Profit_5, 10 AS Profit_10) ) p
       ON l.name = p.name OR (l.name IS NULL AND p.name IS NULL)

Что для примера данных:

CREATE TABLE tb_lose (name VARCHAR(3), lvl INT, lose INT);
INSERT INTO tb_lose (name, lvl, lose) VALUES ('GOL', 10, 12300);
INSERT INTO tb_lose (name, lvl, lose) VALUES ('USD',  5, 43560);
INSERT INTO tb_lose (name, lvl, lose) VALUES ('AUD', 10, 90430);
INSERT INTO tb_lose (name, lvl, lose) VALUES ('USD', 10, 1200);
INSERT INTO tb_lose (name, lvl, lose) VALUES (NULL,  NULL, NULL);

CREATE TABLE tb_profit (name VARCHAR(3), lvl INT, profit INT);
INSERT INTO tb_profit (name, lvl, profit) VALUES ('GOL', 10, 98000);
INSERT INTO tb_profit (name, lvl, profit) VALUES ('USD', 10, 65000);
INSERT INTO tb_profit (name, lvl, profit) VALUES ('USD',  5, 83700);
INSERT INTO tb_profit (name, lvl, profit) VALUES ('AUD', 10, 38210);
INSERT INTO tb_profit (name, lvl, profit) VALUES (NULL,  NULL, NULL);

Выходы:

ИМЯ ПРОИГРЫШ_5 ПРИБЫЛЬ_5 ПРОИГРЫШ_10 ПРИБЫЛЬ_10 ГОЛ нулевой нулевой 12300 98000 доллар США 43560 83700 12000 65000 австралийский доллар нулевой нулевой 90430 38210 нулевой нулевой нулевой нулевой нулевой

Скрипка Oracle

В SQL Server это аналогично:

SELECT COALESCE(l.name, p.name) AS name,
       l.[5] AS lose_5,
       p.[5] AS profit_5,
       l.[10] AS lose_10,
       p.[10] AS profit_10
FROM   tb_lose
       PIVOT( SUM(lose) FOR lvl IN ([5], [10]) ) l
       FULL OUTER JOIN
       tb_profit
       PIVOT( SUM(profit) FOR lvl IN ([5], [10]) ) p
       ON l.name = p.name OR (l.name IS NULL AND p.name IS NULL)

Скрипт SQL Server

Оракул:
Один из вариантов сделать это в Oracle — использовать предложение MODEL, где можно обращаться к строкам и столбцам вашего набора данных почти так же, как к ячейкам в листе Excel.
Ниже приведен код, который работает с вашим примером данных и с некоторыми добавленными строками (CHF, EUR) в качестве образца для возможности отсутствия совпадающих строк в обеих таблицах (строка только с убытком или только с прибылью):

WITH  --  S a m p l e    D a t a :
    tb_lose ( NAME, LVL, LOSE ) AS 
        ( Select 'GOL', 10, 12300  From Dual Union All
          Select 'USD',  5, 43560  From Dual Union All
          Select 'AUD', 10, 90430  From Dual Union All
          Select 'USD', 10, 1200   From Dual Union All
          Select 'CHF', 5, 2000    From Dual          -- added row
        ), 
    tb_profit ( NAME, LVL, PROFIT ) AS
        ( Select 'GOL', 10, 98000  From Dual Union All
          Select 'USD', 10, 65000  From Dual Union All
          Select 'USD',  5, 83700  From Dual Union All
          Select 'AUD', 10, 38210  From Dual Union All
          Select 'EUR', 10,  3000  From Dual          -- added row
        )

... самый внутренний запрос объединяет данные, которые затем суммируются и моделируются для окончательного агрегирования, удаляя повторяющиеся строки по валютам...

--      S Q L :
SELECT    NAME, 
          Max(LOSE_5) as LOSE_5, Max(PROFIT_5) as PROFIT_5, 
          Max(LOSE_10) as LOSE_10, Max(PROFIT_10) as PROFIT_10
FROM    ( Select  * 
          From    ( Select    NAME, LVL, Sum(LOSE) as LOSE, Sum(PROFIT) as PROFIT,
                              0 as LOSE_5, 0 as PROFIT_5, 0 as LOSE_10, 0 as PROFIT_10
                    From    ( Select NAME, LVL, LOSE, 0 as PROFIT From tb_lose   
                             Union All   
                              Select NAME, LVL, 0, PROFIT From tb_profit 
                            ) c
                    Group By  c.NAME, c.LVL
                    Order By  c.NAME, c.LVL
                  ) 
                  MODEL   Dimension By ( NAME, LVL )
                          Measures ( LOSE, PROFIT, LOSE_5, PROFIT_5, LOSE_10, PROFIT_10 )
                  RULES   ( LOSE_5[ANY, 5] = LOSE[CV(), CV()],   -- CV() is Current Value of the respective dimension
                            PROFIT_5[ANY, 5] = PROFIT[CV(), CV()], 
                            LOSE_10[ANY, 10] = LOSE[CV(), CV()], 
                            PROFIT_10[ANY, 10] = PROFIT[CV(), CV()]
                          )
        )
GROUP BY NAME
ORDER BY NAME
/*
NAME     LOSE_5   PROFIT_5    LOSE_10  PROFIT_10
---- ---------- ---------- ---------- ----------
AUD           0          0      90430      38210
CHF        2000          0          0          0    -- added
EUR           0          0          0       3000    -- added
GOL           0          0      12300      98000
USD       43560      83700       1200      65000   */

Другие вопросы по теме