比较表的记录并在sql server中过滤它们的数据

时间:2017-08-29 19:53:00

标签: 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-06-01 08:02:00' 和 '2017-06-01 09:01:00'并忽略其他记录。

我可以通过distinct关键字忽略重复记录(具有相同日期),但我不知道如何比较记录并选择日期差异大于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

你能帮助我,还是你对这个问题有更好的了解?

感谢

更新:

感谢您提供解决方案,我使用的是SQL Server 2014。

3 个答案:

答案 0 :(得分:2)

假设您使用的是SQL Server 2012或更高版本,则可以使用LAG&amp; 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

答案 1 :(得分:0)

这实际上取决于您使用的SQL Server版本。以下是两个解决方案,一个适用于SQL Server 2012及更高版本,另一个适用于SQL Server 2008及更高版本。

第一个是SQL 2008及更高版本:

const expected = {/* very large object */}
test('returns data from `server/index.js` and it contains an array containing the `expected` object', () => {
  expect(data.els[4]).toEqual(
    expect.objectContaining(expected)
  )
})

这个适用于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 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);

答案 2 :(得分: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