42

我的查询:

SELECT sites.siteName, sites.siteIP, history.date
FROM sites INNER JOIN
     history ON sites.siteName = history.siteName
ORDER BY siteName,date

输出的第一部分:

在此处输入图像描述

如何删除siteName列中的重复项?我只想根据date列留下更新的内容。

在上面的示例输出中,我需要第 1、3、6、10 行

4

3 回答 3

47

这是窗口函数row_number()派上用场的地方:

SELECT s.siteName, s.siteIP, h.date
FROM sites s INNER JOIN
     (select h.*, row_number() over (partition by siteName order by date desc) as seqnum
      from history h
     ) h
    ON s.siteName = h.siteName and seqnum = 1
ORDER BY s.siteName, h.date
于 2013-07-06T23:09:44.167 回答
8

从您的示例来看,假设该siteIP列由该siteName列确定(即每个站点只有一个siteIP)似乎是合理的。如果确实如此,那么有一个简单的解决方案group by

select
  sites.siteName,
  sites.siteIP,
  max(history.date)
from sites
inner join history on
  sites.siteName=history.siteName
group by
  sites.siteName,
  sites.siteIP
order by
  sites.siteName;

但是,如果我的假设不正确(也就是说,一个站点可能有多个siteIP),那么您的问题并不清楚siteIP您希望查询在第二列中返回哪个。如果只是 any siteIP,那么以下查询将执行:

select
  sites.siteName,
  min(sites.siteIP),
  max(history.date)
from sites
inner join history on
  sites.siteName=history.siteName
group by
  sites.siteName
order by
  sites.siteName;
于 2013-07-07T01:41:32.843 回答
0

我使用这种模式解决了这样的查询:

SELECT *
FROM t
WHERE t.field=(
  SELECT MAX(t.field) 
  FROM t AS t0 
  WHERE t.group_column1=t0.group_column1
    AND t.group_column2=t0.group_column2 ...)

也就是说,它将选择字段值处于最大值的记录。要将其应用于您的查询,我使用了公用表表达式,这样我就不必重复 JOIN 两次:

WITH site_history AS (
  SELECT sites.siteName, sites.siteIP, history.date
  FROM sites
  JOIN history USING (siteName)
)
SELECT *
FROM site_history h
WHERE date=(
  SELECT MAX(date) 
  FROM site_history h0 
  WHERE h.siteName=h0.siteName)
ORDER BY siteName

需要注意的是,它仅在我们计算最大值的字段是唯一的情况下才有效。在您的示例中date,每个字段都应该是唯一的siteName,也就是说,如果 IP 不能每毫秒更改多次。根据我的经验,这通常是这种情况,否则您无论如何都不知道哪条记录是最新的。如果history表有唯一索引(site, date),这个查询也非常快,history可以使用只扫描第一项的表上的索引范围扫描。

于 2020-04-02T15:08:03.657 回答