Laravel的查询构建器JSON选择器`field-> key`导致语法错误

时间:2017-09-18 14:50:27

标签: php mysql laravel laravel-5 mariadb

因此,我想通过将某个ID与notifications列进行比较来查询Laravel中的data表。这就是data列的样子:

{
    "Message": "some message",
    "id": 3
}

现在,我需要选择ID等于3的所有通知。以下是我尝试执行此操作的方法:

DB::table('notifications')->where('data->id', '3')->get();

但是这会引发以下错误:

  

SQLSTATE [42000]:语法错误或访问冲突:1064您有   SQL语法错误;查看与您的手册相对应的手册   MariaDB服务器版本,用于在'>' $。" id"'附近使用正确的语法。 =   ?'在第1行(SQL:select * from notifications where   data - >' $" ID"' = 3)

我在这里失去理智,任何人都可以帮助我吗?

4 个答案:

答案 0 :(得分:7)

您的查询没有任何问题。这是你的环境。

问题

Laravel的MySqlGrammar将字段名称中的field->key表示法(在Laravel方面)转换为field->'$.key' - 样式的提取(在MySQL方面):

/**
 * Wrap the given JSON selector.
 *
 * @param  string  $value
 * @return string
 */
protected function wrapJsonSelector($value)
{
    $path = explode('->', $value);

    $field = $this->wrapValue(array_shift($path));

    $path = collect($path)->map(function ($part) {
        return '"'.$part.'"';
    })->implode('.');

    // Here:
    return sprintf('%s->\'$.%s\'', $field, $path);
}

我刚刚确认MariaDB不支持-> extraction operator作为JSON_EXTRACT()函数的别名。但是,相同的查询适用于vanilla MySQL 5.7服务器。

假设这个test表:

╔════╤══════════════════╗
║ id │ payload          ║
╟────┼──────────────────╢
║  1 │ {"a": 1, "b": 2} ║
╚════╧══════════════════╝

使用->提取运算符的查询:

SELECT payload->"$.b" FROM test;

对MariaDB 10.2.8失败,而它对MySQL 5.7.19服务器产生正确的2

解决方案

正确的解决方案取决于您在生产中使用的内容。

替换MariaDB

如果您正在使用MySQL,请在开发环境中将MariaDB替换为MySQL。在由自制软件管理的macOS机器上,它就像:

一样简单
brew services stop mysql
brew uninstall mariadb
brew install mysql
brew services start mysql

您的数据将保持不变。

重写您的查询

但是,如果您在制作中使用MariaDB,则需要重写查询以将JSON_EXTRACT()函数用作Elias already mentioned。正如您所看到的,您需要使用Laravel API更加冗长。

以上查询将是:

SELECT JSON_EXTRACT(payload, "$.b") FROM test;

答案 1 :(得分:3)

我为json支持制作了Laravel MariaDB驱动程序。在此处获取:ybr-nx/laravel-mariadb

答案 2 :(得分:2)

问题是只有 MySQL 支持->运算符,然后查询将在 MariaDB 上失败,但是:

MariaDB MySQL 都支持JSON_EXTRACT函数,该函数解析 JSON 并从中获取值。

您可以通过执行以下查询来解决此问题:

SELECT * FROM notifications WHERE JSON_EXTRACT(`notifications.data`, "$.id") = 5

要使用Laravel's Query Builder执行此操作,您需要使用DB::raw方法:

DB::table('notifications')->where(DB::raw('JSON_EXTRACT(`notifications.data`, "$.id")'), '=', 3);

请尝试并告诉我是否出错。

注意: JSON_EXTRACT()仅适用于MySQL >= 5.7MariaDB >= 10.2.3

谢谢到@Sepehr,我不知道->是一个MySQL运算符,也不存在JSON类型。 : - )

答案 3 :(得分:0)

问题在于->,我认为你有一个名为 $ data var ,其中有一些集合。 如果是这样,那么正确的方法是:

DB::table('notifications')->where($data->id, '3')->get();

或者,如果您有与通知表相关的模型,则:

Notification::where($data->id, '3')->get();

如果Model被称为Notification(遵循Eloquent惯例)

但如果你试图找到所有ID等于3,那么只需:

DB::table('notifications')->where('id', '3')->get();