我如何(或可以)在多列上selectDISTINCT?

我需要检索表中的所有行,其中2列合并是不同的。 所以我想要所有没有任何其他销售的销售在同一天发生在相同的价格。 基于date和价格的独特销售将被更新为活动状态。

所以我在想:

UPDATE sales SET status = 'ACTIVE' WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id) FROM sales HAVING count = 1) 

但是我的脑子受伤的远比这更远。

 SELECT DISTINCT a,b,c FROM t 

大致相当于:

 SELECT a,b,c FROM t GROUP BY a,b,c 

习惯GROUP BY语法是一个好主意,因为它更强大。

为了您的查询,我会这样做:

 UPDATE sales SET status='ACTIVE' WHERE id IN ( SELECT id FROM sales S INNER JOIN ( SELECT saleprice, saledate FROM sales GROUP BY saleprice, saledate HAVING COUNT(*) = 1 ) T ON S.saleprice=T.saleprice AND s.saledate=T.saledate ) 

如果你把答案到目前为止,清理和改进,你会得到这个优越的查询:

 UPDATE sales SET status = 'ACTIVE' WHERE (saleprice, saledate) IN ( SELECT saleprice, saledate FROM sales GROUP BY saleprice, saledate HAVING count(*) = 1 ); 

哪一个比哪一个快得多。 核算目前接受的答案的性能10 – 15(在我的testingPostgreSQL的8.4和9.1)。

但是这还远远不够理想。 使用NOT EXISTS (反)半连接来获得更好的性能。 EXISTS是标准的SQL,已经一直存在(至less从PostgreSQL 7.2开始,在这个问题被提出之前很久),完全符合所提出的要求:

 UPDATE sales s SET status = 'ACTIVE' WHERE NOT EXISTS ( SELECT 1 FROM sales s1 WHERE s.saleprice = s1.saleprice AND s.saledate = s1.saledate AND s.id <> s1.id -- except for row itself ); AND s.status IS DISTINCT FROM 'ACTIVE'; -- avoid empty updates. see below 

SQL小提琴。

用于识别行的唯一键

如果您没有表的主键或唯一键(示例中为id ),则可以使用系统列ctidreplace此查询的目的:

  AND s.ctid <> s1.ctid 

每个表都应该有一个主键。 如果您还没有,请添加一个。 我build议一个serial

这是如何更快?

EXISTS (反)半连接中的子查询可以在find第一个重复函数后立即停止计算(没有进一步观察的地方)。 对于重复less的基本表,这只是稍微有效一些。 有了大量的重复,这变得更有效率。

排除空的更新

如果一些或多行已经有status = 'ACTIVE' ,你的更新不会改变任何东西,但是仍然以全部成本插入一个新的行版本(应用less量例外)。 通常情况下,你不需要这个。 添加另一个像上面演示的WHERE条件,以使其更快:

如果status定义为NOT NULL ,则可以简化为:

 AND status <> 'ACTIVE'; 

您的查询的问题是,当使用GROUP BY子句(基本上使用不同的)时,您只能使用您分组或聚合函数的列。 您不能使用列ID,因为有可能不同的值。 在你的情况下,总是只有一个值,因为HAVING子句,但是大多数RDBMS不够聪明以至于不能识别这个值。

这应该工作,但是(不需要连接):

 UPDATE sales SET status='ACTIVE' WHERE id IN ( SELECT MIN(id) FROM sales GROUP BY saleprice, saledate HAVING COUNT(id) = 1 ) 

您也可以使用MAX或AVG而不是MIN,只有使用返回列值的函数(如果只有一个匹配的行)才是重要的。