Sql server 如何在SQL Server中通过Join获取基于时间戳的最新记录
我正在使用SQL Server 2012。我有一个包含多列的表(LocationResults)。我想获取另一个表(TargetAssociationDetails)中也存在的所有列,但仅获取插入的最新行以及第二个表中也存在的行 我的TargetAssociationDetails表:Sql server 如何在SQL Server中通过Join获取基于时间戳的最新记录,sql-server,Sql Server,我正在使用SQL Server 2012。我有一个包含多列的表(LocationResults)。我想获取另一个表(TargetAssociationDetails)中也存在的所有列,但仅获取插入的最新行以及第二个表中也存在的行 我的TargetAssociationDetails表: MSISDN IMEI IMSI -------------------------- 14085551107 NULL NULL 14085551108 NULL NUL
MSISDN IMEI IMSI
--------------------------
14085551107 NULL NULL
14085551108 NULL NULL
14085551113 NULL NULL
我的位置结果表:
Latitude Longitude MSISDN IMSI IMEI RecordedTimeStamp
---------------------------------------------------------------------------
57.785125 -123.40476 14085551107 NULL NULL 05:54.8
57.78374111 -123.4027269 14085551107 NULL NULL 19:12.6
57.78476194 -123.4045131 14085551107 NULL NULL 09:08.3
57.61768861 -123.4081439 14085551108 NULL NULL 19:08.4
57.801585 -123.45619 14085551114 NULL NULL 19:08.5
57.55303194 -123.3019161 14085551113 NULL NULL 19:08.5
这是我的疑问-
SELECT MAX(lr.RecordTimestamp) AS RecordedTimeStamp, lr.IMEI, lr.IMSI, lr.MSISDN
FROM LocationResults lr LEFT OUTER JOIN TargetAssosiationDetails tad ON
tad.IMEI = lr.IMEI AND tad.IMSI = lr.IMSI AND tad.MSISDN = lr.MSISDN
GROUP BY lr.IMEI, lr.IMSI,lr.MSISDN
但在这种情况下,我无法获得所有列。我只能得到我分组所依据的列
我想要的结果是-
Latitude Longitude MSISDN IMSI IMEI RecordedTimeStamp
---------------------------------------------------------------------------
57.78374111 -123.4027269 14085551107 NULL NULL 19:12.6
57.61768861 -123.4081439 14085551108 NULL NULL 19:08.4
57.55303194 -123.3019161 14085551113 NULL NULL 19:08.5
我是DB查询的新手,所以如果您能发布一个脚本并解释它的功能,那就太好了
提前谢谢。试试这个
;with cte as (
select Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp
, row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) as RN
from LocationResults
)
select *
from cte
where RN = 1
试试这个
;with cte as (
select Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp
, row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) as RN
from LocationResults
)
select *
from cte
where RN = 1
只要您使用的是MS SQL Server 2008或更高版本,就可以使用窗口功能来实现这些结果。ROW_NUMBER()函数允许您根据特定顺序(在本例中为时间戳递减)对每一行进行编号,并根据值(在本例中为MSISDN)重新启动排序:因此,对于MSISDN的每个不同值,按从最高时间戳到最低时间戳的顺序对行进行编号。然后从LocationResults表中对该查询进行内部联接,该表中的行号为1,因为这意味着它是最新的行 因为每一行似乎由三个字段而不是一个字段标识,所以您需要将行划分为这三个字段,并在联接中使用它们。这只需在PARTITION by子句中列出它们并用逗号分隔即可
SELECT *
FROM LocationResults AS lr
INNER JOIN (
SELECT *,
-- number the rows based on the time stamp descending and restart the ordering for each MSISDN value
ROW_NUMBER() OVER (PARTITION BY MSISDN, IMEI, IMSI ORDER BY RecordedTimeStamp DESC) AS rnum
FROM TargetAssociationDetails
) AS d ON d.MSISDN=lr.MSISDN
AND d.IMEI=lr.IMEI
AND d.IMSI=lr.IMSI
-- join on row number 1 because that will be the newest row
AND d.rnum=1
只要您使用的是MS SQL Server 2008或更高版本,就可以使用窗口功能来实现这些结果。ROW_NUMBER()函数允许您根据特定顺序(在本例中为时间戳递减)对每一行进行编号,并根据值(在本例中为MSISDN)重新启动排序:因此,对于MSISDN的每个不同值,按从最高时间戳到最低时间戳的顺序对行进行编号。然后从LocationResults表中对该查询进行内部联接,该表中的行号为1,因为这意味着它是最新的行 因为每一行似乎由三个字段而不是一个字段标识,所以您需要将行划分为这三个字段,并在联接中使用它们。这只需在PARTITION by子句中列出它们并用逗号分隔即可
SELECT *
FROM LocationResults AS lr
INNER JOIN (
SELECT *,
-- number the rows based on the time stamp descending and restart the ordering for each MSISDN value
ROW_NUMBER() OVER (PARTITION BY MSISDN, IMEI, IMSI ORDER BY RecordedTimeStamp DESC) AS rnum
FROM TargetAssociationDetails
) AS d ON d.MSISDN=lr.MSISDN
AND d.IMEI=lr.IMEI
AND d.IMSI=lr.IMSI
-- join on row number 1 because that will be the newest row
AND d.rnum=1
有很多方法可以做到这一点。下面是一种不需要CTE或派生表的方法
select top 1 with ties Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp
from
LocationResults
order by row_number() over (partition by MSISDN, order by RecordedTimeStamp desc)
有很多方法可以做到这一点。下面是一种不需要CTE或派生表的方法
select top 1 with ties Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp
from
LocationResults
order by row_number() over (partition by MSISDN, order by RecordedTimeStamp desc)
正如Mike D.提到的,有很多方法可以做到这一点。以下是我的方法:
DECLARE
@TargetAssociationDetails TABLE (
MSISDN BIGINT,
IMEI VARCHAR(100),
IMSI VARCHAR(100)
)
DECLARE
@LocationResults TABLE (
Latitude FLOAT,
Longitude FLOAT,
MSISDN BIGINT,
IMSI VARCHAR(100),
IMEI VARCHAR(100),
RecordedTimeStamp DATETIME
)
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.785125, -123.40476, 14085551107, NULL, NULL, '05:54.8')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.78374111, -123.4027269, 14085551107, NULL, NULL, '19:12.6')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.78476194, -123.4045131, 14085551107, NULL, NULL, '09:08.3')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.61768861, -123.4081439, 14085551108, NULL, NULL, '19:08.4')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.801585, -123.45619, 14085551114, NULL, NULL, '19:08.5')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.55303194, -123.3019161, 14085551113, NULL, NULL, '19:08.5')
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551107, NULL, NULL)
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551108, NULL, NULL)
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551113, NULL, NULL)
SELECT
LR.Latitude,
LR.Longitude,
TAD.MSISDN,
TAD.IMSI,
TAD.IMEI,
LR.RecordedTimeStamp
FROM @TargetAssociationDetails TAD
INNER JOIN (
SELECT
MAX(LR.RecordedTimeStamp) AS RecordedTimeStamp,
LR.MSISDN
FROM @LocationResults LR
GROUP BY
LR.MSISDN
) _LR ON _LR.MSISDN = TAD.MSISDN
INNER JOIN @LocationResults LR ON [_LR].MSISDN = LR.MSISDN AND [_LR].RecordedTimeStamp = LR.RecordedTimeStamp
但公平地说,我会用迈克的方式。这是一个很好的例子。正如Mike D.提到的,有很多方法可以做到这一点。以下是我的方法:
DECLARE
@TargetAssociationDetails TABLE (
MSISDN BIGINT,
IMEI VARCHAR(100),
IMSI VARCHAR(100)
)
DECLARE
@LocationResults TABLE (
Latitude FLOAT,
Longitude FLOAT,
MSISDN BIGINT,
IMSI VARCHAR(100),
IMEI VARCHAR(100),
RecordedTimeStamp DATETIME
)
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.785125, -123.40476, 14085551107, NULL, NULL, '05:54.8')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.78374111, -123.4027269, 14085551107, NULL, NULL, '19:12.6')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.78476194, -123.4045131, 14085551107, NULL, NULL, '09:08.3')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.61768861, -123.4081439, 14085551108, NULL, NULL, '19:08.4')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.801585, -123.45619, 14085551114, NULL, NULL, '19:08.5')
INSERT INTO @LocationResults (Latitude, Longitude, MSISDN, IMSI, IMEI, RecordedTimeStamp)
VALUES (57.55303194, -123.3019161, 14085551113, NULL, NULL, '19:08.5')
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551107, NULL, NULL)
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551108, NULL, NULL)
INSERT INTO @TargetAssociationDetails (MSISDN, IMEI, IMSI)
VALUES (14085551113, NULL, NULL)
SELECT
LR.Latitude,
LR.Longitude,
TAD.MSISDN,
TAD.IMSI,
TAD.IMEI,
LR.RecordedTimeStamp
FROM @TargetAssociationDetails TAD
INNER JOIN (
SELECT
MAX(LR.RecordedTimeStamp) AS RecordedTimeStamp,
LR.MSISDN
FROM @LocationResults LR
GROUP BY
LR.MSISDN
) _LR ON _LR.MSISDN = TAD.MSISDN
INNER JOIN @LocationResults LR ON [_LR].MSISDN = LR.MSISDN AND [_LR].RecordedTimeStamp = LR.RecordedTimeStamp
但公平地说,我会用迈克的方式。这是一个很好的例子。如果可用,请使用这里的
ROW\u NUMBER()OVER()
来定位所需的行
然后可以加入到相关表中。下面是一个使用“派生表”的示例:
其他人提出了一种“公共表表达式”(CTE——这些要求使用
和…AS
),但使用这种方法没有好处。我个人认为,对于SQL的相对新手来说,在不分青红皂白地使用CTE之前理解并熟悉派生表是很重要的。如果可用或使用,就像这里一样,ROW\u NUMBER()OVER()
只定位所需的行
然后可以加入到相关表中。下面是一个使用“派生表”的示例:
其他人提出了一种“公共表表达式”(CTE——这些要求使用
和…AS
),但使用这种方法没有好处。我个人认为,对于SQL的新手来说,在不加区别地使用CTE之前,理解并熟悉派生表是很重要的。您想要关于哪些其他列的最新时间戳?标记SQL Server的版本总是很好的您想要关于哪些其他列的最新时间戳?是的总是挂起标签来标记sql Server的版本我仍然无法应用此查询来包括它与另一个表的关系。我已经更新了问题。我仍然无法应用此查询来包括它与另一个表的关系。我已更新问题。我已更新问题以显示与另一个表存在的关系,并且我还需要在3个字段(MSISDN、IMEI和IMSI)上应用条件。然后使用其他字段更新连接条件。我的代码只是使用ROW\u NUMBER()
函数从表中检索最新记录的一个示例。如果您不知道该怎么做,您可能会问另一个问题,但我建议您先阅读一下SQL中的表联接是如何工作的,因为您的新问题可能会以重复的形式结束。@yazz经过一番思考后,我意识到如果您的行被标识为唯一的,您还需要更新PARTITION BY子句和联接条件多个字段。我更新了我的答案以反映这一点。尽管示例数据在这些列中只显示NULL,这意味着您的联接将无法工作(因为NULL!=NULL)。因此,如果是这种情况,您需要在连接条件中处理这些空值,或者重新考虑行的连接方式。这非常有效,只是我必须反转TargetAssociationDetails(它没有RecordedTimestamp)和LocationResults。我在联接条件中处理了空值。我已更新了问题以显示与另一个表存在的关系,并且我还需要在3个字段(MSISDN、IMEI和IMSI)上应用该条件。然后使用其他字段更新联接条件。我的代码只是使用ROW\u NUMBER()
函数检索