【问题标题】:How do I escape % in Knex where like query?如何在 Knex 中像查询一样逃避 %?
【发布时间】:2018-10-23 22:07:45
【问题描述】:

我正在使用knex 来生成我的 SQL 查询。在knex 文档中,它显示了这一点

knex('users').where('columnName', 'like', '%rowlikeme%')

现在在我的应用程序中,我这样做了:

function search(term) {
  term = "%" + term + "%";
  knex('table').where('description', 'like', term);
  // ...
}

如何转义 % 以便它也搜索 % 作为术语的一部分?

谢谢。

【问题讨论】:

    标签: javascript mysql node.js knex.js


    【解决方案1】:

    使用 RLIKE 代替 LIKE 如下,它应该适合你。

    function search(term){
        knex('table').where('description','rlike',term);
        ...
    }
    

    【讨论】:

    • 嗨,rlike 没有通过测试用例。示例:搜索词是“40%”。结果应显示:“Microscopic 40% Bacterialium”、“40% Alcohol”、“Creatine 40%”,但未显示“Creatine 40%”和“Microscopic 40% Bacterialium”。
    • 你能不能用“ ` ” as 尝试一次把词放在一起:knex('table').where('description','like',term);
    • 如果我在术语前后添加 %,它将回复所有 3 个三个结果。如果我不这样做,它在使用 like 关键字时不会返回任何内容。
    • 因为,这是喜欢的规则。例如,如果您有一个像“World”这样的值并使用 like 搜索“%orl%”,那么它将返回。但如果您搜索“orl”,则不会。这里 '%' 表示一个或多个字符
    【解决方案2】:

    我有一段时间没有使用 knex,所以我无法测试这个。但是你有没有试图从字面上逃避 %?我希望这是你想要的。

    let term = "%something%"
    let parsedTerm = term.replace("%", "\%")
    console.log(parsedTerm);
    

    请告诉我。

    【讨论】:

      【解决方案3】:

      对于这种情况,我使用

      来自es6(安全版本)的字符串插值

      knex('table').where('description', 'like', `%${term}%`)
      

      ??参数binding

      knex('table').whereRaw('description like \'%??%\'', [term])
      

      但在第一种情况下,您必须 100% 确定该术语是有效的,因为 possibility of SQL injection

      【讨论】:

      • first例子有SQL注入的可能。第二种是使用命名参数,所以应该是安全的。
      • 第一个对我不起作用。当 term 为 'foo' 时,绑定为 'undefinedfooundefined'。
      • @user128216 为什么第一个例子where('description', 'like', %${term}%)容易发生sql注入?这不是和参数绑定一样安全吗?参考链接没有提到容易发生 sql 注入的地方,只是原始的。
      • .where 中的术语被转义,因此没有注入风险:github.com/knex/documentation/issues/73#issuecomment-572482153
      • 第二个错误严重,根本不应该工作(?? 绑定应该只用于标识符,所以如果term 中有点,它将失败)。第一个应该没问题,但我不知道它是否真的能够匹配% char。
      【解决方案4】:

      Knex 没有与 ESCAPE 关键字 [1] 等效的关键字,因此您必须执行这样的原始查询,它将搜索具有 name === "%foo%" 的用户:

      knex.raw('select * from users where name like ? escape \', ['\%foo\%'])
      

      而且,在搜索词的开头使用未转义的通配符,将搜索 name"%foo%" 结尾的用户:

      knex.raw('select * from users where name like ? escape \', ['%\%foo\%'])
      

      [1] 关闭功能请求:https://github.com/knex/knex/issues/648

      【讨论】:

      • 通过阅读 SQL 文档,这种做法是有意义的并且可以工作。虽然knex('users').whereRaw('?? like ? escape \\%, ['name', '%\\%foo%']) 可能更接近工作解决方案。
      【解决方案5】:

      你有没有试过这个

      knex('Quotes').where('quoteBody', 'like', **'%'+Quote+'%'**)
      
      

      只是常规的 javascript 转义就可以了。

      【讨论】:

        【解决方案6】:

        @coockoo 对这两个 SQL 的回答都不正确。他们的第一个仍然允许% 通过,因为Knex 不会为LIKE 操作逃脱%。第二个 SQL 根本不起作用,因为 Knex 用引号包裹了绑定值

        正确的方法应该是

        const term = '10%'
        const b = knex('table').where('description', 'like', `%${term.replaceAll('%', '\\%')}%`)
        

        b.toString() 的输出为:

        select * from "table" where "description" like E'%10\\%%'
        

        Postgres 会将E'\\%' 解释为'\%',这是一个转义的百分号,根据:https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE 默认情况下,如果您使用的是较新的 Postgres 版本。


        这可以用这张表来验证:

        CREATE TABLE test (
            description character varying(256)
        );
        
        INSERT INTO test VALUES ('a%b');
        

        并测试以下内容:

        1. 不要像其他人建议的那样转义%。这不应该工作
        knex('test').where('description', 'like', 'a%%%b').toString()
        
        select * from "test" where "description" like 'a%%%b'
        
         description
        -------------
         a%b
        (1 row)
        
        1. 在给 Knex 之前转义 %

          1. 这应该不返回任何行:
          knex('test').where('description', 'like', 'a\\%\\%\\%b').toString()
          
          select * from "test" where "description" like E'a\\%\\%\\%b'
          
           description
          -------------
          (0 rows)
          
          1. 这应该返回'a%b':
          knex('test').where('description', 'like', 'a\\%b').toString()
          
          select * from "test" where "description" like E'a\\%b'
          
           description
          -------------
           a%b
          (1 row)
          

        SQL 小提琴:http://sqlfiddle.com/#!17/d2f5e/1

        【讨论】:

          【解决方案7】:

          所以我一直在寻找一种将 LOWER 函数应用于参数的正确方法。这是对我来说似乎工作正常的解决方案:

          builder.whereRaw('LOWER(last_name) LIKE LOWER(?)', [`%${lastName}%`])
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-14
            • 1970-01-01
            相关资源
            最近更新 更多