PostgreSQL UPDATE相当于MySQL查询

时间:2012-11-10 00:51:46

标签: mysql sql postgresql sql-update

我有一个简单的MySQL查询,我想转换为PostgreSQL。 3天后我终于退出了,因为我不明白这里有什么不妥:

UPDATE webUsers u, 
(SELECT IFNULL(count(s.id),0) AS id, p.associatedUserId FROM pool_worker p 
LEFT JOIN shares s ON p.username=s.username 
WHERE s.our_result='Y' GROUP BY p.associatedUserId) a
SET shares_this_round = a.id WHERE u.id = a.associatedUserId

我试图转换它,但它在SET上说错误。这是我的疑问:

UPDATE webusers 
SET (shares_this_round) = (a.id)
FROM (SELECT coalesce(count(s.id),0) AS id, p.associatedUserId FROM pool_worker p 
LEFT JOIN shares s ON p.username=s.username WHERE s.our_result='Y' GROUP BY p.associatedUserId) a, webusers w WHERE u.id = a.associatedUserId

任何人都可以告诉我它有什么问题吗?因为这个原因,我无法入睡。

     ------------------------------EDIT-------------------------------------

分享表

CREATE TABLE shares (
id bigint NOT NULL,
rem_host character varying(255) NOT NULL,
username character varying(120) NOT NULL,
our_result character(255) NOT NULL,
upstream_result character(255),
reason character varying(50),
solution character varying(1000) NOT NULL,
"time" timestamp without time zone DEFAULT now() NOT NULL
);

webusers表

CREATE TABLE webusers (
id integer NOT NULL,
admin integer NOT NULL,
username character varying(40) NOT NULL,
pass character varying(255) NOT NULL,
email character varying(255) NOT NULL,
"emailAuthPin" character varying(10) NOT NULL,
secret character varying(10) NOT NULL,
"loggedIp" character varying(255) NOT NULL,
"sessionTimeoutStamp" integer NOT NULL,
"accountLocked" integer NOT NULL,
"accountFailedAttempts" integer NOT NULL,
pin character varying(255) NOT NULL,
share_count integer DEFAULT 0 NOT NULL,
stale_share_count integer DEFAULT 0 NOT NULL,
shares_this_round integer DEFAULT 0 NOT NULL,
api_key character varying(255),
"activeEmail" integer,
donate_percent character varying(11) DEFAULT '1'::character varying,
btc_lock character(255) DEFAULT '0'::bpchar NOT NULL
);

pool_workes表

CREATE TABLE pool_worker (
id integer NOT NULL,
"associatedUserId" integer NOT NULL,
username character(50),
password character(255),
allowed_hosts text
);

1 个答案:

答案 0 :(得分:5)

首先,我格式化了这个不那么令人困惑但仍然不正确的查询:

UPDATE webusers 
SET   (shares_this_round) = (a.id)
FROM  (
   SELECT coalesce(count(s.id),0) AS id, p.associatedUserId
   FROM   pool_worker p 
   LEFT   JOIN shares s ON p.username=s.username
   WHERE  s.our_result='Y'
   GROUP  BY p.associatedUserId) a
   , webusers w
WHERE u.id = a.associatedUserId

此声明中有多个不同的错误和更多次优部分。错误首先出现,并强调粗体。最后几项只是建议。

  1. 缺少别名 u for webuser。一个微不足道的错误。

  2. {li>

    wa之间缺少加入。结果是交叉连接,这几乎没有任何意义,就性能而言是一个非常昂贵的错误。它也完全不受欢迎,您可以从查询中删除冗余的webuser 第二个实例。

  3. SET (shares_this_round) = (a.id)语法错误。您不能在括号中的SET子句中包装列名。无论如何,这都是毫无意义的,就像围绕a.id的括号一样。不过,后者不是语法错误。

  4. 事实证明,在评论和问题更新之后,您使用双引号"CamelCase"标识符创建了表格(我建议您不要使用,以确保我们遇到的那种问题)。阅读手册中的Identifiers and Key Words章节,了解出了什么问题。简而言之:非标准标识符(带大写字母或保留字,......)必须始终双引号。
    我修改了下面的查询以适应新信息。

  5. 根据定义,聚合函数count()永远不会返回NULL。在这种情况下,COALESCE毫无意义。我引用the manual on aggregate functions

      

    应该注意除了计数,这些函数返回一个   没有选择行时为空值。

    强调我的。计数本身有效,因为NULL值不计算在内,因此在没有找到s.id的情况下实际得到0。

  6. 我还使用了不同的列别名(id_ct),因为计数的id只会产生误导。

  7. WHERE s.our_result = 'Y' ...如果our_result的类型为boolean,就像它应该是的那样,您可以简化为WHERE s.our_result。我在这里猜测,因为你没有提供必要的表定义。

  8. 避免实际没有改变任何内容的UPDATE几乎总是一个好主意(很少有例外情况适用)。我添加了第二个WHERE子句来消除这些:

    AND   w.shares_this_round IS DISTINCT FROM a.id
    

    如果定义shares_this_round NOT NULL,则可以使用<>,因为id_ct不能是NULL。 (再次,缺少有问题的信息。)

  9. USING(username)只是一个可以在这里使用的符号快捷方式。

  10. 将所有内容放在一起以获得此正确形式:

    UPDATE webusers w
    SET    shares_this_round = a.id_ct
    FROM  (
       SELECT p."associatedUserId", count(s.id) AS id_ct
       FROM   pool_worker p 
       LEFT   JOIN shares s USING (username)
       WHERE  s.our_result = 'Y'                        -- boolean?
       GROUP  BY p."associatedUserId"
       ) a
    WHERE w.id = a."associatedUserId"
    AND   w.shares_this_round IS DISTINCT FROM a.id_ct  -- avoid empty updates