【问题标题】:Get last item in each group MySql获取每组MySql中的最后一项
【发布时间】:2016-07-01 23:38:37
【问题描述】:

在第一张桌子上我有订单。在第二个 - 发送给这些订单的消息。我需要从最后一条消息中获取日期和状态(如果消息尚未发送,则为 NULL)对于每个具有 active=1 的订单。通过复合键连接的表 - “order_id + offer”。

“订单”表:

+----------+----------+--------+----------+
| order_id | offer    | active | timezone |
+----------+----------+--------+----------+
|        6 | kopiya   |      1 |        0 |
|        6 | kopiya-3 |      1 |        0 |
|       10 | kopiya   |      1 |      180 |
|       23 | kopiya-2 |      1 |        0 |
|       27 | kopiya-2 |      0 |        0 |
+----------+----------+--------+----------+

“短信”表:

+------+----------+----------+------+--------+---------------------+
| key_ | order_id | offer    | type | status | date                |
+------+----------+----------+------+--------+---------------------+
| 1    |        6 | kopiya   | text |      1 | 2016-06-20 00:00:00 |
| 2    |        6 | kopiya-3 | text |      0 | 2016-06-21 00:00:00 |
| 3    |       10 | kopiya   | text |      0 | 2016-06-27 00:00:00 |
| 4    |       27 | kopiya-2 | text |      1 | 2016-06-21 00:00:00 |
| 6    |        6 | kopiya-3 | text |      1 | 2016-06-23 00:00:00 |
+------+----------+----------+------+--------+---------------------+

结果将是:

+----------+----------+---------------------+--------+
| order_id | offer    | last_date           | status |
+----------+----------+---------------------+--------+
|        6 | kopiya   | 2016-06-20 00:00:00 |      1 |
|        6 | kopiya-3 | 2016-06-23 00:00:00 |      1 |
|       10 | kopiya   | 2016-06-27 00:00:00 |      0 |
|       23 | kopiya-2 | NULL                |   NULL |
+----------+----------+---------------------+--------+

此查询无法正常工作:

SELECT o.order_id, o.offer, max(date) as last_date, status
FROM orders AS o
LEFT JOIN sms AS s
ON o.order_id=s.order_id AND o.offer=s.offer
WHERE `active` = 1
GROUP BY o.order_id, o.offer;

它显示:

+----------+----------+---------------------+--------+
| order_id | offer    | last_date           | status |
+----------+----------+---------------------+--------+
|        6 | kopiya   | 2016-06-20 00:00:00 |      1 |
|        6 | kopiya-3 | 2016-06-23 00:00:00 |      0 |
|       10 | kopiya   | 2016-06-27 00:00:00 |      0 |
|       23 | kopiya-2 | NULL                |   NULL |
+----------+----------+---------------------+--------+

