MySQL选择每组嵌套的前n条记录

时间:2017-11-02 15:20:49

标签: mysql greatest-n-per-group

我试图从MySQL(版本:5.6.29和10.1.28-MariaDB)获得前n个(现在2个)行。 我在SO或其他地方看过简单的例子(example1example2) 问题是我的查询更复杂,而且看起来效果不好。

我有图表所示的表格(为简洁起见,删除了一些字段):

EER

每个purchase_item可以是优惠券,purchase_offer或subscription_plan(一个有效,另外两个为空)。其中每个都有subscription_days > 0

Innermost SELECT本身就能按预期工作。第二个SELECT没有按预期工作(即使我删除了外部选择),purchase_rank对于相同的customer_uuid通常是相同的,就好像最里面的选择不按customer_uuid排序

有什么想法吗?我read ORDER BY在嵌套查询中不能正常工作或许这是我的问题吗?那我该怎么办呢? 或者查询优化器可能正在做一些奇怪的事情?我尝试用IF替换CASE,结果一样。 这是代码:

SELECT 
    id,
    uuid,
    purchase_offer,
    subscription_plan,
    coupon,
    customer_uuid,
    payment_date,
    subscription_days,
FROM
    (SELECT 
        id,
            uuid,
            purchase_offer,
            subscription_plan,
            coupon,
            customer_uuid,
            payment_date,
            subscription_days,
            @purchase_rank := CASE @current_customer
                WHEN customer_uuid THEN @purchase_rank + 1
                ELSE 1
            END AS purchase_rank,
            @current_customer:= customer_uuid AS current_customer
    FROM
        (SELECT 
            pi.id,
            pi.uuid,
            pi.purchase_offer,
            pi.subscription_plan,
            pi.coupon,
            pi.customer_uuid,
            p.payment_date,
            IFNULL(po.subscription_days, IFNULL(sp.subscription_days, cpo.subscription_days)) AS subscription_days
    FROM
        purchase_item pi
    JOIN purchase p ON p.id = pi.purchase
    LEFT JOIN purchase_offer po ON pi.purchase_offer = po.id
    LEFT JOIN subscription_plan sp ON pi.subscription_plan = sp.id
    LEFT JOIN coupon cp ON pi.coupon = cp.id
    LEFT JOIN purchase_offer cpo ON cp.purchase_offer = cpo.id
    WHERE
        p.status = 'COMPLETED'
            AND pi.customer_uuid IS NOT NULL
            AND p.payment_date IS NOT NULL
            AND (po.subscription_days > 0
            OR sp.subscription_days > 0
            OR cpo.subscription_days > 0)
    ORDER BY pi.customer_uuid , p.payment_date DESC) AS temp) 
AS pu
WHERE
    pu.purchase_rank <= 2
ORDER BY pu.customer_uuid , pu.payment_date DESC

非常感谢任何帮助。提前致谢。

2 个答案:

答案 0 :(得分:0)

对于MySql查询的这种限制,您只需在语句末尾添加LIMIT 0, 2即可。

有关限制声明的详细信息,请随时查看this documentation with realtime example.

编辑我

例如:从声明中获取前n个结果:

SELECT * FROM purchase
ORDER BY payment_date ASC
LIMIT n

反过来说:

SELECT * FROM purchase
ORDER BY payment_date DESC
LIMIT n

如果您知道要跳过查询的前n个结果,则可以在给定的偏移量处启动LIMIT。例如,我们想跳过前10个结果:

SELECT * FROM purchase
ORDER BY payment_date DESC
LIMIT 10, n

答案 1 :(得分:0)

回答我自己的问题:我找到了this。它似乎在MySQL上运行良好,而不仅仅是MariaDB。嵌套查询需要LIMIT <large number>来创建临时表。所以Cataklysm's answer部分正确,但它不适用于较小的数字(至少不是根据我的测试)。

以下是代码的更正部分:

...
ORDER BY pi.vehicle_uuid , p.payment_date DESC LIMIT 18446744073709551615) temp) pu

感谢您的帮助。