3

我有一个简单的 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
);

网络用户表

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_works 表

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

1 回答 1

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网络用户的别名。一个微不足道的错误。

  2. w和之间缺少连接a。导致交叉连接,这几乎没有任何意义,并且就性能而言是一个非常昂贵的错误。这也是完全不需要的,您可以从查询中删除冗余的第二个实例。webuser

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

  4. 事实证明,在评论和问题更新后,您创建了带有双引号"CamelCase"标识符的表(我建议永远不要将其用于我们刚刚遇到的那种问题)。阅读手册中的标识符和关键字一章以了解问题所在。简而言之:非标准标识符(带有大写字母或保留字,..)必须始终用双引号引起来。
    我修改了下面的查询以适应新信息。

  5. 根据定义,聚合函数count()永远不会返回NULLCOALESCE在这种情况下是没有意义的。我引用了关于聚合函数的手册

    需要注意的是,除了 count 之外,这些函数在没有选择行时返回空值。

    强调我的。计数本身有效,因为NULL不计算值,所以实际上你得到 0 在没有s.id找到的地方。

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

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

  8. 避免实际上不会更改任何内容的更新几乎总是一个好主意(适用罕见的例外情况)。我添加了第二个WHERE子句来消除这些:

    AND   w.shares_this_round IS DISTINCT FROM a.id
    

    如果shares_this_round已定义NOT NULL,则可以使用<>代替,因为id_ct不能NULL。(同样,缺少相关信息。)

  9. USING(username)只是可以在此处使用的符号快捷方式。

把所有东西放在一起,得到这个正确的形式:

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
于 2012-11-10T03:58:47.377 回答