有没有办法根据MySQL中的CASE动态定义运算符?

时间:2016-12-02 13:42:26

标签: php mysql join left-join

我有一个连接自己的查询,以获取每个唯一列表的最新或最旧订单记录。

SELECT
    lists.ordered,
    cnt1.*
FROM 
    cnt_lists as cnt1
    LEFT JOIN 
        lists
        on 
            cnt1.list_id = lists.id
    LEFT JOIN 
        cnt_lists as cnt2
        on 
            (cnt1.list_id = cnt2.list_id AND cnt1.id < cnt2.id)

WHERE
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') and cnt1.listable_type = 'Movie';

此查询效果很好,但lists.ordered可以是0或1.当lists.ordered = 0我希望on语句中的运算符为cnt1.id < cnt2.id但是当lists.ordered = 1我希望它被颠倒cnt1.id > cnt2.id时。

有没有办法根据CASE语句动态定义运算符?以下不起作用,但我正在玩想法。

SELECT
    lists.ordered,
    CASE
        WHEN lists.ordered = 1 THEN '>'
        ELSE '<'
    END AS operator,
    cnt1.*
FROM 
    cnt_lists as cnt1
    LEFT JOIN 
        lists
        on 
            cnt1.list_id = lists.id
    LEFT JOIN 
        cnt_lists as cnt2
        on 
            (cnt1.list_id = cnt2.list_id AND cnt1.id operator cnt2.id)

WHERE
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') and cnt1.listable_type = 'App\\Models\\Movie';

如何为每个列表提取最高顺序和最低顺序的方法,我可以确定在PHP端使用哪两条记录?

我只是在寻找想法,因为我试图避免N + 1查询问题,不得不单独查询每个列表。

1 个答案:

答案 0 :(得分:2)

依赖动态查询很麻烦。您最好将该运算符拉入查询的WHERE部分并将其与OR配对:

SELECT
    lists.ordered,
    cnt1.*
FROM 
    cnt_lists as cnt1
    LEFT JOIN 
        lists
        on 
            cnt1.list_id = lists.id
    LEFT JOIN 
        cnt_lists as cnt2
        on 
            (cnt1.list_id = cnt2.list_id)

WHERE
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') 
    and cnt1.listable_type = 'Movie'
    AND (
       cnt2.id IS NULL /* Including this here because you have a LEFT JOIN */
       (lists.ordered = 1 AND cnt1.id < cnt2.id) OR 
       (lists.ordered = 0 AND cnt1.id > cnt2.id)
    );

您的另一个选择是直接将该逻辑放入连接逻辑。这可能更容易阅读。

SELECT
    lists.ordered,
    cnt1.*
FROM 
    cnt_lists as cnt1
    LEFT JOIN 
        lists
        on 
            cnt1.list_id = lists.id
    LEFT JOIN 
        cnt_lists as cnt2
        on 
            (cnt1.list_id = cnt2.list_id AND (
       (lists.ordered = 1 AND cnt1.id < cnt2.id) OR 
       (lists.ordered = 0 AND cnt1.id > cnt2.id)
    ))

WHERE
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') 
    and cnt1.listable_type = 'Movie'
    ;

您可以选择在最终输出中加入<,但这不会特别有用。

如果您 * REALLY * 想要创建动态查询,则很难一步完成but it is definitely doable