代码之家  ›  专栏  ›  技术社区  ›  HalfBrian

SQL Group by Question-选择要分组的行

  •  1
  • HalfBrian  · 技术社区  · 14 年前

    我有一个跟踪序列号和与该序列号相关联的许可证数量的表。客户机可以重新授权一个设备,增加或减少用户数量,并且只对更改的数量收取费用。

    存在下表结构:

    id - Auto Incrementing ID
    serial - The serial number
    numusers - the number of licenses
    date - The date that the request was submitted, with the highest date being the number of users currently licensed
    

    我有以下查询来选择已更新的许可证,如果仅重新提交一次许可证,它就会工作。如果重新提交了多次,则返回对上一次更新的引用,以及在此之前的所有更新。

    SELECT p.id as id, c.id as oldid, p.numusers-c.numusers AS dif, p.date, c.date
    FROM `licenses` AS p 
    JOIN `licenses` AS c ON p.serial = c.serial 
                        AND p.date > c.date 
                        AND p.id <> c.id
    WHERE p.id = 156
    #GROUP BY p.id
    

    以下是数据集:

    id  serial  numusers    date
    26  1234    500         2010-07-14
    34  1234    600         2010-07-15
    156 1234    500         2010-07-21
    

    当我运行查询时,我得到以下信息:

    id      oldid       dif         date          date
    156     26          0          2010-07-21    2010-07-14
    156     34          -100       2010-07-21    2010-07-15
    

    如果在查询中取消对group by子句的注释,我将得到oldid为26的行。如何只选择最近日期的行(oldid为34的行)?我可以使用ORDERBY和LIMIT1,但是我也希望能够从整个表中选择不带WHERE子句。

    我使用的是MySQL5.1。

    2 回复  |  直到 14 年前
        1
  •  1
  •   Jay    14 年前

    也许你想要的是:

    select p.id, c.id as priorid, p.numusers-c.numusers AS dif, p.date, c.date as priordate    
    from licenses p
    join licenses c on c.serial=p.serial
      and c.date=(select max(date) from licenses ref where ref.serial=p.serial
        and ref.date<p.date)
    order by p.serial
    

    我一直认为SQL的一个相当令人讨厌的限制是,说“从字段y的最大值记录中获取字段x”需要我用一个嵌入的查询读取表一次,以查找y的最大值,然后再次读取它,以重新查找具有该值的记录并检索我想要的其他值。

    如果同一个序列有三个记录,上面应该在输出上给出两个“差”行。我想这就是你想说的。如果一个给定序列只有一个记录,那么上面的内容将不会给出该序列的输出,这可能是您想要的,也可能不是。

        2
  •  1
  •   Brian Hooper    14 年前

    派生表是否有任何用途;比如…

    SELECT *
        FROM (SELECT p.id as id,
                     c.id as oldid,
                     p.numusers-c.numusers AS dif,
                     p.date,
                     c.date
                  FROM `licenses` AS p JOIN `licenses` AS c ON p.serial = c.serial 
                       AND p.date > c.date 
                       AND p.id <> c.id
                  ORDER BY oldid DESC) AS inner_table
        GROUP BY id;