SQL:按一些ID合并两行并保留值

I'm facing a relatively easy problem but I can't manage to wrap my head around a solution. Keep in mind I'm using PHP with the Laravel framework if it can makes things any easier.

I have a table filled with data like so :

ID | TRANSACTION_ID | BEACON_TYPE
---+----------------+---------------
 1 |       1        |  "abc"
 2 |       2        |  "def"
 3 |       2        |  "xyz"

and I would like to group them by transaction ID and to keep the beacon type inside the data like so:

ID | TRANSACTION_ID | BEACON_TYPE
---+----------------+---------------
 1 |       1        |  "abc"
 2 |       2        |  "def", "xyz"

I've tried using group by with no avail. Any ideas or hints on how to accomplish that? As I said earlier there might be some way to do it with Laravel Eloquent.

Assuming you're using MySQL, the function you're looking for is GROUP_CONCAT(). Using Eloquent, it would look something like this:

$transactions = DB::table('tableName')
                  ->select('TRANSACTION_ID', DB::raw('GROUP_CONCAT(BEACON_TYPE SEPARATOR ', ') as BEACON_TYPE'))
                  ->groupBy('TRANSACTION_ID')
                  ->get();

Note, if you want to change the separator, you just need to edit the ', ' to something else. The default separator is ','.

Use GROUP_CONCAT() to concatenate values of the group. Give it a SEPARATOR of ', ' to get the groups with comma separated values.

Your expected result is going to lose some information, since the IDs of the grouped row will be both 2 and 3 (in your example). So either don't select those IDs, or add them with a separate GROUP_CONCAT().

The raw SQL query would be using GROUP_CONCAT(). The following queries use the table foo, replace that with your actual table name.

SELECT TRANSACTION_ID, 
       GROUP_CONCAT(BEACON_TYPE SEPARATOR ', ') AS BEACON_TYPE
FROM foo
GROUP BY TRANSACTION_ID

Using Eloquent, you need to use DB::raw() to select the GROUP_CONCAT() part, as there's no Eloquent method for GROUP_CONCAT(), so then it becomes

$result = DB::table('foo')
            ->select('TRANSACTION_ID',
                      DB::raw("GROUP_CONCAT(BEACON_TYPE SEPARATOR ', '") as BEACON_TYPE)
            ->groupBy('TRANSACTION_ID');

or if you want to include the grouped IDs to, then..

$result = DB::table('foo')
            ->select('TRANSACTION_ID',
                      DB::raw("GROUP_CONCAT(BEACON_TYPE SEPARATOR ', '") as BEACON_TYPE),
                      DB::raw("GROUP_CONCAT(ID SEPARATOR ', '") as ID)
            ->groupBy('TRANSACTION_ID');

If you already have the data from the database and just want to use collection functions you can do the following:

    $things = $things->groupBy('TRANSACTION_ID')
            ->map(function($x) {
                $beaconTypes = $x->implode('BEACON_TYPE', ', ');
                $firstThing = $x->first();
                $firstThing['BEACON_TYPE'] = $beaconTypes;

                return $firstThing;
            });