Laravel Eloquent захватывает дубликаты (2 или более результатов)

Итак, у меня есть следующий запрос, который работает:

Expense::select('amount', 'date', DB::raw('COUNT(*) as `count`'))
        ->groupBy('amount', 'date')
        ->havingRaw('COUNT(*) > 1')
        ->get();

Это нужно для того, чтобы захватить все expenses, которые являются потенциальными дубликатами (такая же сумма и та же дата). Однако я хочу схватить все, а не только amount и date. Не работает следующее:

    return Expense::select('name', 'amount', 'date', DB::raw('COUNT(*) as `count`'))
        ->groupBy('amount', 'date')
        ->havingRaw('COUNT(*) > 1')
        ->get();

Это даст мне эту ошибку:

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of the SELECT list is not in the GROUP BY clause and contains a nonaggregated column

У меня есть еще много полей для Expense, которые я хочу перечислить, на мой взгляд, самое главное, конечно, имя, но также и слаг, чтобы я мог ссылаться на каждый потенциальный дубликат и т. д.

Также вторая "проблема", но не самая важная, заключается в том, что при указанном выше запросе все расходы возвращаются одной коллекцией. Например, они не сгруппированы по дате.

Наиболее желательным было бы иметь примерно такие результаты. Все потенциальные дубликаты должны быть сгруппированы по дате, чтобы я мог сделать что-то вроде этого, на мой взгляд:

@foreach($duplicates as $date => $expenses)

    @foreach($expenses as $expense)

    {{ $date }}

    // List all expenses for that date.. etc.

Вопрос 1: Как сделать так, чтобы приведенный выше запрос работал со всеми полями базы данных, а не только с date и amount?

Вопрос 2: Как я могу получить потенциальные дубликаты и сгруппировать их по дате, чтобы я мог перебирать даты и расходы, как в приведенном выше примере?

🤔 А знаете ли вы, что...
PHP поддерживает разнообразные базы данных, включая MySQL, PostgreSQL и SQLite.


53
1

Ответ:

Решено

Всегда правильно обрабатывайте столбец при группировке

э.и. вы можете указать все поля, которые вы хотите выбрать в groupBy

// database query
$expenses = Expense::select(['amount', 'date', 'name', 'slug'])
                    ->selectRaw('count(*) AS count')
                    ->havingRaw('count > 1')
                    ->groupBy(['amount', 'date', 'name', 'slug'])
                    ->get();

// Another date grouping done in collection
return $expenses->groupBy('date');

или что-то вроде расчесывания столбцов, принадлежащих к желаемой группе

return Expense::select('date')
    ->selectRaw('group_concat(name) as names') // comma separated names belongs to the group 
    ->selectRaw('group_concat(amount) as amounts') // comma separated amounts belongs to the group 
    ->selectRaw('group_concat(slug) as slugs')// comma separated slugs belongs to the group 
    ->selectRaw('count(*) AS count')
    ->havingRaw('count > 1')
    ->groupBy('date')
    ->get();

РЕДАКТИРОВАТЬ

Если вы хотите сгруппировать их только по дате и при этом иметь фактические повторяющиеся строки, вы можете просто добавить еще один оператор выбора для подсчета дубликатов даты, не группируя их по дате в своем запросе, и выполнить группировку даты в коллекции.

э.и.

$expenses  = Expense::select( ['amount', 'date', 'name', 'slug'] )
    ->selectRaw('(SELECT COUNT(date) FROM expenses t1 WHERE t1.date = expenses.date ) as duplicates')
    ->havingRaw('duplicates > 1')
    ->get();

return $expenses->groupBy('date');

Затем в выходных данных должен быть еще один столбец duplicates, в котором указано количество дубликатов каждой даты, а также все строки для повторяющихся дат.