10

私はこのサイトに不慣れですが、我慢してください。

SQLServerを使用してデータを取得しようとしてGROUP BYいます。

データは次のとおりです。

Computer    VisitDate
ComputerA   2012-04-28 09:00:00
ComputerA   2012-04-28 09:05:00
ComputerA   2012-04-28 09:10:00
ComputerB   2012-04-28 09:30:00
ComputerB   2012-04-28 09:32:00
ComputerB   2012-04-28 09:44:00
ComputerB   2012-04-28 09:56:00
ComputerB   2012-04-28 10:25:00
ComputerA   2012-04-28 12:25:00
ComputerC   2012-04-28 12:30:00
ComputerC   2012-04-28 12:35:00
ComputerC   2012-04-28 12:45:00
ComputerC   2012-04-28 12:55:00

私が達成しようとしているのは、データをコンピューターごとにグループ化することですが、コンピューターの訪問時間が1時間より長い場合はグループ化することもできます。これが私がやろうとしていることの結果です:

Computer     VisitDate
ComputerA    2012-04-28 09:00:00
ComputerB    2012-04-28 09:30:00
ComputerA    2012-04-28 12:25:00
ComputerC    2012-04-28 12:30:00

つまりComputer A、09:10:00に訪問し、12:25:00に再度訪問したため、2回表示されます。これは、1時間以上の差を意味します。

「GROUPBYComputer」は簡単ですが、もう1つは、どこから始めればよいのかわかりません。この問題についての助けをいただければ幸いです。

4

3 に答える 3

5

単純なでこれを行うことはできませんGROUP BYこの演算子は単一の列でのみ機能します。たとえば、コンピューター名などでグループ化することはできますが、時間の差が1時間より大きくなければならないなどのロジックをグループ化に追加することはできません。

できること-SQLServer2005以降を使用している場合(質問でバージョンについて言及していなかった場合)、CTE(共通テーブル式)を使用することになります。これらは、データをスライスアンドダイスする方法を提供します。

ここでは、いくつかのことを行っています。最初に、データを「パーティション化」しComputerName、並べ替えて、各パーティションの連番を取得するためVisitDateに使用しています。ROW_NUMBER()次に、2番目のCTEが各コンピューターの「最初の」エントリ(行番号= 1のエントリ)を決定しVisitDate、3番目のCTEが、行番号= 1のエントリと比較した各エントリの違いを最終的に決定します。その3番目のCTEから、最後に、行番号= 1(各「パーティション」の最初)または60分以上の差があるエントリを選択します。

コードは次のとおりです。

;WITH Computers AS
(
    SELECT
        ComputerName, VisitDate,
        RN = ROW_NUMBER() OVER(PARTITION BY ComputerName ORDER BY VisitDate)
    FROM    
        dbo.YourComputerTable
),
FirstComputers AS
(
    SELECT ComputerName, VisitDate
    FROM Computers
    WHERE RN = 1
),
SelectedComputers AS
(
    SELECT 
        c.ComputerName, c.VisitDate, c.RN,
        DiffToFirst = ABS(DATEDIFF(MINUTE, c.VisitDate, fc.VisitDate))
    FROM Computers c
    INNER JOIN FirstComputers fc ON c.ComputerName = fc.ComputerName
)
SELECT * 
FROM SelectedComputers
WHERE RN = 1 OR DiffToFirst >= 60
于 2012-04-28T14:46:18.100 に答える
2

SQL Server 2012にアップグレードした場合は、LAGを使用できます。

with Lagged as (
  select
    Computer,
    VisitDate,
    LAG(VisitDate,1) over (
      partition by Computer
      order by VisitDate
    ) as LastVisit
  from @Visit
)
  select
    Computer,
    VisitDate
  from Lagged
  where LastVisit is null
  or VisitDate > dateadd(hour,1,LastVisit);

SQLフィドルはこちら

于 2012-04-29T00:24:32.237 に答える
0

CTEは、少なくとも1回の訪問、または60分を超えるギャップの前後の訪問があるすべてのコンピューターを表示します。

create table compVisits (Computer varchar(20), VisitDate datetime)
go
insert into compVisits values
('ComputerA', '2012-04-28 09:00:00')
, ('ComputerA', '2012-04-28 09:05:00')
, ('ComputerA', '2012-04-28 09:10:00')
, ('ComputerB', '2012-04-28 09:30:00')
, ('ComputerB', '2012-04-28 09:32:00')
, ('ComputerB', '2012-04-28 09:44:00')
, ('ComputerB', '2012-04-28 09:56:00')
, ('ComputerB', '2012-04-28 10:25:00')
, ('ComputerA', '2012-04-28 12:25:00')
, ('ComputerC', '2012-04-28 12:30:00')
, ('ComputerC', '2012-04-28 12:35:00')
, ('ComputerC', '2012-04-28 12:45:00')
, ('ComputerC', '2012-04-28 12:55:00')

; WITH a as ( --Initial row count
    select *, r=ROW_NUMBER()OVER(PARTITION BY Computer ORDER BY VisitDate)
    FROM compVisits
)
, b as ( -- gaps >60 minutes
    SELECT a1.Computer, a1.VisitDate
    FROM a a1
    INNER JOIN a a2 ON a1.Computer=a2.Computer AND (a1.r+1)=a2.r
    AND DATEDIFF(MINUTE,a1.VisitDate,a2.VisitDate)>60
    UNION
    SELECT a2.Computer, a2.VisitDate
    FROM a a1
    INNER JOIN a a2 ON a1.Computer=a2.Computer AND (a1.r+1)=a2.r
    AND DATEDIFF(MINUTE,a1.VisitDate,a2.VisitDate)>60
)
-- at least one visit
SELECT a1.Computer, a1.VisitDate
FROM a a1
WHERE r=1
AND NOT EXISTS(SELECT 1 FROM b WHERE Computer=a1.Computer)

UNION

-- gaps >60 minutes
SELECT * FROM b
ORDER BY VisitDate

結果:

ここに画像の説明を入力してください

于 2012-04-28T15:28:48.250 に答える