【问题标题】:Extended placeholders for SQL, e.g. WHERE id IN (??)SQL 的扩展占位符,例如身份在哪里 (??)
【发布时间】:2011-04-11 09:54:36
【问题描述】:

赏金更新:已经从 Mark 那里得到了很好的回答。将 := 改编为 :, 下面。但是,我仍在寻找除 DBIx 之外的类似方案。我只是对兼容任何东西感兴趣。


我需要有关我为参数化 SQL 语句中的“扩展”占位符选择的语法的建议。因为构建一些结构(IN 子句)让我很烦,所以我决定使用一些自动扩展为普通的语法快捷方式?占位符。
我喜欢他们。但我想把它打包分发,我问自己它们是否容易理解。

基本上我的新占位符是??:?(枚举参数)和:&:,:|::(用于命名占位符),具有以下用例:

-> db("  SELECT * FROM all WHERE id IN (??)  ", [$a, $b, $c, $d, $e])

?? 扩展为 ?,?,?,?,?,...,具体取决于我的 db() 函数的 $args 数量。这个很清楚,它的语法已经有点标准化了。 Perls DBIx::Simple 也使用它。所以我很确定这是一个可以接受的想法。

-> db("  SELECT :? FROM any WHERE id>0   ",  ["title", "frog", "id"]);
// Note: not actually parameterized attr, needs cleanup regex

承认吧。我只是喜欢笑脸。基本上,这个 :? 占位符将关联的 $args 扩展为普通的列名。实际上,它会丢弃任何 $args 值。它实际上对于与 ?? 结合使用的 INSERT 非常有用,有时对于 IN 子句也很有用。但是在这里我已经想知道这种新语法是否合理,或者不仅仅是一个误称,因为它混合了 : 和 ?人物。但不知何故,它似​​乎与语法方案很好地匹配。

-> db("  UPDATE some SET :, WHERE :& AND (:|)   ", $row, $keys, $or);

这里的助记符 :, 扩展为由 , 逗号分隔的 name=:name 对列表。而:& 是由ANDs 加入的column=:column 列表。为了平价,我添加了:|。不过 :& 有 UPDATE 命令之外的其他用例。
但我的问题不是关于有用性,而是如果 :, 和 :& 似乎可以记住?

 -> db("  SELECT * FROM all WHERE name IN (::)  ", $assoc);

虽然我还添加了:: 来插入:named,:value,:list,但很像?? 扩展为?,?,?。类似的用例,并且具有一致性。

无论如何,还有其他人实施过这样的计划吗?不同的占位符?或者为了简单起见,您会推荐哪个? 更新: 我知道 PHP Oracle OCI 接口也可以绑定数组参数,但不使用特定的占位符。我正在寻找类似的占位符语法。

【问题讨论】:

  • 我认为您对此进行了很多思考,但是GROUP BYHAVINGORDER BY 子句和子查询呢?自定义格式怎么样,比如当您需要按日期分组而不包括时间部分时?那些需要额外配置的函数,比如 COALESCE 或任何使用 OVER 子句的函数(假设支持)?
  • @OMG Nah,并没有考虑太多。我专注于我最常见的用例。而具体的动态SQL还是需要人工操作的。尤其是表情。但例如:?可用于 ORDER 和 GROUP BY 子句。对于一些结构,我已经有了 {TOKEN} 支持(本质上又是 SQL 连接)。
  • @stereofrog:确实。尽管后端目标不同,但我更关心在 SQL 中抛出数组。占位符方法具有可比性。

标签: php sql


【解决方案1】:

非常整洁!我认为占位符很好,只要您将它们记录好并在分发时提供大量示例。可以自己发明占位符;毕竟有人不得不考虑使用?

