SQL根据值优先的列取结果
SQL to fetch the result on the basis of the column value with value having the priorities
我正在尝试编写 SQL 以获得以下结果:
规则:
- 按计划类型优先 (STO->MTO->LTO)
- 针对多个 PlanType 可以存在相同的 taskIds
- 获取所有 PlanType 为 STO 的 taskId。
- 获取所有具有 PlanType AS MTO 的 taskId,这些 taskId 不存在于 PlanType AS STO 中。
- 获取所有带有 PlanType AS LTO 的 taskId,这些 taskId 不存在于 PlanType AS MTO 中。
下面是DDL/import SQL:
CREATE TABLE FTASK (
id INT PRIMARY KEY,
taskId VARCHAR2 (100) NOT NULL,
PLANTYPE VARCHAR2 (100)
);
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (1,'T1','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (2,'T2','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (3,'T3','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (4,'T4','MTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (5,'T5','MTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (6,'T2','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (7,'T1','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (8,'T5','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (9,'T3','MTO');
期待以下结果:
我尝试使用 UNION 和 INTERSECT。
提前致谢。
一种方法使用 row_number()
。您的类型按字母顺序排列,因此可以使用该事实:
select t.*
from (select t.*,
row_number() over (partition by taskid order by plantype desc) as seqnum
from ftask t
) t
where seqnum = 1;
如果在实际问题中类型不是字母顺序的,您可以修改 order by
以使用 case
表达式。但是,上面可以使用 (taskid, plantype desc)
.
上的索引
以上允许您获取所有列。如果你只有这三列,你也可以很容易地使用聚合:
select max(id) keep (dense_rank first order by plantype desc) as id,
taskid,
max(plantype) as plantype
from ftask
group by taskid;
keep
语法是 Oracle 实现“第一个”聚合函数的(相当冗长的)方式。
Here 是一个 db<>fiddle.
您可以使用 Gordon 的答案,或者您也可以使用具有适当 CASE
表达式的行号
WITH cte AS (
SELECT f.*, ROW_NUMBER() OVER (PARTITION BY TASKID
ORDER BY CASE PLANTYPE WHEN 'LTO' THEN 1
WHEN 'MTO' THEN 2
WHEN 'STO' THEN 3 END DESC) rn
FROM FTASK f
)
SELECT ID, TASKID, PLANTYPE
FROM cte
WHERE rn = 1;
试试这个。我认为它非常适合你。
从在线尝试:http://sqlfiddle.com/#!4/7b597/1
SELECT id, TASKID, PLANTYPE
FROM (SELECT id,
TASKID,
PLANTYPE,
CASE
WHEN PLANTYPE = 'STO' THEN 1
WHEN PLANTYPE = 'MTO' THEN 2
WHEN PLANTYPE = 'LTO' THEN 3
END
order_by
FROM (SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'STO'
UNION ALL
SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'MTO'
AND TASKID NOT IN (SELECT TASKID
FROM FTASK
WHERE PLANTYPE = 'STO')
UNION ALL
SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'LTO'
AND TASKID NOT IN (SELECT TASKID
FROM FTASK
WHERE PLANTYPE = 'MTO')))
ORDER BY order_by, TASKID;
我正在尝试编写 SQL 以获得以下结果:
规则:
- 按计划类型优先 (STO->MTO->LTO)
- 针对多个 PlanType 可以存在相同的 taskIds
- 获取所有 PlanType 为 STO 的 taskId。
- 获取所有具有 PlanType AS MTO 的 taskId,这些 taskId 不存在于 PlanType AS STO 中。
- 获取所有带有 PlanType AS LTO 的 taskId,这些 taskId 不存在于 PlanType AS MTO 中。
下面是DDL/import SQL:
CREATE TABLE FTASK (
id INT PRIMARY KEY,
taskId VARCHAR2 (100) NOT NULL,
PLANTYPE VARCHAR2 (100)
);
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (1,'T1','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (2,'T2','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (3,'T3','STO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (4,'T4','MTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (5,'T5','MTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (6,'T2','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (7,'T1','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (8,'T5','LTO');
INSERT INTO FTASK (ID,TASKID,PLANTYPE) VALUES (9,'T3','MTO');
期待以下结果:
我尝试使用 UNION 和 INTERSECT。 提前致谢。
一种方法使用 row_number()
。您的类型按字母顺序排列,因此可以使用该事实:
select t.*
from (select t.*,
row_number() over (partition by taskid order by plantype desc) as seqnum
from ftask t
) t
where seqnum = 1;
如果在实际问题中类型不是字母顺序的,您可以修改 order by
以使用 case
表达式。但是,上面可以使用 (taskid, plantype desc)
.
以上允许您获取所有列。如果你只有这三列,你也可以很容易地使用聚合:
select max(id) keep (dense_rank first order by plantype desc) as id,
taskid,
max(plantype) as plantype
from ftask
group by taskid;
keep
语法是 Oracle 实现“第一个”聚合函数的(相当冗长的)方式。
Here 是一个 db<>fiddle.
您可以使用 Gordon 的答案,或者您也可以使用具有适当 CASE
表达式的行号
WITH cte AS (
SELECT f.*, ROW_NUMBER() OVER (PARTITION BY TASKID
ORDER BY CASE PLANTYPE WHEN 'LTO' THEN 1
WHEN 'MTO' THEN 2
WHEN 'STO' THEN 3 END DESC) rn
FROM FTASK f
)
SELECT ID, TASKID, PLANTYPE
FROM cte
WHERE rn = 1;
试试这个。我认为它非常适合你。
从在线尝试:http://sqlfiddle.com/#!4/7b597/1
SELECT id, TASKID, PLANTYPE
FROM (SELECT id,
TASKID,
PLANTYPE,
CASE
WHEN PLANTYPE = 'STO' THEN 1
WHEN PLANTYPE = 'MTO' THEN 2
WHEN PLANTYPE = 'LTO' THEN 3
END
order_by
FROM (SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'STO'
UNION ALL
SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'MTO'
AND TASKID NOT IN (SELECT TASKID
FROM FTASK
WHERE PLANTYPE = 'STO')
UNION ALL
SELECT id, TASKID, PLANTYPE
FROM FTASK
WHERE PLANTYPE = 'LTO'
AND TASKID NOT IN (SELECT TASKID
FROM FTASK
WHERE PLANTYPE = 'MTO')))
ORDER BY order_by, TASKID;