带有CASE的PostgresSQL ORDER BY子句用于已排序的列

时间:2019-03-26 03:10:55

标签: sql postgresql

我有一个简单的SELECT ORDER BY查询形式,它使用CASE创建排序的ID。 我提到了基于https://gist.github.com/cpjolicoeur/3590737的两种方法,并使用了其中一种。

SELECT id FROM tasks t ORDER BY 
CASE 
WHEN t.type = 'TypeA' THEN 1 
WHEN t.type = 'TypeB' THEN 2 
WHEN t.type = 'TypeC' THEN 3 
END, 
CASE 
WHEN t.state = 'Interrupted' THEN 4 
WHEN t.state = 'Terminated' THEN 5 
WHEN t.state = 'Completed' THEN 6
WHEN t.state = 'Killed' THEN 7
WHEN t.state = 'Warning' THEN 8
WHEN t.state = 'Starting' THEN 9
WHEN t.state = 'New' THEN 10
WHEN t.state = 'Running' THEN 11
END, 
modified ASC;

上面的查询是基于以下条件对ID进行排序的:

  1. 具有状态的TypeA: 中断,终止,已完成,已杀死,警告,开始,新建,正在运行
  2. 具有状态的TypeB: 中断,终止,已完成,已杀死,警告,开始,新建,正在运行
  3. TypeC,状态为: 中断,终止,已完成,已杀死,警告,开始,新建,正在运行

我现在需要针对以下排序标准修改此sql:

  1. 状态为:中断,已终止,已完成,已终止的TypeA
  2. 状态为:中断,终止,已完成,已终止的TypeB
  3. 状态为:已中断,已终止的TypeC
  4. 状态为:警告,正在启动,正在新建,正在运行的TypeA
  5. 状态为:警告,正在启动,正在新建,正在运行的TypeB
  6. 状态为:已完成,已杀死,警告,正在启动,新建,正在运行的TypeC

请注意,“状态”(如指定)的顺序在这里对于“类型”同样重要

我正在尝试修改上述sql,使其符合新条件。作为非SQL专家,我正在寻找最有效的方式来重写此sql,这也可能在不久的将来适应排序标准的细微变化。

要在下面进一步阐明共享示例:

样本数据

id  | type  |    state
----+-------+-------------
 1  | TypeC | Completed
 2  | TypeA | Completed
 3  | TypeA | Running
 4  | TypeB | Completed
 5  | TypeB | Running
 6  | TypeC | Terminated
 7  | TypeC | Unknown
 8  | TypeA | Completed
 9  | TypeB | Interrupted
 10 | TypeB | Completed
 11 | TypeB | Interrupted
 12 | TypeC | Killed
 13 | TypeC | Running
 14 | TypeB | Warning
 15 | TypeB | Running
 16 | TypeB | Killed

预期数据

id  | type  |    state
--- +-------+-------------
 1  | TypeA | Completed
 8  | TypeA | Completed
 9  | TypeB | Interrupted
 11 | TypeB | Interrupted
 4  | TypeB | Completed
 10 | TypeB | Completed
 16 | TypeB | Killed
 7  | TypeC | Unknown
 6  | TypeC | Terminated
 3  | TypeA | Running
 14 | TypeB | Warning
 5  | TypeB | Running
 15 | TypeB | Running
 1  | TypeC | Completed
 12 | TypeC | Killed
 13 | TypeC | Running

1 个答案:

答案 0 :(得分:1)

也许是这样吗?

CASE 
WHEN t.type = 'TypeA' AND t.state 
        IN ( 'Interrupted','Terminated','Completed','Killed') 
  THEN 1
WHEN t.type = 'TypeB' AND t.state 
        IN ( 'Interrupted','Terminated','Completed','Killed') 
  THEN 2
..
..

编辑

我建议您创建一个层次结构表,这样可以使查询变得更简单。

CREATE TABLE type_state_hier AS
select *  FROM 
(
 VALUES
(1,'TypeA','Interrupted'),
(2,'TypeA','Terminated'),
(3,'TypeA','Completed'),
(4,'TypeA','Killed'),
(5,'TypeB','Interrupted'),
(6,'TypeB','Terminated'),
(7,'TypeB','Completed'),
(8,'TypeB','Killed'),
(9,'TypeC','Interrupted'),
(10,'TypeC','Terminated'),
(11,'TypeA','Warning'),
(12,'TypeA','Starting'),
(13,'TypeA','New'),
(14,'TypeA','Running'),
(15,'TypeB','Warning'),
(16,'TypeB','Starting'),
(17,'TypeB','New'),
(18,'TypeB','Running'),
(19,'TypeC','Completed'),
(20,'TypeC','Killed'),
(21,'TypeC','Warning'),
(22,'TypeC','Starting'),
(23,'TypeC','New'),
(24,'TypeC','Running')
) As s(rnk,type,state)
;

现在,通过与主表的简单连接对其进行查询。

select t.* from tasks t 
  join type_state_hier h on 
  h.type=t.type and h.state = t.state
order by h.rnk ,t.id

如果您不想创建表,只需将其用作CTE(请参阅演示)

DEMO