如何在 Knex 中像查询一样逃避 %?

Posted

技术标签:

【中文标题】如何在 Knex 中像查询一样逃避 %?【英文标题】:How do I escape % in Knex where like query? 【发布时间】: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);
  // ...

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

谢谢。

【问题讨论】:

【参考方案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');

并测试以下内容:

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

    在给 Knex 之前转义 %

      这应该不返回任何行:
    knex('test').where('description', 'like', 'a\\%\\%\\%b').toString()
    
    select * from "test" where "description" like E'a\\%\\%\\%b'
    
     description
    -------------
    (0 rows)
    
      这应该返回'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%`])

【讨论】:

以上是关于如何在 Knex 中像查询一样逃避 %?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 knex 查询存储在变量中?

如何在 Knex 上使用 EXISTS 进行子查询?

如何在 Knex 查询中执行 MySQL 函数?

如何在 iOS 中像 UITabBarItem 一样设计 UIButton?

如何在Objective-C中像Twitter一样显示预览

如何在 jupyter 中像 pandas Dataframe 一样打印 Pyspark Dataframe