0

好的,所以我一直在处理这个查询,我很确定必须有一种更好的方法来做这件事,而不是我当前的方法,即在彼此之间嵌套语句。

这是我的 2 个主表(快速重写,因此它们可能不是完美的“创建表”代码)

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. 我们还需要确保 flags 等于 0

这是我正在运行的查询:

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;

如您所见,我正在做的是将人员表与对人员状态进行排序的表连接起来,然后按组和 statusesid 进行过滤。然后我使用两个连接的表,按名称过滤,然后我尝试获取最近的人员行并确保它具有正确的标志。

我想,因为这似乎是一个有趣的难题,所以我想请你们看看是否有人能想出一个像样的解决方案。我不是这些事情的最专家,所以我只知道更多基本的 SQl 命令,所以任何建议都会是有益的。谢谢 =)

4

1 回答 1

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;

如果您要使用记录的“生效日期”(the 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;

在这个版本中,子查询是相互关联的,并将变成索引查找。

于 2013-08-09T00:20:11.137 回答