这个问题不一定只与Laravel相关,但我正在尝试获取记录,这些记录由连接字段区分。我需要将其与MySQL/MariaDB
以及SQLite
一起用于测试目的。
在进行我的研究时,我发现SQLite
没有CONCAT
函数 - 而是使用||
运算符来连接项目。另一方面,MySQL
不会以同样的方式解释||
,但我总是可以使用条件语句来涵盖这两种情况。
然而,我仍然无法获得我追求的记录 - 我的表格包括:
| id | tagable_id | tagable_type | name | title | description | url | image | hits |
| 1 | 1 | App\Models\Article | a.. | A.. | A.. descr.. | https://localhost | https://localhost... | 0 |
| 2 | 1 | App\Models\Article | b.. | B.. | B.. descr.. | https://localhost | https://localhost... | 2 |
| 3 | 1 | App\Models\Article | c.. | C.. | C.. descr.. | https://localhost | https://localhost... | 3 |
| 4 | 1 | App\Models\Page | a.. | A.. | C.. descr.. | https://localhost | https://localhost... | 0 |
我只需要获得4条记录,这些记录按照匹配数排序ASC,并且使用CONCAT(table_id, tagable_type)
是唯一的。
在这种情况下,语句应返回的内容是ID为1
和4
的记录 - 因为2
和3
具有相同的tagable_id
和{ {1}}作为ID为tagable_type
的记录,其点击次数最少 - 实际上只返回2条记录:
1
我已经尝试过了:
| id | tagable_id | tagable_type | name | title | description | url | image | hits |
| 1 | 1 | App\Models\Article | a.. | A.. | A.. descr.. | https://localhost | https://localhost... | 0 |
| 4 | 1 | App\Models\Page | a.. | A.. | C.. descr.. | https://localhost | https://localhost... | 0 |
然而,这不会返回不同的记录 - 它将返回所有记录,无论是不同的串联 - 在MySQL / MariaDB中 - 在SQLite中它会告诉我DB::table('tags')
->selectRaw("DISTINCT CONCAT(`tagable_id`, '-', `tagable_type`), `id`, `name`, `title`, `description`, `url`, `image`")
->whereIn('name', $tags->toArray())
->orderBy('hits');
。
我也尝试过:
no such function: CONCAT
这次MySQL / MariaDB告诉我,我需要在组中包含其他字段DB::table('tags')
->selectRaw("CONCAT(`tagable_id`, '-', `tagable_type`) as `identifier`, `id`, `name`, `title`, `description`, `url`, `image`")
->whereIn('name', $tags->toArray())
->groupBy('identifier')
->orderBy('hits');
,但是当我将其与SQLite一起使用并将tags.id' isn't in GROUP BY
函数替换为CONCAT
时 - 它似乎有用。
所以在这个阶段我是:(tagable_id || '-' || tagable_type) as identifier
非常感谢任何帮助。
更新
经过几个小时试图解决它后,我决定添加一个新列
MySQL: 0 | SQLite: 1
到表中以克服不可用identifier
函数的问题 - 我的代码现在看起来像这样:
concat
这仍然不是我所追求的,因为它依赖于给定标识符的最低id Tag::with('tagable')->whereIn('id', function($query) use ($tags) {
$query->selectRaw('min(`id`) from `tags`')
->whereIn('name', $tags->toArray())
->groupBy('identifier');
})
->orderBy('hits')
->take(4)
->get();
,并且如果具有相同标识符的最低id的记录具有更高的命中数,则其兄弟那么兄弟姐妹不会被退回。
答案 0 :(得分:1)
您可以使用DISTINCT
获取不同的组合,但不能使用整行:
DB::table('tags')->distinct()->get(['tagable_id', 'tagable_type']);
您必须使用更复杂的查询:
$join = DB::table('tags')
->select('tagable_id', 'tagable_type')->selectRaw('MIN(hits) as hits')
->whereIn('name', $tags->toArray())
->groupBy('tagable_id', 'tagable_type');
$sql = '(' . $join->toSql() . ') as grouped';
$tags = DB::table('tags')
->join(DB::raw($sql), function($join) {
$join->on('tags.tagable_id', '=', 'grouped.tagable_id')
->on('tags.tagable_type', '=', 'grouped.tagable_type')
->on('tags.hits', '=', 'grouped.hits');
})->mergeBindings($join)
->whereIn('name', $tags->toArray())
->get();
保证每个唯一组合一条记录的解决方案:
$join = DB::table('tags')
->select('tagable_id', 'tagable_type')->selectRaw('MIN(hits) as hits')
->whereIn('name', $tags->toArray())
->groupBy('tagable_id', 'tagable_type');
$sql = '(' . $join->toSql() . ') as grouped';
$ids = DB::table('tags')
->selectRaw('MIN(id) as id')
->join(DB::raw($sql), function($join) {
$join->on('tags.tagable_id', '=', 'grouped.tagable_id')
->on('tags.tagable_type', '=', 'grouped.tagable_type')
->on('tags.hits', '=', 'grouped.hits');
})->mergeBindings($join)
->whereIn('name', $tags->toArray())
->groupBy('tags.tagable_id', 'tags.tagable_type')
->pluck('id');
$tags = DB::table('tags')->whereIn('id', $ids)->get();