如何为每个组仅选择表中的最新条目,以便每个“最新”都是一行?

问题描述 投票:0回答:5

我有一个 3 表 SQLServer 数据库:两个事实表和一个链接它们的表。

CREATE TABLE Project (
    ProjectID INT IDENTITY PRIMARY KEY,
    ProjectName VARCHAR(256)
);

CREATE TABLE Thing (
    ThingID INT IDENTITY PRIMARY KEY,
    ThingName VARCHAR(256)
);

CREATE TABLE ProjectThingLink (
    ProjectID INT NOT NULL,
    ThingID INT NOT NULL,
    CreatedDate DATE NOT NULL DEFAULT GETDATE(),
    UNIQUE (ThingID, CreatedDate),
    FOREIGN KEY (ProjectID) REFERENCES Project (ProjectID),
    FOREIGN KEY (ThingID) REFERENCES Thing (ThingID)
);

当将

Thing
分配给
Project
时,会在
ProjectThingLink
表中放入一个条目。
Thing
可以在
Project
之间移动。
CreatedDate
用于了解
Project
最后移动到哪个
Thing
。请注意,
Thing
永远不会在同一日期在项目之间多次移动(因此存在
UNIQUE
约束)。

我正在尝试创建一个当前与

Project
链接的所有
Thing
的列表,但我的大脑无法正常工作。

有简单的方法吗?

使用此示例数据:

INSERT INTO Project
  VALUES
('Project 1'),
('Project 2'),
('Project 3');

INSERT INTO Thing
  VALUES
('Some Thing'),
('This Thing'),
('That Thing'),
('Unassigned');

INSERT INTO ProjectThingLink
  VALUES
(1, 1, '2000-01-01'),
(2, 2, '2000-01-01'),
(2, 3, '2000-02-01'),
(1, 2, '2000-03-01');

结果应该是:

项目 东西
项目1 一些事
项目1 这个东西
项目2 那件事
项目3
sql sql-server greatest-n-per-group
5个回答
3
投票
select p.projectName, t.ThingName
from projects p
join projectThingLink l on l.projectId = p.projectId
join thing t on t.thingId = l.thingId
where l.createdDate =
( select max(l2.createdDate)
  from projectThingLink l2
  where l2.thingId = l.thingId
);

注意:评论后更正


2
投票

这几乎总是比子查询方法提供更好的性能。您基本上是在寻找后面没有任何其他行的行,而不是寻找具有最大日期的行:

SELECT
     P.ProjectID,
     P.ProjectName,
     T.ThingID,
     T.ThingName
FROM
     dbo.Projects P
INNER JOIN dbo.ProjectThingLinks PTL1 ON
     PTL1.ProjectID = P.ProjectID
LEFT OUTER JOIN dbo.ProjectThingLinks PTL2 ON
     PTL2.ProjectID = ThingID = PTL1.ThingID AND
     PTL2.CreatedDate > PTL1.CreatedDate
INNER JOIN dbo.Things T ON
     T.ThingID = PTL1.ThingID
WHERE
     PTL2.ThingID IS NULL

一旦您决定处理具有相同 CreatedDate 值的两行的业务规则,您可能需要调整查询。

此外,作为旁注,名为“事物”的表通常是数据库设计存在问题的好兆头。表格应该代表不同的现实生活实体。这种普遍性通常会在未来带来问题。如果这些是资源,那么它们可能会共享某些属性,而不仅仅是名称。也许您的情况是一个非常特殊的情况,但很可能不是。 ;)


1
投票

试试这个:

select p.ProjectID, p.Name, t.ThingID, t.ThingName, l.CreatedDate 
from Project p
inner join (
    select ProjectID, max(CreatedDate) as CreatedDate
    from ProjectThingLink
    group by ProjectID
) lm on p.ProjectID = l.ProjectID
inner join ProjectThingLink l on lm.ProjectID = l.ProjectID and lm.CreatedDate = l.CreatedDate
inner joing Thing t on l.ThingID = t.ThingID

0
投票

你可以简单地做

SELECT Project.projectId, Project.ProjectName, ThingName
FROM Project  INNER JOIN ProjectThingLink
 ON Project.ProjectID = ProjectThingLink.ProjectID INNER JOIN
                     Thing ON ProjectThingLink.ThingID = Thing.ThingID

将获得每个项目的列表,以及与其链接的所有内容,如下所示:

1 |项目1 |一些东西

1 |项目1 |这东西

2 |项目2 |那东西


0
投票
select * from project
inner join (select projectid,
                   max(createdate) as maxdate 
            from projectThingLink 
            group by projectid) as a
on projectid = a.projectid  and createDate = a.maxDate
© www.soinside.com 2019 - 2024. All rights reserved.