Answers:
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)(在PostgreSQL 8.4和9.1上的测试中)。
但是,这仍然远非最佳。使用NOT EXISTS
(反)半联接可获得更好的性能。EXISTS
是标准SQL,已经存在了很长时间(至少从PostgreSQL 7.2开始,很久以前才问这个问题),并且完全符合提出的要求:
UPDATE sales s
SET status = 'ACTIVE'
WHERE NOT EXISTS (
SELECT FROM sales s1 -- SELECT list can be empty for EXISTS
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
如果您没有该表的主键或唯一键(id
在示例中),则可以使用system列代替ctid
该查询(但不能用于其他目的):
AND s1.ctid <> s.ctid
每个表都应有一个主键。如果还没有,请添加一个。我建议Postgres 10+中有一个serial
或一个IDENTITY
专栏。
有关:
EXISTS
一旦找到第一个重复对象,反半联接中的子查询就可以停止评估(进一步寻找毫无意义)。对于几乎没有重复的基本表,这只会稍微提高效率。随着大量重复的这成为方式更有效。
对于已经进行了status = 'ACTIVE'
此更新的行,不会进行任何更改,但仍会全额插入新的行版本(有一些例外情况)。通常,您不希望这样做。添加WHERE
如上所述的另一种条件来避免这种情况,并使其更快:
如果status
已定义NOT NULL
,则可以简化为:
AND status <> 'ACTIVE';
列的数据类型必须支持<>
运算符。某些类型json
不喜欢。看到:
此查询(不同于Joel当前接受的答案)不会将NULL值视为相等。以下两行将(saleprice, saledate)
被视为“与众不同”(尽管看上去与人眼相同):
(123, NULL)
(123, NULL)
还传递唯一索引和几乎其他任何地方,因为NULL值根据SQL标准不等于相等。看到:
OTOH, GROUP BY
,DISTINCT
或DISTINCT ON ()
NULL值视为相等。根据您要实现的目的使用适当的查询样式。您仍然可以使用此更快的查询,IS NOT DISTINCT FROM
而不是=
对任何或所有比较使用,以使NULL比较相等。更多:
如果定义了要比较的所有列NOT NULL
,则没有分歧的余地。
count(*)
是更比效率count(<expression>)
。去尝试一下。Postgres对于聚合函数的此变体具有更快的实现。也许您将Postgres与其他RDBMS混淆了?
查询的问题在于,当使用GROUP BY子句时(本质上是通过使用distinct来完成的),您只能使用按功能分组或聚合功能的列。您不能使用列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,只有只有一个匹配行的情况下,使用返回列值的函数才是重要的。
我想从“ GrondOfLucht”列中选择不同的值,但是应该按照“排序”列中给出的顺序对它们进行排序。我无法使用仅获得一列的不同值
Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering
它还将给列“排序”,并且因为“ GrondOfLucht”和“排序”不是唯一的,所以结果将是所有行。
使用“组”以“排序”给定的顺序选择“ GrondOfLucht”的记录
SELECT GrondOfLucht
FROM dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
如果您的DBMS不支持像这样的多个列,则:
select distinct(col1, col2) from table
通常,可以安全执行多重选择,如下所示:
select distinct * from (select col1, col2 from table ) as x
因为这可以在大多数DBMS上使用,并且由于避免了分组功能,所以预计它比按解决方案分组要快。