Mysql 分组依据和自定义订单

Mysql 分组依据和自定义订单,mysql,group-by,sql-order-by,mysql-5.7,mysql-5.1,Mysql,Group By,Sql Order By,Mysql 5.7,Mysql 5.1,我已经通读了上的答案,但将其应用到我的查询中,结果是在一个相当简单的情况下,子查询中有一个子查询,因此我想知道这是否可以简化: 带有示例数据的模式 为简洁起见,我省略了members表中的其他字段。此外,在实际应用程序中还有更多的表被连接,但是这些表很容易连接。给我带来问题的是成员资格\u堆栈表 CREATE TABLE members ( id int unsigned auto_increment, first_name varchar(255) not null, PRIMAR

我已经通读了上的答案,但将其应用到我的查询中,结果是在一个相当简单的情况下,子查询中有一个子查询,因此我想知道这是否可以简化:

带有示例数据的模式 为简洁起见,我省略了
members
表中的其他字段。此外,在实际应用程序中还有更多的表被连接,但是这些表很容易连接。给我带来问题的是
成员资格\u堆栈

CREATE TABLE members (
  id int unsigned auto_increment,
  first_name varchar(255) not null,
  PRIMARY KEY(id)
);

INSERT INTO members (id, first_name)
     VALUES (1, 'Tyler'),
            (2, 'Marissa'),
            (3, 'Alex'),
            (4, 'Parker');

CREATE TABLE membership_stack (
  id int unsigned auto_increment,
  member_id int unsigned not null,
  sequence int unsigned not null,
  team varchar(255) not null,
  `status` varchar(255) not null,
  PRIMARY KEY(id),
  FOREIGN KEY(member_id) REFERENCES members(id)
);

-- Algorithm to determine correct team:
-- 1. Only consider rows with the highest sequence number
-- 2. Order statuses and pick the first one found:
--    (active, completed, cancelled, abandoned)

INSERT INTO membership_stack (member_id, sequence, team, status)
     VALUES (1, 1, 'instinct', 'active'),
            (1, 1, 'valor', 'abandoned'),
            (2, 1, 'valor', 'active'),
            (2, 2, 'mystic', 'abandoned'),
            (2, 2, 'valor', 'completed'),
            (3, 1, 'instinct', 'completed'),
            (3, 2, 'valor', 'active');
我无法更改数据库架构,因为数据与外部数据源同步

查询 这就是我到目前为止所做的:

    SELECT m.id, m.first_name, ms.sequence, ms.team, ms.status
      FROM membership_stack AS ms
      JOIN (
    SELECT member_id, MAX(sequence) AS sequence
      FROM membership_stack
  GROUP BY member_id
           ) AS t1
        ON ms.member_id = t1.member_id
       AND ms.sequence = t1.sequence
RIGHT JOIN members AS m
        ON ms.member_id = m.id
  ORDER BY m.id, FIELD(ms.status, 'active', 'completed', 'cancelled', 'abandoned');
这与预期的一样有效,但如果成员的“最新序列”涉及多个团队,则成员可能会出现多次。我需要做的是在
id
上再次聚合,然后选择每组中的第一行

然而,这带来了一些问题:

  • 整个结果集将成为一个子表(子查询),这在这里不是什么大问题,但在应用程序中查询相当大
  • 它需要与兼容,因为默认情况下它在MySQL 5.7上启用。我没有检查,但我怀疑
    字段(ms.status,'active','completed','cancelled','dependend')
    是否被视为此结果集的功能相关字段。查询还需要与MySQL 5.1兼容,因为这就是我们目前正在运行的
  • 目标 我能做些什么


    编辑:我注意到有些成员不属于任何团队。这些成员应包含在结果集中,这些字段的值为空。问题已更新以反映新信息。

    我会使用变量进行此操作

    您正在寻找一个
    membership\u stack
    行,该行对于您的特殊订购是最大的。我只关注这一点。
    join
    返回到
    members
    是微不足道的

    select ms.*
    from (select ms.*,
                 (@rn := if(@m = member_id, @rn + 1,
                            if(@m := member_id, 1, 1)
                           )
                 ) as rn
          from membership_stack ms cross join
               (select @m := -1, @rn := 0) params
          order by member_id, sequence desc,
                   field(ms.status, 'active', 'completed', 'cancelled', 'abandoned')
         ) ms
    where rn = 1;
    
    变量是逻辑的实现方式。排序是获得正确结果的关键

    编辑:

    MySQL对子查询中的
    限制非常挑剔。这可能会起作用:

    select ms.*
    from membership_stack ms
    where (sequence, status) = (select ms2.sequence, ms2.status
                                from membership_stack ms2
                                where ms2.member_id = ms.member_id
                                order by ms2.member_id, ms2.sequence desc,
                                         field(ms2.status, 'active', 'completed', 'cancelled', 'abandoned')
                                limit 1
                               );
    

    您可以在WHERE子句中使用限制为1的相关子查询:

    SELECT m.id, m.first_name, ms.sequence, ms.team, ms.status
    FROM members AS m
    JOIN membership_stack AS ms ON ms.member_id = m.id
    WHERE ms.id = (
        SELECT ms1.id
        FROM membership_stack AS ms1
        WHERE ms1.member_id = ms.member_id
        ORDER BY ms1.sequence desc, 
                 FIELD(ms1.status, 'active', 'completed', 'cancelled', 'abandoned'),
                 ms1.id asc
        LIMIT 1
    )
    ORDER BY m.id;
    
    演示:

    更新

    要包括
    成员资格\u stack
    表中没有条目的成员,应使用左连接,并将子查询条件从WHERE子句移动到ON子句:

    SELECT m.id, m.first_name, ms.sequence, ms.team, ms.status
    FROM members AS m
    LEFT JOIN membership_stack AS ms 
        ON  ms.member_id = m.id
        AND ms.id = (
            SELECT ms1.id
            FROM membership_stack AS ms1
            WHERE ms1.member_id = ms.member_id
            ORDER BY ms1.sequence desc, 
                     FIELD(ms1.status, 'active', 'completed', 'cancelled', 'abandoned'),
                     ms1.id asc
            LIMIT 1
        )
    ORDER BY m.id;
    

    演示:

    是的,我明白了。再次尝试理解您的问题。我已编辑我的问题,以包括成员可能在成员资格堆栈中没有任何条目的情况。有没有办法使这个查询适应这些情况?或者将
    WHERE
    条件放入带有
    左连接的
    ON
    子句中是否有任何问题?@rink.attendant.6使用左连接。检查更新。如果序列和状态相同怎么办?例子Tyler@valor状态为“活动”吗?@PaulSpiegel我也对此提出了质疑,但数据提供商还没有回复这是否可能。同一序列中不应同时有多个
    活动的
    ,但我认为如果它们在同一序列中连续进行,则可能有多个
    完成的
    。但是,您应该定义一个“不同”的顺序。在我的解决方案中,我使用
    membership\u stack.id ASC
    作为ORDER BY子句中的最后一列(以防万一)。子查询中的WHERE with LIMIT在“WHERE子句”中生成一个错误
    未知列“field”
    。变量1似乎工作正常,请您进一步解释,以便我能理解并向其他人提出解决方案好吗?@rink.attendant.6。您似乎熟悉窗口功能。这相当于MySQL中的
    row_number()(按成员id按字段(…)进行分区)
    。变量逐行跟踪状态。(第二个查询中的错误是列名键入错误。)实际上我从未听说过窗口函数。我只看到
    row_number()
    来自试图解决这个问题的人,他曾使用过另一种RDBMS。无论如何,我将与我的团队讨论这个问题,并希望在下周的某个时候接受解决方案。
    SELECT m.id, m.first_name, ms.sequence, ms.team, ms.status
    FROM members AS m
    LEFT JOIN membership_stack AS ms 
        ON  ms.member_id = m.id
        AND ms.id = (
            SELECT ms1.id
            FROM membership_stack AS ms1
            WHERE ms1.member_id = ms.member_id
            ORDER BY ms1.sequence desc, 
                     FIELD(ms1.status, 'active', 'completed', 'cancelled', 'abandoned'),
                     ms1.id asc
            LIMIT 1
        )
    ORDER BY m.id;