MySQL / MariaDB / SQLite:DISTINCT CONCAT

时间:2018-03-26 10:46:49

标签: mysql laravel laravel-5 sqlite

这个问题不一定只与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为14的记录 - 因为23具有相同的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的记录具有更高的命中数,则其兄弟那么兄弟姐妹不会被退回。

1 个答案:

答案 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();