"选择*来自用户的ID输入为()的用户" ==失败

时间:2020-03-06 14:38:05  来源:igfitidea点击:

我有一个称为sqlf()的函数,它可以模拟准备好的语句。例如,我可以做类似的事情:

$sql = sqlf("SELECT * FROM Users WHERE name= :1 AND email= :2",'Big "John"','[email protected]') ;

由于各种原因,我无法使用准备好的语句,但是我想模仿它们。我遇到的问题是查询

$sql = sqlf("SELECT * FROM Users WHERE id IN (:1)",array(1,2,3) );

我的代码可以用,但是用空数组会失败,例如以下引发mysql错误:

SELECT * FROM Users WHERE id IN ();

有没有人有什么建议?我应该如何将数组转换为空并插入可以插入IN子句的sql中?替换为NULL将不起作用。

解决方案

Null是我们可以保证不在集合中的唯一值。为什么这不是一个选择?其他任何东西都可以看作是潜在集合的一部分,它们都是值。

是否有可能使用sqlf检测空数组并将SQL更改为不具有IN子句?

或者,我们可以对SQL进行后处理,然后再将其传递给"真正的" SQL执行程序,以便删除" IN()"部分,尽管我们必须做各种技巧来查看必须删除哪些其他元素,以便:

SELECT * FROM Users WHERE id IN ();
SELECT * FROM Users WHERE a = 7 AND id IN ();
SELECT * FROM Users WHERE id IN () OR a = 9;

会成为:

SELECT * FROM Users;
SELECT * FROM Users WHERE a = 7;
SELECT * FROM Users WHERE a = 9;

根据SQL的复杂性,这可能会变得棘手,我们基本上需要一个完整的SQL语言解释器。

我能想到的唯一方法是对sqlf()函数进行扫描,以查看是否在" IN("之后立即进行了特定的替换,然后如果传递的变量是空数组,则放入我们肯定不会在该列中:例如"" m,znmzcb ~~ 1"`。这确实是一种hack,但可以使用。

如果我们想进一步扩展它,是否可以更改功能,以便进行不同类型的替换?看起来函数扫描了一个冒号,然后是一个数字。为什么不添加其他类型,如@后跟数字,这对于空数组来说很聪明(这使我们不必扫描和猜测变量是否应该为数组)。

如果类准备函数只是用等效参数替换:1,则可以尝试让查询包含类似(':1')的内容,这样,如果:1为空,则解析为(''),而不会导致解析错误(但是,如果该字段可以具有空白值,则可能会导致不良行为-尽管如果它是int,则这不是问题)。但是,这不是一个很干净的解决方案,我们最好检查一下数组是否为空,并简单地使用缺少" IN(:1)"组件的备用查询版本。 (如果这是WHERE子句中的唯一逻辑,那么大概我们不想选择所有内容,因此根本就不会执行查询。)

我会说将空数组作为IN()子句的参数传递是一个错误。调用此函数时,我们可以控制查询的语法,因此也应该负责输入。我建议在调用函数之前检查参数是否为空。

我将使用零,假设" id"列是自动分配了数字的伪键。

据我所知,大多数品牌数据库中的自动密钥生成器都从1开始。这是一个约定,而不是一个要求(自动编号字段未在标准SQL中定义)。但是这种约定足够普遍,我们可能可以依靠它。

由于零可能永远不会出现在" id"列中,因此当输入数组为空且永远不会匹配时,可以在IN()谓词中使用此值。