当变量为false时,where子句不会将其考虑在SQL查询中?

12

我有一些不太理解的问题,我有解决方案,但是我不知道为什么,这让我有点疯狂。

控制器

DB::connection()->enableQueryLog();

$transfer = Transfer::where('ticket_id', $last_ticket)->where('event_id', 36)->where('buyer', $user_email)->first();

$queries = DB::getQueryLog();

dd($queries);

结果

array:1 [
  0 => array:3 [
    "query" => "select * from `transfers` where `ticket_id` = ? and `event_id` = ? and `buyer` = ? limit 1"
    "bindings" => array:3 [
      0 => false
      1 => 36
      2 => "[email protected]"
    ]
    "time" => 0.36
  ]
]

情况: 数据库中的$last_ticket是唯一的,从来不会是null,空或false

在我的例子中$last_ticketfalse,但在数据库中没有任何false,为什么我还是得到了结果?

是因为只要一个条件为false,它就不被考虑在内了吗?

所以问题是: 我该怎么做才能获得正确的结果:如果$last_ticket为false,则没有结果,如果它有一些数据,则返回被$last_ticket限制的行结果

一个选项是将if($last_ticket == false){$last_ticket='randomInexistentString_ag4dh&2g32y4t'}放入代码中,这样它就不为空或零,但我认为这不是更好的方法


请提供“转移”表模式,特别是“ticket_id”列的数据类型和约束条件。 - llouk
返回结果集中的ticket_id字段的值是多少?(我猜是0)。 - Shadow
@Shadow 是假的,可能与0相同。 - TrOnNe
我对返回值感兴趣,而不是您提供的参数。这将告诉我们发生了什么。 - Shadow
啊抱歉,根据帖子中的调试结果,您所说的返回值也是false。或者您在询问另一个值? - TrOnNe
2个回答

13

在 MySQL 中,0 总是匹配任何不以数字开头的字符串 - 这是因为它希望比较的两侧类型相同,所以将字符串转换为数字,并且任何不以数字开头的字符串都会自动评估为 0。

现在,您没有传递给它一个 0 - 但是您传递给它一个 false,在 MySQL 中,这不是一个真正的布尔值,实际上是一个 0。

不知道您的数据库具体情况,我想这可能是最可能的解释。

有一些解决办法,例如您可以在 Eloquent 上使用 ->when() 链式调用:

Transfer::where('event_id', 36)
        ->where('buyer', $user_email)
        ->when($last_ticket, function ($query) use ($last_ticket) {
            $query->where('ticket_id', $last_ticket);
        })
        ->first();

(从记忆中取出,语法可能有点偏差。感谢Rick James在评论中的纠正。)


哦,谢谢,我不知道0的情况,如果我输入null呢? - TrOnNe
1
你的额外问题有点奇怪 - 这是一个纯 if 条件,那么为什么不直接这样做 if ($last_ticket) { do things } else { don't do things } - Joel Hinz
1
@JoelHinz - 不是的。零可以匹配任何不以数字开头的字符串。在将字符串转换为数字时,如果有前导数字,则会将其消耗掉。 - Rick James
@TrOnNe - ticket_id = NULL 并不像你想象中的那样起作用 -- 你需要写成 ticket_id IS NULL - Rick James
@RickJames,以数字开头和以数值开头有什么不同?英语是我的第四种语言,所以我可能会错过一些与MySQL无关的东西。 - Joel Hinz
显示剩余4条评论

2
重新设计用户界面。如果查询中应该省略某些内容,则不要在查询中包含它。
也就是说,动态构建WHERE子句,这样当提供“false”时,它就变成:
WHERE `event_id` = ? and `buyer` = ?

我不了解Laravel,但在PHP中,我会构建一个数组来将要“AND”在一起的条件组合起来,然后构造“WHERE”语句:

$ands = array();
if (...)  $ands[] = "ticket_id = ...";
if (...)  $ands[] = "event_id = ...";
if (...)  $ands[] = "buyer = ...";

if (empty($ands))
    $where = '';
else
    $where = 'WHERE ' . implode(' AND ', $ands);

$sql = "SELECT ... $where ...";

请注意,它可以轻松处理任何一个、全部或没有项目被省略的情况。

在Laravel的查询构建器中,您可以传递一个条件数组:->where(['ticket_id' => 7, 'event_id' => 5])。请参见此处的第一条评论。您甚至可以传递一个空数组,这样您就不需要检查 if (empty($ands)) - Paul Spiegel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接