Postgresql更新基于count,min和group by

时间:2012-05-16 19:01:04

标签: postgresql select command-line group-by min

感谢您抽出宝贵时间来查看我的问题。 我见过类似的问题,但深度不一样。请帮忙!

我想更新一个表中包含user_id和date_created的表中的所有行,其中user_id的date_created最低。

以下选项为我提供了我想要更新的所有行:

select user_id, min(date_created) from mytable s1 where 
    (select count(1) from mytable s2 where 
        s1.user_id = s2.user_id group by s2.user_id) 
 > 1 group by user_id order by user_id;

我原本希望这次更新有效:

update mytable set join_status = 1 where date_created = 
    (select min(date_created) from mytable s1 where 
        (select count(1) from simplepay_payment s2 where 
            s1.user_id = s2.user_id group by s2.user_id)
  > 1 group by user_id);

但是给出了以下错误:

ERROR:  more than one row returned by a subquery used as an expression

我尝试了一些不同的解决方案,但似乎没有任何帮助。

有人对我有任何想法吗?

再次感谢。

1 个答案:

答案 0 :(得分:3)

将您的SQL更改为:

update mytable set join_status = 1 where date_created IN
    (select min(date_created) from mytable s1 where 
        (select count(1) from simplepay_payment s2 where 
            s1.user_id = s2.user_id group by s2.user_id)
  > 1 group by user_id);

详细了解the docs中的行比较。


修改

在子查询中,您正在执行GROUP BY user_id。这意味着 将根据simplepay_payment表中唯一user_id值的数量接收多行。

要使查询按预期工作,您应该使用2列加入:user_iddate_created。正如您所提到的,您已经拥有了可以提供正确结果的查询,因此您可以像这样使用它:

WITH desired AS (
  SELECT user_id, min(date_created) AS mindt
    FROM mytable s1 where 
      (SELECT count(1) FROM mytable s2
        WHERE s1.user_id = s2.user_id GROUP BY s2.user_id) > 1
   GROUP BY user_id)
UPDATE mytable m SET join_status = 1 FROM desired d
 WHERE d.user_id = m.user_id AND d.mindt = m.date_created;

我已将您的查询包含在Common Table Expression中,并在UPDATE语句中使用它。您可以在查询末尾添加RETURNING m.*,以查看已更新的行及其新值。

您可以在SQL Fiddle上测试此查询。


<强> EDIT2:

UPDATE语句的9.1版之前,公用表表达式(WITH-queries)不可用。您只需将CTE子查询移动到更新中,如下所示:

UPDATE mytable m SET join_status = 1 FROM (
  SELECT user_id, min(date_created) AS mindt
    FROM mytable s1 where 
      (SELECT count(1) FROM mytable s2
        WHERE s1.user_id = s2.user_id GROUP BY s2.user_id) > 1
   GROUP BY user_id) d
 WHERE d.user_id = m.user_id AND d.mindt = m.date_created;