Postgresql 将行数()与Update语句一起使用

Postgresql 将行数()与Update语句一起使用,postgresql,Postgresql,希望只是一个简单的问题。我在UPDATE语句中使用row_number()时遇到了一些困难 假设我有一张书架桌: userid createddate bookid pagenumber 1 2021-18-01 charper 141 1 2021-17-01 mproust 136 1 2021-17-01 sking 134 1 2021-15-01 charper 128 1 2021-

希望只是一个简单的问题。我在UPDATE语句中使用row_number()时遇到了一些困难

假设我有一张书架桌:

userid  createddate bookid  pagenumber
1       2021-18-01  charper    141
1       2021-17-01  mproust    136
1       2021-17-01  sking       134
1       2021-15-01  charper    128
1       2021-10-01  jausten    122
2       2021-18-01  vwoolf    141
2       2021-17-01  vwoolf    136
2       2021-17-01  charper    134
我想(求和)相同的bookid页码,然后写到右边的列。我的预期结果必须是:

userid  createddate      bookid pagenumber  countrow
1         2021-18-01    charper  141        269
1         2021-17-01    mproust  136        136
1         2021-17-01    sking    134        134
1         2021-15-01    charper  128        
1         2021-11-01    jausten  122        122
2         2021-18-01    vwoolf   141        277
2         2021-17-01    vwoolf   136        
2         2021-17-01    charper  134        134
我的选择语句

SELECT userid, bookid, pagenumber,
       case when row_number() over (partition by userid, bookid order by bookid) = 1 
            then sum(pagenumber) over (partition by userid, bookid) 
       end as countrow
  from usertable;
上面的sql查询非常适合在临时列上显示countrow。我想存储所有这些输出。所以我改成这样的陈述:

UPDATE bookshelf
SET countrow = countrow_new
FROM ( select userid, createddate, bookid, pagenumber,
       case when row_number() over (partition by userid, bookid, order by bookid) = 1
            then sum(pagenumber) over (partition by userid, bookid) 
       end as countrow_new
  from bookshelf
      )x
此查询似乎无法正常工作。它会用错误的值更新countrow中的所有单元格。我在谷歌上搜索,发现了一些有用的东西,比如和,但没什么。有没有人知道这里发生了什么,或者有没有人有过类似的问题?
如何解决此问题以获得预期结果?

您正在尝试更新表中不存在的列(
countrow
),因此需要将此列添加到原始表并加入子查询:

/* add the column */
ALTER TABLE usertable ADD countrow INT;

/* do the update */
UPDATE  usertable
SET     countrow = countrow_new
FROM ( 
        SELECT  userid, 
                createddate, 
                bookid, 
                pagenumber,
                CASE 
                    WHEN ROW_NUMBER() OVER (PARTITION BY userid, bookid ORDER BY bookid) = 1
                    THEN SUM(pagenumber) OVER (PARTITION BY userid, bookid) 
                END AS countrow_new
        FROM    usertable
      ) x
      JOIN usertable u
        ON u.bookid = x.bookid AND u.createddate = x.createddate AND u.userid = x.userid;
以上假设
{bookid,createddate,userid}
始终是唯一的

然而以这种方式将计算存储在表中是非常糟糕的设计和糟糕的做法-您必须在每次插入/更新/删除时使用触发器使列保持最新,这将对性能造成严重影响

更好的方法是采用原始查询并为其创建一个视图,然后可以将其用作表:

创建视图:

CREATE VIEW vwMyView
AS
SELECT  userid, 
        bookid, 
        pagenumber,
        CASE 
            WHEN ROW_NUMBER() OVER (PARTITION BY userid, bookid ORDER BY bookid) = 1 
            THEN SUM(pagenumber) OVER (PARTITION BY userid, bookid) 
        END AS countrow
FROM    usertable;
SELECT * FROM vwMyView;
从视图中选择:

CREATE VIEW vwMyView
AS
SELECT  userid, 
        bookid, 
        pagenumber,
        CASE 
            WHEN ROW_NUMBER() OVER (PARTITION BY userid, bookid ORDER BY bookid) = 1 
            THEN SUM(pagenumber) OVER (PARTITION BY userid, bookid) 
        END AS countrow
FROM    usertable;
SELECT * FROM vwMyView;

尚未测试此功能,但我认为您需要进行更新连接。我认为您可能需要额外的过滤器-RN-来只更新最新的bookid记录

WITH latestreadtotal AS
(
         SELECT   userid,
                  createddate,
                  bookid,
                  pagenumber,
                  row_number() OVER (partition BY userid, bookid order by bookid) AS rn,
                  CASE
                           WHEN row_number() OVER (partition BY userid, bookid, ORDER BY bookid) = 1 THEN sum(pagenumber) OVER (partition BY userid, bookid)
                  END AS countrow_new
         FROM     bookshelf )
UPDATE bsf
FROM   bookshelf bsf
JOIN   latestreadtotal lrt
ON     bsf.userid = lrt.userid
AND    bsf.createddate = lrt.createddate
AND    bsf.bookid = lrt.bookid
AND    bsf.pagenumber = lrt.pagenumber
AND    lrt.rn = 1

我想您只需要将
更新
更改为
x

UPDATE x
    SET countrow = countrow_new
    FROM (select userid, createddate, bookid, pagenumber,
                 (case when row_number() over (partition by userid, bookid, order by bookid) = 1
                       then sum(pagenumber) over (partition by userid, bookid) 
                  end )as countrow_new
          from bookshelf
         ) x;
您的代码引用子查询中的
书架
。但是,结果称为
x
。这可能意味着
更新
中的
书架
将作为单独的参考。我必须承认,SQL Server在
update
s中有关于解析表引用的神秘规则。我通常只使用CTE进行这样的单表转换:

WITH toupdate AS (
      select userid, createddate, bookid, pagenumber,
             (case when row_number() over (partition by userid, bookid, order by bookid) = 1
                   then sum(pagenumber) over (partition by userid, bookid) 
              end )as countrow_new
      from bookshelf
     )
UPDATE toupdate
    SET countrow = countrow_new;

根据您问题中的引用,我添加了SQL Server标记。请使用您正在使用的数据库标记问题。SQL Server或Postgres?当涉及到带有FROM子句的更新时,它们是非常不同的。