【问题标题】:How to order a table based on null values?如何根据空值对表进行排序?
【发布时间】:2020-01-10 20:17:59
【问题描述】:

我有一个warehouse 表。它有一个名为level 的列。我想对它进行升序排序,如果level 为空,那么它应该根据id 降序排序。

例如。我的表有以下记录。

+----+-----------+-------+
| id | name      | level |
+----+-----------+-------+
| 1  | osaka     | 3     |
+----+-----------+-------+
| 2  | tokyo     | null  |
+----+-----------+-------+
| 3  | sapporo   | null  |
+----+-----------+-------+
| 4  | nagoya    | 4     |
+----+-----------+-------+
| 5  | hiroshima | 1     |
+----+-----------+-------+

首先基于级别列,它应该对广岛->大阪->名古屋进行排序。其余为空。因此它们将根据 id 列进行降序排序。所以,它将是札幌->东京。 因此,最终排序结果将是广岛->大阪->名古屋->札幌->东京。

到目前为止,我已经尝试过了,

$warehouses = Warehouse::orderby('level','asc)
                         ->pluck('name');
dd($warehouses);

这显然行不通。但我不确定如何前进。我正在使用 PGSQL。

我在 SO 中发现了类似的问题。我已经尝试了一些基于此的原始查询。仍然无法解决问题。

【问题讨论】:

    标签: laravel postgresql eloquent


    【解决方案1】:

    这样的事情怎么样:

    1. 从表中获取所有内容。
    2. 使用收集的结果得到所有不为空的级别,然后对它们进行排序。
    3. 使用收集的结果获取所有空级别,然后对其进行排序。
    4. 合并2个排序的集合结果并提取名称。
    // 1. Get all from the table.
    $warehouses = Wharehouse::all();
    
    // 2. Using the collected results get all without null levels then sort them.
    $warehousesWithLevels = $warehouses->where('level', '!=', null)
                                            ->sortBy('level');
    
    // 3. Using the collected results get all with null levels then sort them.
    $warehousesWithoutLevels  = $warehouses->where('level', null)
                                            ->sortByDesc('id');
    
    // 4. Merge the 2 sorted collection results and pluck the name.
    $warehousesSorted = $warehousesWithLevels->merge($warehousesWithoutLevels)->pluck('name');
    
    dd($warehousesSorted);
    
    

    或者配合我在模型中创建的Scope你可以使用:

    Wharehouse::allSortedMyWay();
    

    上面有一个数据库查询,然后处理收集的结果。

    您可以修改最适合您需要的任何键的排序。

    测试结果如下:

    Collection {#268 ▼
      #items: array:5 [▼
        0 => "hiroshima"
        1 => "osaka"
        2 => "nagoya"
        3 => "sapporo"
        4 => "tokyo"
      ]
    }
    

    我使用的型号:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Wharehouse extends Model
    {
        /**
         * The database table used by the model.
         *
         * @var string
         */
        protected $table = 'warehouses';
    
        /**
         * Indicates if the model should be timestamped.
         *
         * @var bool
         */
        public $timestamps = false;
    
        /**
         * The attributes that are not mass assignable.
         *
         * @var array
         */
        protected $guarded = [
            'id',
        ];
    
        /**
         * Fillable fields for a Profile.
         *
         * @var array
         */
        protected $fillable = [
            'name',
            'level',
        ];
    }
    
        /**
         * Return all warehousts sorted my way - Quick but not a true query scope.
         *
         * @return collection
         */
        public function scopeAllSortedMyWay()
        {
            $warehouses = Wharehouse::all();
    
            $warehousesWithLevels = $warehouses->where('level', '!=', null)
                                                    ->sortBy('level');
    
            $warehousesWithoutLevels  = $warehouses->where('level', null)
                                                    ->sortByDesc('id');
    
            return $warehousesWithLevels->merge($warehousesWithoutLevels)->pluck('name');
        }
    
    

    我使用的播种机:

    <?php
    
    use App\Wharehouse;
    use Illuminate\Database\Seeder;
    
    class WharehouseTableSeeder extends Seeder
    {
        /**
         * Run the database seeds.
         *
         * @return void
         */
        public function run()
        {
            $items = [
                [
                    'name'   => 'osaka',
                    'level'   => 3,
                ],
                [
                    'name'   => 'tokyo',
                    'level'   => null,
                ],
                [
                    'name'   => 'sapporo',
                    'level'   => null,
                ],
                [
                    'name'   => 'nagoya',
                    'level'   => 4,
                ],
                [
                    'name'   => 'hiroshima',
                    'level'   => 1,
                ],
            ];
    
            foreach ($items as $item) {
                $newItem = Wharehouse::where('name', '=', $item['name'])->first();
    
                if ($newItem === null) {
                    $newItem = Wharehouse::create([
                        'name'         => $item['name'],
                        'level'        => $item['level'],
                    ]);
                }
            }
        }
    }
    

    我使用的迁移:

    <?php
    
    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;
    
    class CreateWarehouseTable extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('warehouses', function (Blueprint $table) {
                $table->bigIncrements('id');
                $table->string('name')->unique();
                $table->integer('level')->nullable();
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('warehouses');
        }
    }
    

    【讨论】:

      【解决方案2】:

      使用以下所有空值项目将是最后一个

      SELECT * FROM warehouse ORDER BY ISNULL(level), level ASC;
      

      这里是SQLFiddle

      【讨论】:

        【解决方案3】:

        你可以使用:

        SELECT
           *
        FROM
           warehouse
        ORDER BY
           CASE WHEN level IS null THEN 1 ELSE 0 END, level, id;
        

        你可以try here

        【讨论】:

        • 我试过了。它首先给出了札幌->东京。他们最终应该是。如何强制 null 值放在最后?如果可能的话,给我雄辩的查询,我可以在 laravel 中使用。
        • 我已经编辑了我的答案。试试它是否能给你想要的结果。
        • 它给出错误“订单方向必须是“asc”或“desc”。”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-29
        • 2014-07-13
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多