如何基于联接表的唯一值从表中选择最大值?

时间:2018-11-07 15:02:59

标签: sql-server

我有三个桌子。所有这些都遵循CRUD模式进行插入和更新。我需要进行查询,根据另一个表的唯一值选择一个表中的所有最新更新,并通过连接两次将其删除:(在示例中,我省略了两个表的CRUD结构)

表COPY_HISTORY

COPY_ID | DATA_ID | STATUS | TIME  |        
1       |  A      | open   | 10:34 |
1       |  A      | locked | 10:37 |
2       |  A      | open   | 10:38 |
3       |  B      | open   | 11:29 |
4       |  C      | open   | 10:37 |
5       |  D      | locked | 09:34 |       

表DATA_SET

DATA_ID | LOCATION |    
A       | 88       | 
B       | 77       | 
C       | 88       | 
D       | 99       | 
E       | 88       | 
F       | 88       |   

表COPY_RULES

LOCATION_FROM | LOCATION_TO 
55            | 110 
66            | 120
77            | 120
88            | 130
99            | 130

我需要做的是从复制规则表中获取每个LOCATION_TO的状态。如果执行了副本,它将被记录在副本历史记录中,并且副本将始终覆盖位置(110,120,130)上的所有数据。

在这种情况下,位置110从未发生过复制,并且110根本不应包含在返回的数据中。即使它存在于规则中,也不相关。 120将从66和77的数据集中接收副本。但是,我们在66上还没有数据集,因此只有77是相关的。 B位于77,数据集B在11:29插入了复制历史记录,状态为打开。由于这是属于120的唯一状态,因此状态对120处于打开状态,并且位置120可能会被覆盖。

位置130,但是同时接收88和99的副本。这意味着数据集A,C,D,E和F都将复制到130中,因为它们都位于88或99中。我们有两个复制历史记录记录A的日志,记录C和D的日志。这意味着我只希望最新注册的状态,在这种情况下为10:38。

现在,我已尝试根据LOCATION_TO从COPY_HISTORY中选择最大值,但我陷入僵局,无法使LOCATION_TO唯一

我尝试:

SELECT cr.LOCATION_TO, ch.STATUS, ch.TIME FROM COPY_HISTORY ch
JOIN DATA_SET ds ON ch.DATA_ID = ds.DATA_ID
JOIN COPY_RULES cr ON cr.LOCATION_FROM = ds.LOCATION 
WHERE ch.TIME = (SELECT MAX(TIME) FROM COPY_HISTORY
                WHERE COPY_ID = ch.COPY_ID
                AND ch.DATA_ID = ds.DATA_ID
                AND ds.LOCATION = cr.LOCATION_FROM)

该选择的最大时间陈述不完整。两条AND线什么都不做。我唯一能做的就是摆脱COPY_HISTORY中的第一行,这意味着我可以获得每个COPY_ID的所有最大时间,但是我不知道如何过滤它们以仅获取每个LOCATION_TO的最大值。 >

这样做,我设法从一个LOCATION_TO中获得了最大值:

SELECT cr.LOCATION_TO, ch.STATUS, ch.TIME FROM COPY_HISTORY ch
JOIN DATA_SET ds ON ch.DATA_ID = ds.DATA_ID
JOIN COPY_RULES cr ON cr.LOCATION_FROM = ds.LOCATION 
WHERE ch.TIME = (SELECT MAX(TIME) FROM COPY_HISTORY ch2, DATA_SET ds2, COPY_RULES cs2 
                WHERE ch2.DATA_ID = ds2.DATA_ID
                AND ds2.LOCATION = cr2.LOCATION_FROM 
                AND cr2.LOCATION_TO = 2180)

但是,这不能解决我获取所有LOCATION_TO的状态列表的问题。

期望的输出:

LOCATION_TO | STATUS  | TIME  |
120         | open    | 11:29 |
130         | open    | 10:38 |

COPY_HISTORY中的有效行将是第3行和第4行

这是试图极大简化实际数据库结构的尝试,因此存在输入错误的风险。

DDL

create table #COPY_HISTORY (COPY_ID int, DATA_ID char(1), [STATUS] varchar(16), [TIME] time)
create table #DATA_SET (DATA_ID char(1), [LOCATION] int)
create table #COPY_RULES (LOCATION_FROM int, LOCATION_TO int)

insert into #COPY_HISTORY
values
(1,'A','open','10:34'),
(1,'A','locked','10:37'),
(2,'A','open','10:38'),
(3,'B','open','11:29'),
(4,'C','open','10:37'),
(5,'D','locked','09:34')

insert into #DATA_SET     
values
('A',88),
('B',77), 
('C',88), 
('D',99), 
('E',88), 
('F',88)


insert into #COPY_RULES
values
(55,110), 
(66,120),
(77,120),
(88,130),
(99,130)

2 个答案:

答案 0 :(得分:4)

我认为该查询将为您服务。正如Ryan在评论中提到的那样,您可以使用ROW_NUMBER分析函数按时间(ORDER BY)对位置记录(PARTITION BY)进行排名,然后仅返回每个位置的第一行(RowOrder = 1)。

SELECT * FROM (
SELECT cr.LOCATION_TO, ch.STATUS, ch.TIME, ROW_NUMBER() OVER (PARTITION BY cr.LOCATION_TO ORDER BY ch.TIME desc) AS RowOrder
FROM #COPY_HISTORY ch
JOIN #DATA_SET ds ON ch.DATA_ID = ds.DATA_ID
JOIN #COPY_RULES cr ON cr.LOCATION_FROM = ds.LOCATION 
) ordered_set
WHERE RowOrder = 1

答案 1 :(得分:2)

如果我正确理解了逻辑:

nssm install MDHIS_WebClient "%MDHIS2_HOME%/MDHIS_WebClient.cmd" AppDirectory %MDHIS2_HOME% DisplayName MDHIS_WebClient Start SERVICE_AUTO_START DependOnService MSSQLSERVER AppNoConsole 1 AppStopMethodConsole 30000