有没有办法使用 DBI 和 MySQL/MyISAM 将 @variables 与 Perl 中的占位符混合?

Posted

技术标签:

【中文标题】有没有办法使用 DBI 和 MySQL/MyISAM 将 @variables 与 Perl 中的占位符混合?【英文标题】:Is there a way to mix @variables with placeholders in Perl using DBI and MySQL/MyISAM? 【发布时间】:2020-11-19 09:14:16 【问题描述】:

我有一个这样的查询:

SELECT
    foo.bar
FROM
    foo
WHERE
    foo.bang = 0
    AND (
        CASE
            WHEN ? = 2 THEN foo.baz IS NOT NULL
            WHEN ? = 1 THEN foo.baz IS NULL
            ELSE ? NOT IN (1, 2)
        END
    )
    AND (
        (? = 0)
        OR
        (foo.bang = ?)
    )

占位符 (?) 用作过滤器参数的输入:

my $query = $aboveQuery;
my ( $results ) = $dbh->DBI::db::selectall_arrayref(
    $query,
     Slice =>  ,
    $bazFilter,
    $bazFilter,
    $bazFilter,
    $bangFilter,
    $bangFilter,
);

这可行,但对读者不太友好。 mysql 支持@ 变量,这将增加可读性:

SET @bazFilter = ?;  -- passed in via selectall_arrayref or execute;
SET @bangFilter = ?;

SELECT
    foo.bar
FROM
    foo
WHERE
    foo.bang = 0
    AND (
        CASE
            WHEN @bazFilter = 2 THEN foo.baz IS NOT NULL
            WHEN @bazFilter = 1 THEN foo.baz IS NULL
            ELSE @bazFilter NOT IN (1, 2)
        END
    )
    AND (
        (@bangFilter = 0)
        OR
        (foo.bang = @bangFilter)
    );

我想做这样的事情:

my $query = $aboveAtVariablizedQuery;
my ( $results ) = $dbh->DBI::db::selectall_arrayref(
    $query,
     Slice =>  ,
    $bazFilter,
    $bangFilter,
);

但 MyISAM 显然不会在单个查询中执行多个语句。

我的 google-fu 让我失望了。 有没有一种很好的方法可以将@variables 与占位符混合匹配?

【问题讨论】:

$dbh->do('SET @bazFilter = ?;', ...); $dbh->do('SET @bangFilter = ?;', ...); $dbh->selectall_arrayref(...)? 提示:$dbh->DBI::db::selectall_arrayref 应该只是 $dbh->selectall_arrayref @ikegami 我宁愿一次性完成所有操作,而不是对$dbi 进行三个单独的调用(而且我的商店的代码要求迫使我们在使用它们时必须完全限定它们,因此上面代码中的DBI::db::)。 Re "和我商店的代码要求迫使我们完全限定软件包",这很糟糕。您要求调用者对 DBI 的工作有内部知识,并对这些内部施加依赖。你的方法很脆弱,很容易出错,也很容易出错。糟糕,糟糕,糟糕。这与程序员应该努力的目标完全相反 @ikegami 我不是要和你争论我商店的代码要求。总的来说,我同意你的观点,我也反对过,但无济于事。 【参考方案1】:

单独执行每个语句,使用execute 而不是其中一种 fetch 方法。

@变量对于连接来说是本地的,所以线程之间不存在污染问题。

如果目标是没有重复替换的单个查询,那么考虑:

SELECT  foo.bar
    FROM  ( SELECT baz = ?, bang = ? ) AS init
    JOIN  foo
    WHERE   foo.bang = 0
        AND (
            CASE
                WHEN init.baz = 2 THEN foo.baz IS NOT NULL
                WHEN init.baz = 1 THEN foo.baz IS NULL
                ELSE init.baz NOT IN (1, 2)
            END
        )
        AND (
            (init.bang = 0)
            OR
            (foo.bang = init.bang)
        );

【讨论】:

虽然我希望真正将 @ 变量与 ? 占位符混合在一起,但这绝对符合我的(隐含的)单一可读 没有重复替换的查询。谢谢!

以上是关于有没有办法使用 DBI 和 MySQL/MyISAM 将 @variables 与 Perl 中的占位符混合?的主要内容,如果未能解决你的问题,请参考以下文章

DBI dbWriteTable

在 Windows-7-x64 上使用 DBI Perl 和 MySql 的未定义 $DBI::errstr

无法在 R DBI 中获得完整的结果集

如何使用 Perl 的 DBI 处理 unicode?

Perl DBI - 加载到 SQL Server

如何在自定义 @INC 中使用 DBI 构建 DBD::mysql?