每组最大N,具有JOIN和多个订单列

时间:2018-12-23 06:14:07

标签: sql postgresql

我有两个表:

Table0:
| ID | TYPE | TIME  | SITE |
|----|------|-------|------|
| aa | 1    | 12-18 | 100  |
| aa | 1    | 12-10 | 101  |
| bb | 2    | 12-10 | 102  |
| cc | 1    | 12-09 | 100  |
| cc | 2    | 12-12 | 103  |
| cc | 2    | 12-01 | 109  |
| cc | 1    | 12-07 | 101  |
| dd | 1    | 12-08 | 100  |

Table1:
| ID |
|----|
| aa |
| cc |
| cc |
| dd |
| dd |

我正在尝试将结果输出到以下位置:

  • ID必须同时存在于两个表中。
  • TYPE必须是每个ID的最大值。
  • TIME必须是每个TYPE中最大值ID的最小值。
  • SITE应该与最小TIME值来自同一行。

鉴于我的示例数据,我的结果应如下所示:

| ID | TYPE | TIME  | SITE |
|----|------|-------|------|
| aa | 1    | 12-10 | 101  |
| cc | 2    | 12-01 | 109  |
| dd | 1    | 12-08 | 100  |

我已经尝试过以下语句:

INSERT INTO "NuTable"
SELECT DISTINCT(QTS."ID"), "SITE",
       CASE WHEN MAS.MAB=1 THEN 'B'
            WHEN MAS.MAB=2 THEN 'F'
            ELSE NULL END,
       "TIME"
FROM (SELECT DISTINCT("ID") FROM TABLE1) AS QTS,
     TABLE0 AS MA,
     (SELECT "ID", MAX("TYPE") AS MASTY, MIN("TIME") AS MASTM 
      FROM TABLE0 
      GROUP BY "ID") AS MAS,
WHERE QTS."ID" = MA."ID"
      AND QTS."ID" = MAS."ID"
      AND MSD.MASTY  =MA."TYPE"

...这会产生语法错误

INSERT INTO "NuTable"
SELECT DISTINCT(QTS."ID"), "SITE",
       CASE WHEN MAS.MAB=1 THEN 'B'
            WHEN MAS.MAB=2 THEN 'F'
            ELSE NULL END,
       "TIME"
FROM (SELECT DISTINCT("ID") FROM TABLE1) AS QTS,
     TABLE0 AS MA,
     (SELECT "ID", MAX("TYPE") AS MAB 
      FROM TABLE0 
      GROUP BY "ID") AS MAS,
     ((SELECT "ID", MIN("TIME") AS MACTM, MIN("TYPE") AS MACTY 
       FROM TABLE0 
       WHERE "TYPE" = 1 
       GROUP BY "ID")  
      UNION
      (SELECT "ID", MIN("TIME"), MAX("TYPE") 
       FROM TABLE0 
       WHERE "TYPE" = 2 
       GROUP BY "ID")) AS MACU 
WHERE QTS."ID" = MA."ID"
      AND QTS."ID" = MAS."ID"
      AND MACU."ID" = QTS."ID"
      AND MA."TIME" = MACU.MACTM
      AND MA."TYPE" = MACU.MACTB

...得到错误的结果。

3 个答案:

答案 0 :(得分:1)

回答您的直接问题“如何避免...”:

当您在GROUP BY部分中不存在的语句的SELECT区域中指定一列,并且不属于诸如MAX,MIN,AVG之类的聚合函数时,会出现此错误

在您的数据中,我不能说

SELECT
  ID, site, min(time)
FROM
  table
GROUP BY
  id 

我没有说要怎么处理SITE;它要么是组中的关键(在这种情况下,我将获得ID,网站和每个网站的最短时间的每个唯一组合),或者应该对其进行汇总(例如,每个ID的最大网站)

这些还可以:

SELECT
  ID, max(site), min(time)
FROM
  table
GROUP BY
  id 

SELECT
  ID, site, min(time)
FROM
  table
GROUP BY
  id,site

我不能简单地不指定如何处理它-在这种情况下数据库应该返回什么? (如果您仍在挣扎,请在注释中告诉我您认为数据库应该做什么,我会更好地理解您的想法,以便告诉您为什么它不能这样做)。数据库的程序员无法为您做出此决定;你必须做到

人们通常在想识别以下内容时会问这个问题:

每个ID的最短时间,并获取所有其他行数据。例如:“每个ID的最早的完整记录数据是什么?”

在这种情况下,您必须编写一个查询,以标识每个id的最短时间,然后将该子查询联接回id = id和time = mintime的主数据表。 db运行子查询,构建每个id的最短时间列表,然后有效地成为主数据表的过滤器

SELECT * FROM
(
  SELECT
    ID, min(time) as mintime
  FROM
    table
  GROUP BY
    id
) findmin
INNER JOIN table t ON t.id = findmin.id and t.time = findmin.mintime

您无法做的是开始将所需的其他数据放入进行分组的查询中,因为您要么必须按添加的列进行分组(使分组更加精细,而不是您想要的),或者必须汇总它们(然后不一定与其他汇总列来自同一行-最小时间来自第1行,最小网站来自第3行-而不是您想要的)

查看您的实际问题:

  

ID值必须存在于两个表中。   Type值必须是最大的ID分组。   时间值必须在最大类型组中最小。

暂时没有涉及或具有分析的解决方案,因此您可以在此处掌握理论:

您需要按ID查找最大类型组,然后将其重新连接到表以获取该ID / MAXTYPE的其他相关数据(需要时间),然后在此新过滤的数据集上,您需要id和最短时间

SELECT t.id,min(t.time) FROM
(
  SELECT
    ID, max(type) as maxtype
  FROM
    table
  GROUP BY
    id
) findmax
INNER JOIN table t ON t.id = findmax.id and t.type = findmax.maxtype
GROUP BY t.id

如果您不明白为什么,请告诉我

答案 1 :(得分:1)

demo:db<>fiddle

SELECT DISTINCT ON (t0.id)
    t0.id,
    type,
    time,
    first_value(site) OVER (PARTITION BY t0.id ORDER BY time) as site
FROM table0 t0
JOIN table1 t1 ON t0.id = t1.id
ORDER BY t0.id, type DESC, time
  

ID必须同时存在于两个表中

这可以通过将两个表针对它们的id进行连接来实现。内部联接的结果是两个表中都存在行。

  

SITE应该是与最小TIME值在同一行中的值。

这与"Give me the first value of each group of id s ordered by时间"相同。这可以通过使用first_value() window function来完成。窗口函数可以对您的数据集(PARTITION BY)进行分组。因此,您将获得id个组,可以单独订购。 first_value()给出这些有序组的第一个值。

  

TYPE必须是每个ID中的最大值。

要获取每个id的最大类型,您首先必须ORDER BY id, type DESC。您将在type的第一行中获得最大的id ...

  

TIME必须是每个TYPE中最大值ID的最小值。

...然后,您可以另外通过time对结果进行排序,以确保满足这种条件。

现在您有了一个有序的数据集:对于每个id,具有最大type和最小time的行是第一个。

DISTINCT ON恰好为您提供了每个组的第一行。在这种情况下,您定义的组是(id)。结果就是您预期的结果。

答案 2 :(得分:0)

我会用distinct onin / exists来写:

select distinct on (t0.id) t0.*
from table0 t0
where exists (select 1 from table1 t1 where t1.id = t0.id)
order by t0.id, type desc, time asc;