根据订单合并多行

时间:2016-03-08 11:54:34

标签: sql psql

假设有以下行

| Id | MachineName | WorkerName | MachineState |
|----------------------------------------------|
| 1  | Alpha       | Young      |  RUNNING     |
| 1  | Beta        |            |  STOPPED     |
| 1  | Gamma       | Foo        |  READY       |
| 1  | Zeta        | Zatta      |              |
| 2  | Guu         | Niim       |  RUNNING     |
| 2  | Yuu         | Jaam       |  STOPPED     |
| 2  | Nuu         |            |  READY       |
| 2  | Faah        | Siim       |              |
| 3  | Iem         |            |  RUNNING     |
| 3  | Nyt         | Fish       |  READY       |
| 3  | Qwe         | Siim       |              |

我们希望根据以下优先级合并这些行:

STOPPED>跑步>准备> (null或空)

如果某行具有最高优先级的值,则应使用该行的值(仅当该行不为空时)。如果为null,则应使用来自任何其他行的值。行应按id

分组

上述输入的正确输出为:

| Id | MachineName | WorkerName | MachineState |
|----------------------------------------------|
| 1  | Beta        | Foo        |  STOPPED     |
| 2  | Yuu         | Jaam       |  STOPPED     |
| 3  | Iem         | Fish       |  RUNNING     |

什么是一个很好的SQL查询来完成这个?我尝试使用连接,但它没有用完。

3 个答案:

答案 0 :(得分:1)

这是优先级查询。一种方法使用变量。另一个使用union all。 。 。如果对于给定的id不重复状态,则此方法有效:

select t.*
from table t
where machinestate = 'STOPPED'
union all
select t.*
from table t
where machinestate = 'RUNNING' and
      not exists (select 1 from table t2 where t2.id = t.id and t2.machinestate in ('STOPPED'))
union all
select t.*
from table t
where machinestate = 'READY' and
      not exists (select 1 from table t2 where t2.id = t.id and t2.machinestate in ('STOPPED', 'RUNNING'));

答案 1 :(得分:1)

如果您可以通过>>> from itertools import takewhile >>> input = '123abc456def' >>> ''.join(takewhile(str.isdigit, input)) '123' 列获得合适的排序,则可以将此视为分组最大问题的一种情况。使用CASE表达式:

MachineState

sqlfiddle上看到它:

| id | machinename | workername | machinestate |
|----|-------------|------------|--------------|
|  1 |        Beta |        Foo |      STOPPED |
|  2 |         Yuu |       Jaam |      STOPPED |
|  3 |         Iem |       Fish |      RUNNING |

如果SELECT a.Id, COALESCE(a.MachineName, t.MachineName) MachineName, COALESCE(a.WorkerName , t.WorkerName ) WorkerName, a.MachineState FROM myTable a JOIN ( SELECT Id, MIN(MachineName) AS MachineName, MIN(WorkerName ) AS WorkerName, MAX(CASE MachineState WHEN 'READY' THEN 1 WHEN 'RUNNING' THEN 2 WHEN 'STOPPED' THEN 3 END) AS MachineState FROM myTable GROUP BY Id ) t ON t.Id = a.Id AND t.MachineState = CASE a.MachineState WHEN 'READY' THEN 1 WHEN 'RUNNING' THEN 2 WHEN 'STOPPED' THEN 3 END ENUM类型列(按适当的顺序定义),您可以省去使用CASE的痛苦。在这种情况下会发生这样的情况:对字符串值进行简单的字典排序会产生相同的结果,但这是你不应该依赖的巧合,因为它必然会在雷达下滑动当有人试图在将来维护此代码时。

答案 2 :(得分:0)

将MachineState更改为枚举:

`MachineState` enum('READY','RUNNING','STOPPED') DEFAULT NULL

和sql很简单:

select t.id,state.machinename,state.workername,t.mstate from state,(select id,max(MachineState) mstate from state group by Id) t  where t.mstate=state.machinestate and t.id=state.id;