【问题标题】:Bind parameters to partial SQL statement将参数绑定到部分 SQL 语句
【发布时间】:2018-01-04 16:53:02
【问题描述】:

我正在处理一个旧的 PHP 应用程序,我的任务是确保所有区域都使用准备好的语句。目前它使用 sprintf 在执行之前构建大部分查询。

以下是当前实现的一些示例代码:

$queryString = "SELECT count(user.uid) as count
              FROM user
              LEFT JOIN voucher
                ON user.voucher_uid = voucher.uid
              LEFT JOIN affiliation
                ON voucher.uid = affiliation.voucher_uid
                  @affiliation
              LEFT JOIN account
                ON affiliation.account_uid = account.uid
              WHERE affiliation.account_uid IN (@accounts)
                @active
                @search
                @template
                @onlyown
                AND voucher.template NOT LIKE 'api_%'
                AND user.role != 'superadmin'";
$sql = replace_tokens(
  $queryString,
  array(
    'accounts' => implode(', ', array_fill(0, count($accounts), '?')),
    'template' => $template,
    'search' => $search,
    'onlyown' => $onlyown,
    'affiliation' => $affiliation,
    'active' => $active
  )
);

return array_get(self::queryFetchOne($sql, $accounts), 'count', 0);

replace_tokens函数将前面用@声明的“变量”替换为sql。下面是如何构建 @search 变量的示例。

if (is_string($search) && !empty($search)) {
  $search = sprintf('AND (voucher.code LIKE "%%%s%%" OR user.email LIKE "%%%s%%" OR user.salutation LIKE "%%%s%%")', $search, $search, $search);
} else {
  $search = '';
}

现在,我想通过将%%%s%% 更改为:search 并简单地使用命名参数来解决搜索问题。但是,$accounts 变量是一个帐户名称数组,并在 in 语句中使用问号参数。

我的问题的答案可能是否定的,但我想解决这个问题,而不必只使用问号参数,这需要我在构建数组时跟踪我为所有参数保留的顺序。

有没有什么好的方法可以将参数绑定到部分语句或解决我上面描述的使用大量问号参数的问题?

【问题讨论】:

  • 不,这是不可能的。不过,您可以继续使用当前方法,只需确保将 "%%%s%%"(包括引号)替换为 $pdo->quote($variable) 结果。或者您可以继续处理参数的麻烦,但在这种情况下,您必须将所有变量收集到数组中以便进一步执行

标签: php pdo dynamic-sql


【解决方案1】:

我通过构建两个变量来解决这个问题:一个是查询字符串,另一个是查询参数的哈希数组。

if (is_string($search) && !empty($search)) {
  $search = 'AND (voucher.code LIKE :code OR user.email LIKE :email OR user.salutation LIKE :salutation)';
  $params['code'] = "%%$search%%";
  $params['email'] = "%%$search%%";
  $params['salutation'] = "%%$search%%";
} else {
  $search = '';
}

当您完成所有条件代码时,您就有了一个查询参数的哈希数组,您可以将其传递给 PDO execute()

但您必须确保所有命名参数都是唯一的。如果你在不同的条件搜索词中使用相同的名称,就会出现混乱。在这种情况下,位置参数具有优势。

【讨论】:

  • 变量“$accounts”可能平均有大约 20 个变量,但可能有更多,可能有数千个。您会建议使用循环为数组中的每个值生成一个命名参数吗?
  • 这也是位置参数有优势的情况。对于一堆? 使用array_fill() 很容易,但是要制作一系列命名参数需要更多的工作。可能需要array_map()。 PHP 匿名函数语法总是让我讨厌这种语言。 :-P
  • @MarkusTenghamn 也可以使用命名占位符,检查here。但是,你必须意识到你已经在使用占位符了,你的“%%%s%%”和原生的?一样好
【解决方案2】:

这是工程错误。

我的建议;具有与参数相关的变量的数组。 比如

$sql1 = "select * from Apples where a=? and b=?"

还有$sql2 = " or c=?;"

均由函数gen_sql1()gen_sql2() 生成。

只需让gen_sql1 返回数组的前半部分:1, 2。有gen_sql2下半场回复:3

最后,组合数组,你就有了一个数组,并将它们插入“?”参数按顺序排列:

$fullsql = "select * from Apples where a=1 and b=2 or c=3"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多