【问题标题】:PostgreSQL and JDBC: Is `UPDATE table ... RETURNING ... INTO` supported?PostgreSQL 和 JDBC:是否支持`UPDATE table ... RETURNING ... INTO`?
【发布时间】:2013-02-24 18:48:54
【问题描述】:

我有一个带有 [主键计数器] 的表,用于 [另一个表中的每页 cmets]。
这些主键是每个页面的:​​对于每个页面,评论 ID 从 1 开始。

我想自动分配 10 个 ID 来编写 10 个新 cmets。
— 我可以用 PostgreSQL 和 JDBC 做到这一点吗?

(您是否有任何示例/相关 JDBC 文档的链接?)

我只找到了一些关于 returning 如何作为新插入行的主键的示例,使用了一些 getGeneratedKeys,这在我的情况下似乎没有用。

                                                     ***

我认为 SQL UPDATE 语句看起来像这样:

update PAGES
set NEXT_COMMENT_ID = NEXT_COMMENT_ID + 10
where PAGE_ID = ?                    <-- next-comment-id is *per page*
returning NEXT_COMMENT_ID into ?

因此,不同的线程和服务器不会尝试重用/覆盖相同的 ID(对吗?)。

【问题讨论】:

  • 为什么需要每页评论 ID?为什么不使用每个评论的 ID 和外键返回页面?
  • @muistooshort 然后 ID 会变得相当大。但它们应该是短的连续数字,所以我可以将它们用作bitset 中的索引。
  • ((我会试试这个:stackoverflow.com/a/881414/694469))

标签: java sql postgresql jdbc


【解决方案1】:

在不使用 execute()getResult() 方法的情况下支持 Statement 对象:

类似这样的东西(排除任何错误处理):

String sql = "update ... returning ...";
boolean hasResult = statement.execute(sql);
int affectedRows = 0;
ResultSet rs = null;
if (hasResult) {
  rs = statement.getResultSet();
}
int affectedRows = statement.getUpdateCount();

您知道该语句的作用,这应该没问题。处理“未知”SQL 语句有点复杂,因为您需要在循环中调用getMoreResults()getUpdateCount()。有关详细信息,请参阅 Javadocs。

【讨论】:

  • 谢谢!我实际上正要测试这样的东西——也就是说,executed() 而不是executeUpdate()。我首先这样做了,但认为executeUpdate() 是调用的方法(因为我找到了其他一些答案),但这不起作用,所以我使用了存储函数。但是你的解决方案更好——我宁愿避免存储函数。我会在今天晚些时候尝试一下。
  • 应该是rs = statement.getResultSet();
【解决方案2】:

所以你想要以下结构?:

x = 页面主键 y = cmets 主键

页表

x
-
1
2
3
4 etc

评论表

x y
- -
1 1
1 2
1 3
1 4
2 1
2 2 
2 3
etc?

在这里有一个外键结构并限制子记录是最有意义的。

【讨论】:

  • 是的,您的评论表插图符合预期。 ——外键结构,你的意思是“mu太短”评论的方法?即“每条评论ID和外键返回页面”?
  • 我不明白这是什么意思:“子记录的上限”?
  • 是的,我的意思是结构是最好的选择。您应该与父级建立子关系,但对子级也有限制,因此每个父行只能有 10 行。
  • 但它是一个讨论系统,每页(每个父行)可能有 10 000 cmets。所以我想我不能这样做,如果我想要相当多和小的连续 id,每页。
  • 如果是没有限制的讨论页面,那就更简单了。获取父键,也就是页面键,并向子表(也包含父键,也就是外键)添加注释。上述方法将起作用,但子键将没有逻辑顺序(如果您使用序列)。
【解决方案3】:

创建一个执行 update ... returning ... into 工作的存储函数:

create or replace function INC_NEXT_PER_PAGE_REPLY_ID(
  site_id varchar(32), page_id varchar(32), step int) returns int as $$
declare
  next_id int;
begin
  update DW1_PAGES
    set NEXT_REPLY_ID = NEXT_REPLY_ID + step
    where SITE_ID = site_id and PAGE_ID = page_id
    returning NEXT_REPLY_ID into next_id;
  return next_id;
end;
$$ language plpgsql;

然后这样称呼它:

statement = connection.prepareCall(
    "{? = call INC_NEXT_PER_PAGE_REPLY_ID(?, ?, ?) }")
statement.registerOutParameter(1, java.sql.Types.INTEGER)
bind(values, statement, firstBindPos = 2)  // bind pos no. 1 is the return value
statement.execute()
nextNewReplyIdAfterwards = statement.getInt(1)

相关文档:

【讨论】:

    【解决方案4】:

    要使表包含逻辑顺序,您可能需要在子表中创建复合键和外键。

    sd=# create table x (x int);
    CREATE TABLE
    sd=# create table y (x int, y int);
    CREATE TABLE
    
    sd=# alter table x add primary key (x);
    NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "x_pkey" for table "x"
    ALTER TABLE
    sd=# alter table y add foreign key (x) references x (x);
    ALTER TABLE
    sd=# alter table y add primary key (x,y);
    NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index "y_pkey" for table "y"
    ALTER TABLE
    
    sd=# insert into x values (1);
    INSERT 0 1
    sd=# insert into x values (2);
    INSERT 0 1
    sd=# insert into x values (3);
    INSERT 0 1
    sd=# insert into y values (1,1);
    INSERT 0 1
    sd=# insert into y values (1,2);
    INSERT 0 1
    sd=# insert into y values (1,3);
    INSERT 0 1
    sd=# insert into y values (1,1);
    ERROR:  duplicate key value violates unique constraint "y_pkey" 
    DETAIL:  Key (x, y)=(1, 1) already exists.
    
    sd=# select * from x;
     x
    ---
     1
     2
     3
    (3 rows)
    
    sd=# select * from y;
     x | y
    ---+---
     1 | 1
     1 | 2
     1 | 3
    (3 rows)
    

    这应该能让你到达你想去的地方?

    【讨论】:

    • 嗨,戴尔!感谢您的回答!以您描述的方式,已经有一个带有父表外键和主键的子页面。我的问题是关于如何在子页面中生成每页评论 ID,因此 ID 从 1(每页)开始,并且是连续的(每页)。 - 我认为这个答案与此无关,而更多的是关于 SQL 和一般的外键。还是谢谢
    • (我已经有了一个可行的解决方案,使用存储函数。此外,“a_horse_with_no_name”建议进行“纯”更新(没有任何存储函数),我可能稍后再尝试——除此之外,来自我的观点,这个问题已经解决了。)
    【解决方案5】:

    您正在进行更新,但语句会生成结果,因此请使用 executeQuery() 而不是 executeUpdate()。这就是调用之间的真正区别:executeQuery() 处理产生ResultSet 的语句;而executeUpdate() 返回受影响的行数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-31
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      • 1970-01-01
      • 2015-04-12
      • 1970-01-01
      相关资源
      最近更新 更多