【讨论】:

    【解决方案2】:

    您可能希望避免使用 := 作为占位符,因为它已经在例如 MySQL 中使用了 has a usage

    查看例如this answer 以了解真实世界的用法。

    【讨论】:

    • 此外,: 在 Oracle(可能还有 Postgres,也可能是其他)中是 BIND 变量语法。 Oracle 还使用:= 进行值分配。
    • 好收获!没有过多考虑存储过程。
    【解决方案3】:

    我喜欢您提案背后的基本理念,但不喜欢占位符的“命名”。我基本上有两个反对意见:

    • 您的占位符以:? 开头。您应该选择一种形式,以便可以立即识别占位符。我会选择?,因为它与 SQL 发生冲突的可能性较小,并且更常用于表示占位符。
    • 占位符很难理解也很难记住。 :&:| 在我看来似乎是合理的,但区分 ??:?: 是相当困难的。

    我更改了我的DB class 以支持更多的占位符并更智能:DB_intelligent.php(README 中关于占位符的部分不适用于这个类。它只适用于普通类。)

    DB 类有两种占位符:多功能? 占位符和关联数组占位符?xx 可能是,&|)。

    ?占位符:这个占位符根据参数的类型决定插入的类型:

    null                => 'NULL'
    'string'            => 'string'
    array('foo', 'bar') => ('foo','bar')
    

    ?x 占位符:数组中的每个元素都转换为`field`='value' 结构并使用分隔符内爆。分隔符由x 组件指定:, 由逗号分隔,&AND|OR 分隔。

    示例代码:

    DB::x(
        'UPDATE table SET ?, WHERE value IN ? AND ?&',
        array('foo' => 'bar'),
        array('foo', 'bar'),
        array('hallo' => 'world', 'hi' => 'back')
    );
    
    // Results in this query:
    // UPDATE table SET `foo`='bar' WHERE value IN ('foo','bar') AND `hallo`='world' AND `hi`='back'
    

    我在设计这个版本的 DB 类时的一些想法:

    可能会出现一个明显的想法:为什么不将? 用于所有 类型的数据,甚至是关联数组。仅额外添加?&?|。在关联数组上使用? 与在当前设计中使用?, 相同。我没有这样做的原因是安全性。您经常希望将来自 <select multiple> 的数据插入到查询 (IN ?) 中。但是由于 HTML 允许排列 (form[array]) 表单控件,因此也可以提交具有相同名称的关联数组。因此,我的查询合成器会将其识别为字段 => 值列表。尽管这可能不会损害安全性,但它会导致一个不好的 SQL 错误。

    【讨论】:

    • 非常有趣。但是,您不应该使用 addlashes。它与stereofrog 的相似,类型说明符不同,您的? 总是从php 类型中推断出sql。我喜欢 DB::x() 界面,看起来可以节省时间。 (- 我与 ?*:* 的混淆是由于 ?enumerated 和 :named 参数占位符的不同。“:?” 两者兼而有之。和笑脸。)
    • 我为什么不应该使用addslashes?它比self::$instance->quote 更不安全吗?如果是这样,我会改变它。
    • 这是一个非常假设的问题,但是 ->quote 考虑了 UTF-8,而替代的 ' 编码序列可能会跳过添加斜杠。取决于字符集和数据库。例如SQLite 没关系。
    • 你完全正确。此外,一些数据库可能不使用\' 转义,而仅使用'' 转义。我会改变的。
    【解决方案4】:

    如果你愿意花一些时间来学习doctrine,那么你可以做一些很棒的事情,比如:

    $q = Doctrine_Query::create()
        ->select('u.id')
        ->from('User u')
        ->whereIn('u.id', array(1, 3, 4, 5));
    
    echo $q->getSqlQuery();
    

    什么会产生这样的查询:

    SELECT 
    u.id AS u__id 
    FROM user u 
    WHERE u.id IN (?, 
    ?, 
    ?, 
    ?)
    

    本例取自:doctrine dql documentation

    【讨论】:

    • 感谢您的建议。然而,Doctrine 对我的使用产生了太多的开销。 ORM 适用于许多用例,但基本上相当于“非存储过程”。 Doctrine 查询构建器需要两者,在 SQL 之上学习另一种领域语言,以及预定义模式 (YAML)。我看到它显着简化了复杂的数据库。对于单数表来说,这有点矫枉过正。尽管它在某种程度上具有我正在寻找的数组处理。
    • YAML 并不是真正需要的。没有它你可以完美地生活并自己编写模型类。 YAML 只是一个用于自动创建模型的简单工具。
    • 如果你将像 implode(',',$array) 这样的数组传递给你的函数怎么办?一个看起来像 array("first","second","third") 的数组将被转换为 "first,second,third"
    猜你喜欢
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 2011-01-31
    • 2018-12-03
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多