perl DBI 和占位符

发布于 2024-12-11 18:48:17 字数 321 浏览 0 评论 0原文

我有这个查询 select * from table where ID in (1,2,3,5...)

如何使用占位符通过 DBI 构建此查询?

例如:

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID in (?)";

$sth->prepare($sql);
$sth->execute();

我应该发送什么参数来执行?它是一个列表还是一个由 或其他内容分隔的字符串?

I have this query select * from table where ID in (1,2,3,5...)

How is it possible to build this query with the DBI using placeholders ?

for example :

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID in (?)";

$sth->prepare($sql);
$sth->execute();

What argument should I send to execute? Is it a list or a string separated by , or something else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

落墨 2024-12-18 18:48:18

我总结了上述所有建议,找到了一种可行的方法。我的生产查询(我在这里发布了一个更简单的版本)使用 IN <>,其中代码及其数量都是未知的。它可以是单个代码(例如FIN),也可以是一系列代码(FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU)。某些函数将其作为列表返回。

实现这一点的代码是

            @codes =  get_muni_evcode( $category );
            my $in = join( ', ', ('?') x @codes );
            print "\n\nProcessing Category: $category --> Codes: @codes   .. in: $in\n";

            my $sql = "select distinct cusip9 
            from material_event 
            where event_date between (trunc(sysdate) - 1) + 2/3 and trunc(sysdate) + 2/3 
            and event_code in ($in)";
            my $sth2 = $dbh->prepare($sql);
            $sth2->execute( @codes );

            while (my $s2 = $sth2->fetchrow_hashref('NAME_lc'))
            {
                    my $cusip9 = $s2->{cusip9};
                    print "$cusip9\t";
                   .................. further processing ..............

            }

结果示例:

Processing Category: RatingChange -->代码: FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU MDYSC MDYSD MDYSU SPLD SPLPR SPLU SPSD SPSPR SPSU .. 中: ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
359496HQ2 359496GB6 359496GH3 359496GL4 359496HU3 359496HS8 359496HA7 359496HF6 359496GM2 359496HM1 359496HR0 359496HT6 359496GY6 359496GJ9 359496HL3 359496GU4 359496HK5 359496HN9 359496HP4 359496GW0 359496GZ3 359496HC3 359496GC4 359496GK6 359496GP5 359496GV2 359496GX8 359496GN0

我非常感谢在这里发表想法的每个人,他们最终让我找到了正确的方法来做到这一点。我想这一定是一个很常见的问题。

I found a sure way for this to work summarizing all of the above advice. My Production query (I posted a much simpler version here) uses IN <>, where neither the codes nor their quantity is unknown. It could be a single Code (e.g. FIN), or a series of them (FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU). Some function returns that as a list.

The code that makes this happen is

            @codes =  get_muni_evcode( $category );
            my $in = join( ', ', ('?') x @codes );
            print "\n\nProcessing Category: $category --> Codes: @codes   .. in: $in\n";

            my $sql = "select distinct cusip9 
            from material_event 
            where event_date between (trunc(sysdate) - 1) + 2/3 and trunc(sysdate) + 2/3 
            and event_code in ($in)";
            my $sth2 = $dbh->prepare($sql);
            $sth2->execute( @codes );

            while (my $s2 = $sth2->fetchrow_hashref('NAME_lc'))
            {
                    my $cusip9 = $s2->{cusip9};
                    print "$cusip9\t";
                   .................. further processing ..............

            }

The result sample:

Processing Category: RatingChange --> Codes: FITLC FITLD FITLU FITSC FITSD FITSU MDYLC MDYLD MDYLU MDYSC MDYSD MDYSU SPLD SPLPR SPLU SPSD SPSPR SPSU .. in: ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
359496HQ2 359496GB6 359496GH3 359496GL4 359496HU3 359496HS8 359496HA7 359496HF6 359496GM2 359496HM1 359496HR0 359496HT6 359496GY6 359496GJ9 359496HL3 359496GU4 359496HK5 359496HN9 359496HP4 359496GW0 359496GZ3 359496HC3 359496GC4 359496GK6 359496GP5 359496GV2 359496GX8 359496GN0

I'm extremely grateful to everybody who posted their ideas here that finally made me find the right way to do this. It must be a pretty common problem I think.

甚是思念 2024-12-18 18:48:17

这应该根据数组中的项目数动态构建您的查询

my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";

This should build your query dynamically according to the number of items in your array

my @list =(1,2,3,4,5);
my $sql ="select * from table where ID in (@{[join',', ('?') x @list]})";
她如夕阳 2024-12-18 18:48:17

那样的话是不可能的。您需要为数组中的每个项目指定一个占位符:

my @list = (1,2,3,4,5);
my $sql = "select * from table where ID in (?,?,?,?,?)";

