Sql 基于时差合并记录?

Sql 基于时差合并记录?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有下表: CREATE TABLE #TEMP (id int, name varchar(255), startdate datetime, enddate datetime) INSERT INTO #TEMP VALUES(1, 'John', '2011-01-11 00:00:00.000','2011-01-11 00:01:10.000') INSERT INTO #TEMP VALUES(2, 'John', '2011-01-11 00:00:20.000','2011-01

我有下表:

CREATE TABLE #TEMP (id int, name varchar(255), startdate datetime, enddate datetime)
INSERT INTO #TEMP VALUES(1, 'John', '2011-01-11 00:00:00.000','2011-01-11 00:01:10.000')
INSERT INTO #TEMP VALUES(2, 'John', '2011-01-11 00:00:20.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(3, 'John', '2011-01-11 00:01:40.000','2011-01-11 00:01:50.000')
INSERT INTO #TEMP VALUES(4, 'Adam', '2011-01-11 00:00:40.000','2011-01-11 00:01:20.000')
INSERT INTO #TEMP VALUES(5, 'Adam', '2011-01-11 00:00:10.000','2011-01-11 00:01:30.000')

SELECT * FROM #TEMP

DROP TABLE #TEMP
我正在尝试在60秒内将具有相同名称的所有记录相互合并,以获得以下结果:

John 2011-01-11 00:00:00.000 2011-01-11 00:01:10.000
John 2011-01-11 00:01:40.000 2011-01-11 00:01:50.000
Adam 2011-01-11 00:00:10.000 2011-01-11 00:01:20.000
对于如何在一个有大约50K条记录的表上执行此操作,有什么建议吗?目前,我设法做到了这一点:

SELECT * FROM #TEMP

CREATE TABLE #Merge(id1 int, id2 int)

INSERT INTO #Merge
SELECT id, uuid
FROM
(
    SELECT t.id, u.uuid, t.name, t.startdate, t.enddate, u.ustartdate, u.uenddate,
           (CASE WHEN (DATEDIFF(second, t.startdate, u.ustartdate) <= 60 AND DATEDIFF(second, t.startdate, u.ustartdate) >= 0) then 1 else 0 END) Flag
    FROM #Temp t 
    INNER JOIN
    (SELECT id AS uuid, name, startdate AS ustartdate, enddate AS uenddate
    FROM #Temp) u 
    ON t.name = u.name AND t.startdate != u.ustartdate AND t.id != u.uuid
) w
WHERE Flag = 1

SELECT * FROM #Merge

-- Insert non-mergable records
CREATE TABLE #TEMP2 (id int, name varchar(255), membergroup varchar(255), startdate datetime, enddate datetime)
INSERT INTO #TEMP2
SELECT * FROM #TEMP
WHERE id NOT IN (SELECT id1 FROM #Merge UNION SELECT id2 FROM #Merge)

SELECT * FROM #TEMP2

假设您没有说明如何使用60秒间隔,并且示例代码仅显示startdate比较,那么就开始吧

SELECT
    *
FROM
    #Temp t1
    CROSS APPLY
    (SELECT TOP 1*
    FROM #Temp t2
    WHERE t1.name = t2.name AND DATEDIFF(second, t1.startdate, t2.startdate) < 60 AND t1.id < t2.id
    ORDER BY id DESC
    ) t2x
仅基于startdate,行对1/2和4/5将其作为输出。第3行没有,所以您必须解释添加它的原因

也就是说,行id=3不在基于startdate的行1或2的60秒内。所以它不应该出现在输出中

这假设id和startdate都在增加

聊天后编辑:

SELECT
    *
FROM
    #Temp t1
    CROSS APPLY
    (SELECT TOP 1 *
    FROM #Temp t2
    WHERE t1.name = t2.name AND DATEDIFF(second, t1.startdate, t2.startdate) < 60 AND t1.id < t2.id
    ORDER BY t2.id DESC
    ) t2x
UNION ALL
SELECT
    t1.*, t1.*
FROM
    #Temp t1
WHERE NOT EXISTS
(
    SELECT
        t1ZZ.id, t2xZZ.id
    FROM
        #Temp t1ZZ
        CROSS APPLY
        (SELECT TOP 1 *
        FROM #Temp t2ZZ
        WHERE t1ZZ.name = t2ZZ.name AND DATEDIFF(second, t1ZZ.startdate, t2ZZ.startdate) < 60 AND t1ZZ.id < t2ZZ.id
        ORDER BY t2ZZ.id DESC
        ) t2xZZ
     WHERE
        t1.id IN (t1ZZ.id, t2xZZ.id)
)

下面的代码管理显示合并行第1-2行、第4-5行和唯一行第3行

SELECT DISTINCT a.id,a.name,a.startdate,a.enddate
FROM temp a
  LEFT JOIN temp b ON a.name = b.name AND a.id < b.id AND DATEDIFF(s,a.startdate,b.startdate)<=60
  LEFT JOIN temp c ON c.name = a.name AND c.id < a.id AND DATEDIFF(s,c.startdate,a.startdate)<=60
WHERE (b.id IS NOT NULL OR c.id IS NULL) AND a.id <= COALESCE(c.id,a.id)

答案将取决于有多大,以及您拥有和/或能够添加的索引。。。另外,您要处理的日期/时间范围是在一个很小的时间范围内的一组非常大的用户,还是非常分散?换言之,一次性流程还是高容量需求?最后,我们还需要知道您希望如何处理在不同的60秒范围内创建的3条记录,第一条和第三条间隔40秒,但第二条和第三条记录都匹配,而3条记录间隔15秒。所有三条记录都在一个60秒范围内。谢谢您的评论。事实上,这张桌子没那么大。它有大约50K条记录,所以我可以在任何需要的列上添加索引。据我所见,数据是分散的。在一个时间间隔内,我希望有2-3条记录合并。如果不太难的话,我正在考虑合并这两种情况下的所有记录。你想要吗。。事实上,我还想问另一个问题:60秒的标准是什么?为什么John,C只根据您的示例比较开始日期时才进入输出+1谢谢您的时间。事实上,第3行确实进入了输出。合并的是第1行和第2行。在结果中,第一行是合并原始表中的第1行和第2行的结果。两行的Minstartdate和Minenddate构成了最后一个表的第1行的值。@图例如果我能知道它是否有效,那就太好了。适用于样本数据。+1感谢您抽出时间。我试过了。虽然它似乎在工作,但有一些重复的行可以修复,但有一个不同的问题。请查看我更新的测试集。它不合并输出2011-01-11 00:00:01.000。我不知道为什么会发生这种情况。我觉得这很有挑战性,并且总是想改进我的编码。我来看看。如果你有时间再试试:嗯。。。斗牛眼!工作完美。我所面临的唯一问题是,尽管添加了所有可能的索引,但在一个有50K条记录的表上大约需要6:40分钟。不确定这是否是查询中的工件。我在你的回答中加入了执行计划。再次感谢你。我会接受这个答案,因为它很简单。
SELECT DISTINCT a.id,a.name,a.startdate,a.enddate
FROM temp a
  LEFT JOIN temp b ON a.name = b.name AND a.id < b.id AND DATEDIFF(s,a.startdate,b.startdate)<=60
  LEFT JOIN temp c ON c.name = a.name AND c.id < a.id AND DATEDIFF(s,c.startdate,a.startdate)<=60
WHERE (b.id IS NOT NULL OR c.id IS NULL) AND a.id <= COALESCE(c.id,a.id)