我正在使用SQL Server 2012.我有一个包含多列的表(LocationResults)。我想获得另一个表中存在的所有列(TargetAssociationDetails) - 但只有那些插入最新的行并且也出现在第二个表中。
我的TargetAssociationDetails表:
MSISDN IMEI IMSI
--------------------------
14085551107 NULL NULL
14085551108 NULL NULL
14085551113 NULL NULL
我的LocationResults表:
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
我对数据库查询非常陌生,所以如果您可以发布一个脚本并解释它的作用,那将会很棒。
提前致谢。
答案 0 :(得分:2)
只要您使用的是MS SQL Server 2008或更高版本,就可以使用窗口函数ROW_NUMBER()
来实现这些结果。 ROW_NUMBER()函数允许您根据特定顺序(在这种情况下,时间戳降序)对每一行进行编号,并根据值(在本例中为MSISDN)重新启动该排序:因此,对于MSISDN编号的每个不同值,行从最高时间戳到最低时间顺序。然后从LocationResults表 ONLY 对该查询进行内部联接,其中行号为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
答案 1 :(得分: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
答案 2 :(得分:0)
有很多方法可以做到.Below是一种不需要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)
答案 3 :(得分:0)
正如 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
但我公平地说,我已经习惯了迈克的方式。它是一个较小而且很好的例子。
答案 4 :(得分:0)
当可用的dor使用时,ROW_NUMBER() OVER()
只能找到您需要的行。
然后你可以加入相关的表格。以下是使用"派生表":
的示例SELECT *
FROM (
SELECT *,
row_number() over (partition by MSISDN, order by RecordedTimeStamp desc) as rowno
FROM LocationResults
) as lr
LEFT OUTER JOIN TargetAssosiationDetails tad ON tad.IMEI = lr.IMEI AND tad.IMSI = lr.IMSI AND tad.MSISDN = lr.MSISD
WHERE lr.rowno = 1
其他人提出了一个"公用表表达式" (CTE - 这些要求使用WITH ... AS
)但使用该方法没有任何优势。我个人认为,在不加区别地使用CTE之前,SQL的相关新手理解并熟悉派生表非常重要。