Sql server 如何在SQL Server中通过Join获取基于时间戳的最新记录

Sql server 如何在SQL Server中通过Join获取基于时间戳的最新记录,sql-server,Sql Server,我正在使用SQL Server 2012。我有一个包含多列的表(LocationResults)。我想获取另一个表(TargetAssociationDetails)中也存在的所有列,但仅获取插入的最新行以及第二个表中也存在的行 我的TargetAssociationDetails表: MSISDN IMEI IMSI -------------------------- 14085551107 NULL NULL 14085551108 NULL NUL

我正在使用SQL Server 2012。我有一个包含多列的表(LocationResults)。我想获取另一个表(TargetAssociationDetails)中也存在的所有列,但仅获取插入的最新行以及第二个表中也存在的行

我的TargetAssociationDetails表:

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()
函数检索