У меня есть две таблицы, как показано здесь:
Таблица tb_lose:
И таблица 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
И вот какой результат я получаю:
результат
Опишите словами, что должен делать запрос. Это: join (select Level, Profit, Name from profit_tmp) b кстати, следует сократить до join profit_tmp b. Нет смысла присоединяться к подзапросу, если подзапрос выбирает все строки из таблицы. Это просто делает запрос менее читабельным.


Объедините обе таблицы, используя условное агрегирование (выражение 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);
Выходы:
В 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)
Оракул:
Один из вариантов сделать это в 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 */
Добро пожаловать в Stack Overflow. Скрипты для создания таблиц и настройки выборочных данных очень помогли бы, поскольку люди могли бы сами опробовать ваш запрос. Со снимками экрана данных сложно работать, тем более что вы на самом деле не описали точную проблему, с которой столкнулись.