这个查询可以优化吗?

时间:2018-09-20 09:34:09

标签: sql postgresql optimization

我的目标是根据相互依赖的两个条件选择记录,并按其他条件对其进行分组。

我找到了按单个条件选择记录并将其分组的解决方案

SELECT *
FROM "records"
NATURAL JOIN (
  SELECT "group", min("priority1") AS "priority1" 
  FROM "records" 
  GROUP BY "group") AS "grouped"

我想我了解这种搜索的概念-选择您关心的属性并在原始表中将其匹配-但是当我将此概念与两个优先级一起使用时,我会得到这个庞然大物

SELECT *
FROM "records"
  NATURAL JOIN (
    SELECT *
    FROM (
      SELECT "group", "priority1", min("priority2") AS "priority2"
      FROM "records"
      GROUP BY "group", "priority1") AS "grouped2"
    NATURAL JOIN (
      SELECT "group", min("priority1") AS "priority1"
      FROM "records"
      NATURAL JOIN (
        SELECT "group", "priority1", min("priority2") AS "priority2"
        FROM "records"
        GROUP BY "group", "priority1") AS "grouped2'"
      GROUP BY "group") AS "GroupNested") AS "grouped1"

我要问的是它写得更好(优化且外观更好)吗?

JSFIDDLE

----更新----

目标是我想为id中的每个group选择一个priority1,并且应该首先选择priority2,然后选择优先级2)。

示例: 当我将表recordsidgrouppriority1priority2一起使用时 包含数据:

id , group , priority1 , priority2
56 ,     1 ,         1 ,         2  
34 ,     1 ,         1 ,         3  
78 ,     1 ,         3 ,         1

结果应为56,1,1,2。对于每个组,首先搜索priority1 min ,然后搜索priority2 min

我尝试将maxmin组合在一起(在一个查询中,但是找不到任何东西(我不再有这个查询了)。

3 个答案:

答案 0 :(得分:1)

EXISTS()来营救! (我做了一些重命名以避免保留字)


SELECT *
FROM zrecords r
WHERE NOT EXISTS (
    SELECT *
    FROM zrecords nx
    WHERE nx.zgroup = r.zgroup
    AND ( nx.priority1 < r.priority1
        OR nx.priority1 = r.priority1 AND nx.priority2 < r.priority2
        )
    );

或者,为了避免使用AND / OR逻辑,请直接比较两个元组:


SELECT *
FROM zrecords r
WHERE NOT EXISTS (
    SELECT *
    FROM zrecords nx
    WHERE nx.zgroup = r.zgroup
    AND (nx.priority1, nx.priority2) < (r.priority1 , r.priority2)
    );

答案 1 :(得分:0)

也许这就是您的期望

 with dat as (
SELECT "group" grp
, priority1, priority2, id
, row_number() over (partition by "group" order by priority1) +
      row_number() over (partition by "group" order by priority2) as lp
FROM "records")

select dt.grp, priority1, priority2, dt.id
from dat dt
join (select min(lp) lpmin, grp from dat group by grp) dt1 on (dt1.lpmin = dt.lp and dt1.grp =dt.grp)

答案 2 :(得分:0)

只需使用row_number()即可。 。 。一次:

select r.*
from (select r.*,
             row_number() over (partition by "group" order by priority1, priority2) as seqnum
      from records r
     ) r
where seqnum = 1;

注意:我建议您避免使用natural join。您可以改用using(如果您不想显式地包含相等比较)。

使用natural join进行的查询很难调试,因为没有列出join键。更糟糕的是,“自然”联接不使用正确声明的外键关系。它们仅取决于具有相同名称的列。

在我设计的表中,它们将永远不会有用,因为几乎所有表都有createdAtcreatedBy列。