$sth->prepare($sql);
$sth->execute(@list);

如果您的 @list 不是固定大小,则需要使用适当数量的占位符构建 $sql

It's not possible in that way. You need to specify a placeholder for each item in your array:

my @list = (1,2,3,4,5);
my $sql = "select * from table where ID in (?,?,?,?,?)";

$sth->prepare($sql);
$sth->execute(@list);

If your @list is not a fixed size, you need to build the $sql with the proper number of placeholders.

淡淡の花香 2024-12-18 18:48:17

引用 DBI 文档

此外,占位符只能表示单个标量值。例如,以下语句将不会按预期工作
对于多个值:

 SELECT 姓名、年龄 FROM people WHERE name IN (?) # 错误
     SELECT name,age FROM people WHERE name IN (?,?) # 两个名字

重写为:

my $sql = 'select * from table where ID in ( ?, ?, ?, ?, ? )';
$sth->prepare($sql);
$sth->execute(@list);

Quoting DBI documentation:

Also, placeholders can only represent single scalar values. For example, the following statement won't work as expected
for more than one value:

     SELECT name, age FROM people WHERE name IN (?)    # wrong
     SELECT name, age FROM people WHERE name IN (?,?)  # two names

Rewrite to:

my $sql = 'select * from table where ID in ( ?, ?, ?, ?, ? )';
$sth->prepare($sql);
$sth->execute(@list);
灵芸 2024-12-18 18:48:17

如果您使用 DBI 通过 DBD::Pg 驱动程序访问 PostgreSQL 数据库,则可以使用:

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID = ANY(?::INT[]);";

$sth->prepare ($sql);
$sth->execute (\@list);

If you are using DBI to access a PostgreSQL database with the DBD::Pg driver, you can use:

my @list = (1, 2, 3, 4, 5);
my $sql = "select * from table where ID = ANY(?::INT[]);";

$sth->prepare ($sql);
$sth->execute (\@list);
陌生 2024-12-18 18:48:17

除非您知道元素的确切数量,否则不能使用占位符。试试这个:

my @list = (1, 2, 3, 4, 5);  # any number of elements
my $in = join(',', map { $dbh->quote($_) } @list);
my $sql = "select * from table where someid IN ($in)";

Unless you know the exact number of elements you cannot use placeholders. Try this:

my @list = (1, 2, 3, 4, 5);  # any number of elements
my $in = join(',', map { $dbh->quote($_) } @list);
my $sql = "select * from table where someid IN ($in)";
不及他 2024-12-18 18:48:17

如果您切换到 DBIx::Simple 您可以直接说:

$db->query('INSERT INTO foo VALUES (??)', $foo, $bar, $baz);

??意思是“需要多少就多少”

编辑:

实际上,我有点太乐观了:“如果查询中存在字符串 (??),它将被替换为 as 的列表许多问号为@values。”

所以这似乎不起作用:

$db->query( "SELECT * FROM foo WHERE id IN (??) AND stuff=?", @ids, $stuff )

但仍然有用......

对于好奇的人来说,模块中的代码是:

# Replace (??) with (?, ?, ?, ...)
sub _replace_omniholder {
  my ($self, $query, $binds) = @_;
  return if $query !~ /\(\?\?\)/;
  my $omniholders = 0;
  my $q = $self->{dbd} =~ /mysql/ ? $quoted_mysql : $quoted;
  $query =~ s[($q|\(\?\?\))] {
    $1 eq '(??)'
    ? do {
        Carp::croak('There can be only one omniholder')
            if $omniholders++;
        '(' . join(', ', ('?') x @$binds) . ')'
    }
    : $1
  }eg;
}

If you switch to DBIx::Simple you can just say:

$db->query('INSERT INTO foo VALUES (??)', $foo, $bar, $baz);

?? Means "as many as needed"

Edit:

Actually, I was a little too optimistic: "If the string (??) is present in the query, it is replaced with a list of as many question marks as @values."

So this does not seem to work:

$db->query( "SELECT * FROM foo WHERE id IN (??) AND stuff=?", @ids, $stuff )

Still useful though..

For the curious, the code in the module is:

# Replace (??) with (?, ?, ?, ...)
sub _replace_omniholder {
  my ($self, $query, $binds) = @_;
  return if $query !~ /\(\?\?\)/;
  my $omniholders = 0;
  my $q = $self->{dbd} =~ /mysql/ ? $quoted_mysql : $quoted;
  $query =~ s[($q|\(\?\?\))] {
    $1 eq '(??)'
    ? do {
        Carp::croak('There can be only one omniholder')
            if $omniholders++;
        '(' . join(', ', ('?') x @$binds) . ')'
    }
    : $1
  }eg;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文