Eloquent:获取具有唯一列值的记录,并带有后备

时间:2017-01-06 19:12:52

标签: mysql eloquent

我们说我有下表:

id | name   | parent_id
-- | ------ | ---------
1  | monkey | NULL
2  | nut    | NULL
3  | mies   | NULL
4  | monkey | 1
5  | nut    | 1

现在,我想要使用唯一name获取所有记录,最好使用parent_id = 1,否则使用parent_id IS NULL。因此查询的结果将返回记录[3, 4, 5]

如何用Eloquent实现这一目标?

我已尝试将groupBy( 'name' )orderBy( 'entity_id', 'desc' )结合使用,但groupBy似乎在orderBy之前执行,因此如果我在asc之间切换,结果始终相同{1}}和desc条款中的orderBy

我也试过玩distinct()而没有任何运气。

更新

当然,我可以执行两个查询并合并结果,但我想知道是否可以使用单个查询完成此操作。

更新2

目前,我在Eloquent的unique()课程中使用Collection方法解决了这个问题:

$parent = Parent::find( 1 );
$items  = $parent->items()
                 ->orWhereNull( 'parent_id' )
                 ->orderBy( 'parent_id', 'desc' )
                 ->get()
                 ->unique( 'name' );

1 个答案:

答案 0 :(得分:1)

方法#1:

GROUP BY name上使用aggregateMAX功能时,您需要先parent_id max_parent_id。因此,您的偏好是保留的。

稍后在加入NULL时,您需要检查NULL。因为IS NULL只能使用IS NOT NULL中的MySQLmax_parent_id进行比较。如果name的{​​{1}}为NULL,那么您应该在最终结果集中允许它(请参阅本案例中如何使用IF

SELECT 
 YT.*
FROM your_table YT 
INNER JOIN 
(
    SELECT 
     name,
     MAX(parent_id) AS max_parent_id 
    FROM your_table
    --WHERE parent_id IS NULL OR parent_id IN (1)
    GROUP BY name
) AS t
ON YT.name = t.name AND 
   IF(t.max_parent_id IS NULL, TRUE, YT.parent_id = t.max_parent_id); 

See Demo

方法#2:

使用MySQL user-defined variables您也可以实现这一目标。

方法#2 比例

SELECT 
t.id,
t.name,
t.parent_id
FROM 
(
    SELECT 
        IF(@prev_name = name, @rn := @rn + 1,
           IF(@prev_name := name, @rn := 1, @rn := 1)
           ) AS rank,
        your_table.*
    FROM your_table 
    CROSS JOIN 
    (
        SELECT @rn := 0, @prev_name := NULL
    ) AS var
    ORDER BY name, parent_id DESC
) AS t
WHERE t.rank = 1
ORDER BY t.id;

See Demo