我想按聚合值对数据进行排序,然后按其他字段对数据进行排序,然后按非聚合值进行排序。
我有以下架构:
CREATE TABLE priority_t (
id NUMERIC(10),
priority NUMERIC(10),
CONSTRAINT priority_t_pk PRIMARY KEY (id)
);
CREATE TABLE value_t (
id NUMERIC(10),
value NUMERIC(10),
CONSTRAINT value_t_pk PRIMARY KEY (id)
);
CREATE TABLE file_t (
id NUMERIC(10),
CONSTRAINT file_t_pk PRIMARY KEY (id)
);
CREATE TABLE main_t (
id NUMERIC(10),
priority_id NUMERIC(10),
value_id NUMERIC(10),
file_id NUMERIC(10),
CONSTRAINT main_t_pk PRIMARY KEY (id),
CONSTRAINT priority_t_fk FOREIGN KEY (priority_id) REFERENCES priority_t(id),
CONSTRAINT value_t_fk FOREIGN KEY (value_id) REFERENCES value_t(id),
CONSTRAINT file_t_fk FOREIGN KEY (file_id) REFERENCES file_t(id)
);
然后我插入以下数据:
INSERT INTO priority_t (id, priority) VALUES (1, 10);
INSERT INTO priority_t (id, priority) VALUES (2, 20);
INSERT INTO value_t (id, value) VALUES (1, 987);
INSERT INTO value_t (id, value) VALUES (2, 876);
INSERT INTO value_t (id, value) VALUES (3, 765);
INSERT INTO value_t (id, value) VALUES (4, 654);
INSERT INTO file_t (id) VALUES (111);
INSERT INTO file_t (id) VALUES (222);
INSERT INTO file_t (id) VALUES (333);
INSERT INTO file_t (id) VALUES (444);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (1, 1, 1, 111);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (2, 2, 1, 111);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (3, 2, 2, 222);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (4, 1, 2, 333);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (5, 2, 3, 111);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (6, 1, 4, 444);
INSERT INTO main_t (id, priority_id, value_id, file_id) VALUES (7, 2, 4, 444);
COMMIT;
我希望得到以下结果:
min_priority | priority | value | value_id | file_id
(hidden) | | | (hidden) |
--------------+----------+-------+----------+---------
10 | 10 | 654 | 4 | 444
10 | 20 | 654 | 4 | 444
10 | 10 | 876 | 2 | 333
10 | 10 | 987 | 1 | 111
10 | 20 | 987 | 1 | 111
20 | 20 | 765 | 3 | 111
20 | 20 | 876 | 2 | 222
我知道如何对它们进行排序:
ORDER BY min_value ASC, value ASC, value_id ASC, priority ASC
但我的问题是我不知道如何对值本身进行分组:我的行和/或值都不断重复。
我最接近的尝试如下:
WITH listing AS (
SELECT m.id AS main_id,
p.id AS priority_id,
p.priority AS priority,
v.id AS value_id,
v.value AS value,
f.id AS file_id
FROM main_t m
INNER JOIN priority_t p ON m.priority_id = p.id
INNER JOIN value_t v ON m.value_id = v.id
INNER JOIN file_t f ON m.file_id = f.id
)
SELECT min_p.min_priority AS min_priority,
listing.priority AS priority,
listing.value AS value,
listing.file_id AS file_id
FROM listing,
(
SELECT min(min_p_value.min_priority) AS min_priority,
min_p_value.value_id AS min_value_id,
listing.file_id AS file_id
FROM listing,
(
SELECT min(listing.priority) AS min_priority,
listing.value AS value,
listing.value_id AS value_id
FROM listing
GROUP BY listing.value, listing.value_id
) min_p_value
WHERE listing.value = min_p_value.value
AND listing.value_id = min_p_value.value_id
AND min_p_value.min_priority = min_priority
GROUP BY min_p_value.value_id, listing.file_id
) min_p
WHERE min_p.min_value_id = listing.value_id
AND min_p.file_id = listing.file_id
ORDER BY min_p.min_priority ASC,
listing.value ASC,
listing.value_id ASC,
listing.priority;
这会返回以下错误结果:
MIN_PRIORITY PRIORITY VALUE FILE_ID
------------- ---------- ---------- ----------
10 10 654 444
10 20 654 444
10 10 876 333
10 20 876 222 <-- incorrect, should have a min_priority of 20, and therefore be the last
10 10 987 111
10 20 987 111
20 20 765 111
我如何实现我的期望?
答案 0 :(得分:1)
这应该有效:
select (select min(priority)
from main_t mm
join priority_t tt
on tt.id = mm.priority_id
where mm.value_id = m.value_id) as min_priority,
p.priority as priority,
v.value as value,
m.value_id,
m.file_id
from main_t m
join priority_t p
on p.id = m.priority_id
join value_t v
on v.id = m.value_id
order by 1, 3, 4, 2;
它通过value_id确定最低优先级。 您可以按列号按顺序订购结果。
答案 1 :(得分:0)
我已经在MySQL(而不是Oracle)中编写了这段代码并且不确定CTE语法,所以我用一个名为min_priority的临时表替换了WITH子句,但你当然可以用CTE替换临时表。当我在MySQl上运行它时,我得到了你想要的相同结果。
还不确定你是否需要左连接或内连接,这两个都适用于这个例子。
-- find min priority for each value
create temporary table if not exists min_priority as (
select m.value_id, min(p.priority) as min_pri
from main_t m
inner join priority_t p on m.priority_id = p.id
group by m.value_id
);
-- just join all the tables, including min_priority, and order the result
select mp.min_pri, p.priority, v.value, v.id, f.id
from main_t m
left join priority_t p on m.priority_id = p.id
left join value_t v on m.value_id = v.id
left join file_t f on m.file_id = f.id
left join min_priority mp on mp.value_id = v.id
order by mp.min_pri asc, v.value asc, v.id asc, p.priority asc;
作为旁注,我不会使用多级内部查询作为问题中的示例,因为它们会影响性能。
答案 2 :(得分:0)
当您需要汇总和非汇总值时,请使用analytic functions。我想,那会是这样的:
select *
from (select min(p.priority) over (partition by v.id, v.value, f.id) min_priority,
p.priority, v.value, v.id value_id, f.id file_id
from main_t m
join priority_t p on m.priority_id = p.id
join value_t v on m.value_id = v.id
join file_t f on m.file_id = f.id)
order by min_priority, value, value_id, priority
结果:
MIN_PRIORITY PRIORITY VALUE VALUE_ID FILE_ID
------------ ----------- ----------- ----------- -----------
10 10 654 4 444
10 20 654 4 444
10 10 876 2 333
10 10 987 1 111
10 20 987 1 111
20 20 765 3 111
20 20 876 2 222