MySQL - 如果另一个连接的行具有某个特征,则返回特定行

时间:2013-08-08 23:38:37

标签: mysql join

好的,所以我一直在研究这个查询,我很确定必须有一个更好的方法,而不是我当前的方法,它是在语句之​​后嵌套语句。

这是我的两个主要表格(快速重写,因此它们可能不是完美的'创建表'代码)

CREATE TABLE `person` (
    `personid` INT PRIMARY KEY AUTO_INCREMENT,
    `personuuid` VARCHAR(64),
    `flags` INT,
    `last_updated` DATETIME,
    `first_name` VARCHAR(64),
    `last_name` VARCHAR(64)
);

CREATE TABLE `person_status` (
    `person_statusid` INT PRIMARY KEY AUTO_INCREMENT,
    `person_statusesid` INT,
    `personuuid` VARCHAR(64),
    `groupsuuid` VARCHAR(64),
    `start_date` DATE
);

简要说明:正如您所看到的,个人可能(可能)具有多种状态。最新状态由开始日期(具有最大开始日期)确定。每个人还可能在人员表中有多个条目。 (帮助跟踪更新用户信息)最新信息将是具有最新last_updated值的信息。

我正在尝试做什么:我正在尝试获取所有人(也称为personuuid)的列表,以便:

  1. 返回给我们的条目具有最新的人员身份
  2. 状态仅显示某些groupsuuid(也称为按群组过滤)
  3. 我们还需要额外的过滤,以便过滤名称
  4. 我们还需要确保标志等于0
  5. 这是我正在运行的查询:

    SELECT personuuid FROM (
        SELECT personuuid, flags FROM (
            SELECT DISTINCT personuuid, flags
                FROM person 
                JOIN (
                    SELECT personuuid, t2.person_statusesid FROM (
                            SELECT personuuid, groupsuuid, t1.person_statusesid FROM (
                                SELECT personuuid, groupsuuid, p1.person_statusesid 
                                    FROM person_status as p1
                                    ORDER BY start_date DESC, person_statusid DESC
                            ) as t1
                            GROUP BY personuuid, groupsuuid
                        ) as t2
                        WHERE groupsuuid='xxxxxxxxxx' AND person_statusesid = X
                ) AS t3 USING (personuuid)
                WHERE  (first_name LIKE '%TEST%' OR last_name LIKE '%TEST%')
                ORDER BY person_statusesid, last_name, first_name, last_updated DESC
            ) as t4
            GROUP BY personuuid
        ) as t5
    WHERE flags <> 2;
    

    正如您所看到的,我正在使用一个表来命名人状态,然后按group和statusesid进行过滤。然后我拿两个连接的表,按名称过滤,然后我试图抓住最近的人行并确保它有正确的标志。

    我认为,因为这看起来像一个有趣的谜题,我想请你们看看有人能想出一个像样的解决方案。我不是这些东西中最专家的所以我只知道更多基本的SQl命令,所以任何建议都是有益的。谢谢=)

1 个答案:

答案 0 :(得分:0)

我会通过在一个地方汇集我需要的数据来解决这个问题。也就是说,最近的状态记录和最近的人员记录。这需要查找两个表的最新更新日期,然后将各种表和子查询连接在一起:

select ps.*, p.*
from person_status ps join
     (select personuuid, max(last_updated) as maxlu
      from person_status ps
      group by person_status
     ) psm
     on psm.personuuid = psm.personuuid and psm.maxlu = ps.last_updated join
     (select personuuid, max(last_updated) as maxlu
      from person p
      group by personuuid
     ) pm
     on pm.personuuid = ps.personuuid join
     person p
     on pm.personuuid = p.personuuid and pm.maxlu = p.lastupdated
where p.flags = 0 and
      ps.groupsuuid in (<list of groups>) and
      additional filtering;

如果您要为记录设置一个带有“生效日期”(lastupdated)的数据结构,您应该考虑使用“结束日期”。这在更新中需要更多工作(通常需要一个触发器),但它会使这样的查询变得更加容易。

编辑:

您的原始查询中包含相当数量的子查询。在任何情况下,您都可以在没有子查询的情况下重写它以简化问题。对于以下内容,性能需要personuuid, lastupdated(对于两个表)的索引。

select ps.*, p.*
from person_status ps join
     person p
     on ps.personuuid = p.personuuid and
        p.lastupdated = (select p2.lastupdated
                         from person p2
                         where p2.personuuid = p.personuuid
                         order by p2.lastupdated desc
                         limit 1
                        ) and
        ps.lastupdated = (select ps2.lastupdated
                          from person_status ps2
                          where ps2.personuuid = ps.personuuid
                          order by ps2.lastupdated desc
                          limit 1
                         )
where p.flags = 0 and
      ps.groupsuuid in (<list of groups>) and
      additional filtering;

在此版本中,子查询是相关的,并将转换为索引查找。