2017-08-29 49 views
0

過濾他們的數據我有一個表,包括像下面的數據:比較表中的記錄,並在SQL Server

PersonalID | Date 

193  | 2017-06-01 08:02:00 
193  | 2017-06-01 08:03:00 
193  | 2017-06-01 08:03:00 
193  | 2017-06-01 08:04:00 
193  | 2017-06-01 08:09:00 
193  | 2017-06-01 09:01:00 
193  | 2017-06-01 09:06:00 
193  | 2017-06-01 09:08:00 

我想選擇的所有記錄,他們的時間差超過10分鐘大。

例如,根據這個數據我想,以顯示與日期 記錄「2017年6月1日8點02分00秒」 和 「2017年6月1日9點01分00秒」,而忽略其他記錄。

我可以通過不同的關鍵字忽略重複記錄(具有相同日期),但我不知道如何比較記錄並選擇日期差異大於10分鐘的記錄。

我使用此查詢來實現此目的,但它返回錯誤的記錄。

declare @space int = 10; 

with aaa as (select main.ID, main.PersonalID, main.Date 
from HZG_Traffic main 
where exists(select * from HZG_Traffic tr 
where tr.PersonalID = main.PersonalID and 
ABS(DATEDIFF(MI, main.Date,tr.Date)) < @space and 
ABS(DATEDIFF(MI, main.Date, tr.Date)) <> 0) 
and main.PersonalID = 193) 

Select * from aaa 
where id not in 
(select 
    MIN(ID) 
from aaa 
group by 
PersonalID, 
DATEPART(DAY, Date), DATEPART(MONTH, Date), DATEPART(YEAR, Date), 
DATEPART(HOUR, Date)) 
order by Date desc 

你能幫助我還是你有更好的想法解決這個問題?

感謝

UPDATE:

感謝的解決方案,我使用SQL Server 2014

+0

什麼版本的SQL Sever的嗎? – Greenspark

回答

1

假設你使用SQL Server 2012或更高版本,可以使用LAG & LEAD功能...

IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData; 

CREATE TABLE #TestData (
    PersonalID INT NOT NULL, 
    SomeDate DATETIME2(0) NOT NULL 
    ); 
INSERT #TestData (PersonalID, SomeDate) VALUES 
    (193, '2017-06-01 08:02:00'), 
    (193, '2017-06-01 08:03:00'), 
    (193, '2017-06-01 08:03:00'), 
    (193, '2017-06-01 08:04:00'), 
    (193, '2017-06-01 08:09:00'), 
    (193, '2017-06-01 09:01:00'), 
    (193, '2017-06-01 09:06:00'), 
    (193, '2017-06-01 09:08:00'); 

-- SELECT * FROM #TestData td; 

--================================================== 

WITH 
    cte_LagLead AS (
     SELECT 
      td.PersonalID, td.SomeDate, 
      LagMins = ABS(DATEDIFF(MINUTE, td.SomeDate, LAG(td.SomeDate, 1, td.SomeDate) OVER (PARTITION BY td.PersonalID ORDER BY td.SomeDate))), 
      LeadMins = DATEDIFF(MINUTE, td.SomeDate, LEAD(td.SomeDate, 1, td.SomeDate) OVER (PARTITION BY td.PersonalID ORDER BY td.SomeDate)) 
     FROM 
      #TestData td 
     ) 
SELECT 
    ll.PersonalID, ll.SomeDate 
FROM 
    cte_LagLead ll 
WHERE 
    ll.LagMins > 10 
    OR 
    ll.LeadMins > 10; 

結果...

PersonalID SomeDate 
----------- --------------------------- 
193   2017-06-01 08:09:00 
193   2017-06-01 09:01:00 
0

它確實取決於您使用的是哪個版本的SQL Server。以下是兩種解決方案,一種可以與SQL Server 2012及更高版本一起使用,另一種可與SQL Server 2008及更高版本一起使用。

第一個是SQL 2008和更高:

/* Populating the temp table with the data */ 
DECLARE @HZG_Traffic TABLE 
(PersonalID INT,Date DATETIME); 

INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:08:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:02:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:03:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:03:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:04:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:09:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:01:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:06:00'); 

/* Start with a CTE to number each record for the PersonalID */ 
WITH main AS (
    SELECT 
     ROW_NUMBER() OVER(PARTITION BY ht.PersonalID ORDER BY ht.Date) AS Row_No 
     ,ht.PersonalID 
     ,ht.Date 
    FROM @HZG_Traffic AS ht 
    ) 
SELECT 
    main.PersonalID 
    ,main.Date 
FROM main 
/* Self-join to get the previous record */ 
LEFT JOIN main AS prev ON main.PersonalID = prev.PersonalID AND main.Row_No-1 = prev.Row_No 
/* Another self join to get the next record */ 
LEFT JOIN main AS nex ON main.PersonalID = nex.PersonalID AND main.Row_No+1 = nex.Row_No 
/* Have the OR clause so it will return both records */ 
WHERE 10 <= DATEDIFF(MINUTE, main.Date, nex.Date) 
OR 10 <= DATEDIFF(MINUTE, prev.Date,main.Date); 

這一次將與SQL 2012和工作都高:

/* Populating the temp table with the data */ 
DECLARE @HZG_Traffic TABLE 
(PersonalID INT,Date DATETIME); 

INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:08:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:02:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:03:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:03:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:04:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 08:09:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:01:00'); 
INSERT INTO @HZG_Traffic (PersonalID,Date) VALUES (193,'2017-06-01 09:06:00'); 

/* Start with a CTE to get the next and previous records */ 
WITH main AS (
SELECT 
    ht.PersonalID, ht.Date 
    ,LEAD(ht.Date) OVER(PARTITION BY ht.PersonalID ORDER BY ht.Date) AS Next_Date 
    ,LAG(ht.Date) OVER(PARTITION BY ht.PersonalID ORDER BY ht.Date) AS Prev_Date 
FROM @HZG_Traffic AS ht 
) 
SELECT 
    main.PersonalID 
    ,main.Date 
FROM main 
/* Have the OR clause so it will return both records */ 
WHERE 10 <= DATEDIFF(MINUTE, main.Date, main.Next_Date) 
OR 10 <= DATEDIFF(MINUTE, main.Prev_Date, main.Date); 
0

你說要2017-06-01 08:02:00.0002017-06-01 09:01:00.000,如果是的話,你可以嘗試這樣的事情。

SELECT * 
FROM HZG_Traffic t1 
     CROSS APPLY ( 
      SELECT MIN([Date]) AS MinDate 
      FROM HZG_Traffic t2 
      WHERE t1.PersonalID = t2.PersonalID 
        AND DATEDIFF(Minute, t2.[Date], t1.[Date]) < 10) t2 
WHERE t1.[Date] = t2.MinDate 

SQL Fiddle Demo