我有一个连接自己的查询,以获取每个唯一列表的最新或最旧订单记录。
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查询问题,不得不单独查询每个列表。
答案 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。