2

insert into table1(id, text) select (max(id)+1), "Something" from table1

如何使用 SQL::Abstract 或 SQL::Abstract::More 生成此查询?

4

3 回答 3

2

你可以这样做:

use strict;
use warnings;
use SQL::Abstract;

my $sa = SQL::Abstract->new;
my $select = $sa->select('table1', "MAX(id) + 1, 'Something'");
my $full_sql = "INSERT INTO table1 (id, text) $select";

但实际上,你为什么要这样做?您的示例很简单,正如其他人所指出的,仅编写 SQL 会更好。如果您打算将“某物”作为变量,则可以这样做:

my $new_id = $sa->select('table1', 'MAX(id) + 1');
my $data = {
   id => \["($new_id)"],
   text => $some_value_from_elsewhere
};
my ($sql, @binds) = $sa->insert('table1', $data);
于 2013-04-16T19:06:20.493 回答
1

正如 Rachcha 所指出的,您的 SQL 语句包含一些缺陷。我假设你正在尝试类似的东西

insert into table1(id, text) values((select (max(id)+1) from table1), "Something")

如果您想将新数据添加到具有唯一 ID 的 table1 中,您真的应该考虑在数据库中的 id 字段中添加主键。

更新的答案

旧的 anwser确实创建了一个关于数据和语法的有效 SQL 语句,但是 DBI 中的准备执行函数对这些值做了一些魔术。

如果我像这样运行查询:

my $query = "insert into table1 values((select (max(id)+1) from table1), 'Something')";
$dbh->do($query);

查询将在执行时保持原样。当我改为使用prepareexecute时,DBI 会自动将值放在单引号之间,例如 'this',这会导致:

insert into table1(id, text) values('(select (max(id)+1) from table1)', 'Something');

显然,这会将值打印为文本(如果这是有效的数据类型)。在我看来,这并不意味着从代码生成的查询是错误的,而不是来自 DBI 的不需要的引用。如果可以删除它们,我找不到答案。问题是 DBI 是否支持 insert ... select 语句。否则,您将无法对这些查询使用 SQL::Abstract(或准备/执行)。

只要您的数据库没有可能导致重复的多个事务,您就可以将其构建为两步火箭。

my $select_stmt = $sql->select('table1', '(max(id)+1)'):
# Prepare with $stmt
# Fetch your result and declare $max_id, e.g.
my $sth = $dbh->prepare($select_stmt);
$sth->execute();

my $max_id = 0;
my @max_id_arr = $sth->fetchrow_array();
$max_id = $max_id_arr[0];

die($max_id . " is 0") unless($max_id);

my %data = (
    id => $max_id,
    text => 'Something',
);

my($insert_stmt, @insert_bind) = $sql->insert('table1', \%data);

旧答案

但是,要回答您的问题,这应该可以解决问题:

my $max_id = $sql->select('table1', 'max(id)+1');
my %data = (
    id => "($max_id)",
    text => "Something",
);
my($stmt, @bind) = $sql->insert('table1', \%data);

printf("My SQL statement was %s\nThe values was %s\n", $insert_stmt, join(", ", @insert_bind));

这将打印

我的 SQL 语句是 INSERT INTO table1 ( id, text) VALUES ( ?, ? ) 值是 (SELECT max(id)+1 FROM table1),Something

于 2013-04-12T14:09:03.710 回答
1

虽然我在代码中大量使用 SQL::Abstract,但我不会在您的示例中推荐它。主要是因为如果您直接编写 SQL 代码,它有时更具可读性和可维护性。并且因为您必须确保插入字段的顺序与选择字段的顺序完全匹配。

但是,您可以使用该$sql->where()方法从您的选择查询中提取 where-part,如果您必须:

    my $stmt1 = <<'END_SQL';
    INSERT INTO table1(id, text) 
    SELECT (MAX(id)+1) id, 'Something' text
    FROM table1
    END_SQL

    my ($stmt2,@binds) = $sql->where( key1=>$value1, key2=>$value2 );

然后简单地连接两个 SQL 语句。

于 2013-04-16T11:51:06.797 回答