相关子查询以选择最早条目的ID

时间:2016-03-15 17:49:33

标签: sql-server tsql sql-server-2014

我目前正在使用这个:

IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp

CREATE TABLE #Temp
(
    SomeId INT,
    UtcDateTime DATETIME2
)

INSERT INTO #Temp
    SELECT 1, DATETIME2FROMPARTS(2015,1,1,1,1,1,0,0)
        UNION 
    SELECT 1, DATETIME2FROMPARTS(2015,1,1,2,1,1,0,0)
        UNION 
    SELECT 2, DATETIME2FROMPARTS(2015,1,1,3,1,1,0,0)
        UNION 
    SELECT 2, DATETIME2FROMPARTS(2015,1,12,4,1,1,0,0)
        UNION 
    SELECT 2, DATETIME2FROMPARTS(2015,1,12,5,1,1,0,0)
        UNION 
    SELECT 3, DATETIME2FROMPARTS(2015,1,12,5,1,1,0,0)

SELECT * FROM #Temp ORDER BY UtcDateTime ASC

SELECT 
    *
FROM #Temp AS O1
WHERE UtcDateTime =
(
    SELECT MIN(UtcDateTime) FROM #Temp AS O2 WHERE O1.SomeId = O2.SomeId 
)
AND SomeId =
(
    SELECT MAX(SomeId) FROM #Temp AS O2 WHERE O1.SomeId = O2.SomeId AND O1.UtcDateTime = O2.UtcDateTime
)

目的是根据UtcDateTime选择具有不同SomeId的每个条目的第一个匹配项。换句话说,我在这些行之后:

SomeId  UtcDateTime
1   2015-01-01 01:01:01.0000000
2   2015-01-01 03:01:01.0000000
3   2015-01-12 05:01:01.0000000

以上相关的子查询方法是否正确?

4 个答案:

答案 0 :(得分:3)

两个自连接(提到三次相同的表) - 在我看来太多了

1)

SELECT *
FROM #Temp AS O1
WHERE not exists
    ( select 1 from #Temp O2 
      where O2.SomeId = O1.SomeId and O2.UtcDateTime < O1.UtcDateTime)

2)

SELECT *
FROM #Temp AS O1
CROSS APPLY
(
  SELECT TOP 1 O2.UtcDateTime
  FROM #Temp as O2
  WHERE O2.SomeId = O1.SomeId
  ORDER BY O2.UtcDateTime ASC
) O2
WHERE O1.UtcDateTime = O2.UtcDateTime

2.1)使用group by,min和join的子查询(apply很可能导致循环连接计划,而group by first和join after - to hash join)

3)为你的样本案例

SELECT O1.id, MIN(O1.UtcDateTime)
FROM #Temp AS O1
GROUP BY O1.id

4)小桌子;注意,row_number没有搜索,所以你是&#34;禁用&#34;所有索引并请求额外的内存来填充新列

SELECT *
FROM
(
  SELECT O1.*,
    ROW_NUMBER() OVER(PARTITION BY O1.SomeID ORDER BY O1.UtcDateTime) as row_no
  FROM #Temp as O1
) O2
WHERE O2.row_no = 1

答案 1 :(得分:1)

您也可以按[UtcDateTime]使用ROW_NUMBER顺序,并按[SomeId]分区以获得第一次出现。

SELECT  *
FROM    (
            SELECT  *,
                    ROW_NUMBER () OVER (PARTITION BY SomeId ORDER BY [UtcDateTime]) RN 
            FROM    #Temp
        ) t
WHERE   Rn = 1

答案 2 :(得分:1)

你没有错,但你可以尝试这个(更简单的方法):

SELECT SomeId, MIN(UTCDateTime) AS UTCDateTime FROM #Temp GROUP BY SomeId

将为每个'SomeId'

捕获第一个匹配项

答案 3 :(得分:0)

选择没有具有相同ID和更早时间戳的行的行:

SELECT SomeId, UtcDateTime
FROM Temp AS T1
WHERE NOT EXIST (
    SELECT 1 FROM Temp AS T2
    WHERE T1.SomeId = T2.SomeId
    AND T2.UtcDateTime < T1.UtcDateTime)