我需要从表中检索所有行,其中两列的组合都不同。因此,我希望同一天没有任何其他销售的所有销售都以相同的价格进行。基于日期和价格的唯一销售将更新为活动状态。

所以我在想:

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 倍(在我对 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

数据库<>小提琴 这里
旧的 SQL 小提琴

识别行的唯一键

如果您没有表的主键或唯一键(id 在示例中),您可以替换为系统列 ctid 出于此查询的目的(但不出于其他目的):

   AND    s1.ctid <> s.ctid

每个表都应该有一个主键。如果您还没有,请添加一个。我建议一个 serial 或一个 IDENTITY Postgres 10+ 中的专栏。

有关的:

这怎么更快?

中的子查询 EXISTS 一旦发现第一个受骗者,反半连接就可以停止评估(进一步寻找没有意义)。对于具有很少重复项的基表,这只是稍微更有效。由于有很多重复项,这变成了 方式 更高效。

排除空更新

对于已经有的行 status = 'ACTIVE' 此更新不会更改任何内容,但仍以全部成本插入新的行版本(存在较小的例外情况)。通常,您不希望这样。加上另一个 WHERE 像上面演示的情况可以避免这种情况并使其更快:

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

AND status <> 'ACTIVE';

NULL 处理的细微差别

此查询(与 目前乔尔接受的答案) 不将 NULL 值视为相等。下面两行为 (saleprice, saledate) 将被视为“独特”(尽管看起来与人眼相同):

(123, NULL)
(123, NULL)

还传递唯一索引以及几乎任何其他地方,因为根据 SQL 标准,NULL 值比较不相等。看:

奥托, GROUP BY, DISTINCT 或者 DISTINCT ON () 将 NULL 值视为相等。根据您想要实现的目标,使用适当的查询样式。您仍然可以使用这个更快的查询 IS NOT DISTINCT FROM 代替 = 对于任何或所有比较,使 NULL 比较相等。更多的:

如果定义了所有要比较的列 NOT NULL, ,没有任何异议的余地。

您的查询的问题在于,当使用 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,只有在只有一个匹配行时才使用返回列值的函数才重要。

我想从“GrondOfLucht”一列中选择不同的值,但它们应该按照“排序”列中给出的顺序排序。我无法使用仅一列的不同值

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

它还将给出“排序”列,并且由于“GrondOfLucht”和“排序”不唯一,因此结果将是所有行。

使用 GROUP 按照 'sortering 给出的顺序选择 '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 上工作,并且由于您避免了分组功能,因此预计比分组解决方案更快。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top