对于键“6 kopiya-3”,它返回 status=0 但预期为 1,因为它从第一行而不是具有最大日期的行获取此值。我该如何解决这个问题?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    这是否与 Unix One 的答案相同,只是格式不同? 如果是这样,那么他们就打败了我 - 但请注意,这假定在 (order_id,offer) 上进行 PK,并返回与请求的结果集略有不同的结果集。

    SELECT o.order_id
         , o.offer
         , s.date last_date
         , s.status
      FROM orders o 
      LEFT
      JOIN 
         ( SELECT x.* 
             FROM sms x
             JOIN 
                ( SELECT order_id
                       , offer
                       , MAX(date) date 
                    FROM sms 
                   GROUP 
                      BY order_id
                       , offer
                ) y 
               ON y.order_id = x.order_id 
              AND y.offer = x.offer
              AND y.date = x.date
          ) s
         ON s.order_id = o.order_id 
        AND s.offer = o.offer 
      WHERE o.active = 1;
    

    【讨论】:

    • 不,看来你比我早了几分钟。但是,关于此查询的注意事项:当您在 order_idofferdate 上加入 y 时,不能保证只有一行 - 从理论上讲,可能有 >1 行具有相同的值这些字段,在这种情况下,您最终会得到重复项。如果您想使用MAX(date),您可能需要另一个子选择来获取MAX(key_)(或者您要确定要返回的“最后”行)。
    • 是的。我假设在(order_id,offer) 上进行 PK。
    • 对不起,我什么都不懂。
    • 1) 没问题,因为在我的情况下,每个order_id+offer 组中只有唯一的日期。 key_ 我从另一个 api 获得,它看起来像 md5,所以最大 key_ 不指最后一行。 2)这个查询不是很快 - 1.3 秒,大约 10,000 行。 100,000 或更多会是什么?我在orders.order_id_offer 上有索引。 sms.order_id_offersms.datesms.key_。我可以更快地添加额外的索引吗?
    【解决方案2】:
    SELECT o.order_id, o.offer, max(date) as last_date, (select (SELECT sd.status FROM sms sd WHERE sd.order_id=o.order_id AND sd.offer=s.offer ORDER BY sd.key_ DESC LIMIT 1) as 'st' case when st = '1' then '1' else '0' end) as status
    FROM orders AS o
    LEFT JOIN sms AS s
    ON o.order_id=s.order_id AND o.offer=s.offer
    WHERE `active` = 1
    GROUP BY o.order_id, o.offer;
    

    如果我的语法正确,这可能会起作用

    旁注:我的回答很糟糕,哈哈

    【讨论】:

      【解决方案3】:
      SELECT
        o.order_id,
        o.offer,
        s3.`date` AS last_date,
        s3.status
      FROM
        orders o
        LEFT JOIN
          (SELECT
             s1.order_id,
             s1.offer
           FROM
             sms s1
             JOIN
               (SELECT
                  MAX(key_) AS key_
                FROM
                  sms
                GROUP BY
                  order_id,
                  offer) s2 ON s1.key_ = s2.key_) s3 ON (o.order_id = s3.order_id AND o.offer = s3.offer)
      

      【讨论】:

        【解决方案4】:

        Bingo,问题是你把GROUP BY放在哪里:

        SELECT o.order_id, o.offer, max(date) as last_date, status
        FROM orders AS o
        LEFT JOIN sms AS s
        ON o.order_id=s.order_id AND o.offer=s.offer
        WHERE `active` = 1
        GROUP BY o.order_id, o.offer;
        

        这会导致以下结果:

        WITH C AS (SELECT --columns
        FROM Orders AS A
        WHERE O.Active = 1
        GROUP BY O.Order_ID, O.Offer)
        
        SELECT --columns
        FROM C
        INNER JOIN sms AS S ON O.Order_ID = S.order_ID
                           AND O.Offer = S.Offer;
        

        由于 group by 不是确定性的,因此您会遇到错误。 相反,尝试这样的事情:

        SELECT B.ORDER_ID, A.OFFER, B.Status, B.DATE
        FROM Orders A
        INNER JOIN (SELECT Order_ID, Offer, MAX([DATE]) AS [DATE], MAX(Status) AS [Status]
                    FROM #EXAMPLE2
                    GROUP BY Order_ID, OFFER) B ON A.Offer = B.OFFER 
                                           AND A.Order_ID = B.Order_ID
        WHERE ACTIVE = 1;
        
        Results:
        -- 6    kopiya      1       2016-06-20 00:00:00.000
        -- 27   kopiya-2    1       2016-06-21 00:00:00.000
        -- 6    kopiya-3    1       2016-06-23 00:00:00.000
        -- 23   kopiya-2    NULL    NULL
        

        现在,Orders 表上的谓词完成了它应该做的事情,并过滤了结果。

        【讨论】:

        • 哎呀,读错了(只用了一半的结果。xD)
        【解决方案5】:

        我认为这是你想要的:

        select sms.*
        from orders o left join
             sms
             on o.order_id = sms.order_id and o.offer = sms.offer
        where sms.date = (select max(sms2.date)
                          from sms sms2
                          where sms2.order_id = sms.order_id and sms2.offer = sms.offer
                         ) or
              sms.order_id is null
        

        对于这个查询,我建议在sms(order_id, offer, date) 上建立索引。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-27
          • 2011-03-14
          • 2022-01-19
          • 1970-01-01
          • 1970-01-01
          • 2017-09-29
          • 2016-07-23
          • 2015-09-29
          相关资源
          最近更新 更多