2

SELECT選択した行が以前に選択した行の日時よりも一定の分数だけ大きいテーブルのすべての行が必要です。例はおそらく最もよく話します。

以下はデータのテーブルを表しています - これを myTable と呼びます。

guid     fkGuid   myDate
-------  -------  ---------------------
1        100      2013-01-10 11:00:00.0
2        100      2013-01-10 11:05:00.0
3        100      2013-01-10 11:10:00.0
4        100      2013-01-10 11:15:00.0
5        100      2013-01-10 11:20:00.0
6        100      2013-01-10 11:25:00.0
7        100      2013-01-10 11:30:00.0
8        100      2013-01-10 11:35:00.0
9        100      2013-01-10 11:40:00.0
10       100      2013-01-10 11:50:00.0
11       100      2013-01-10 11:55:00.0

私がやりたいことは、一定の増分 (たとえば 10 分) を提供し、前の行から 10 分以上の最初の行をすべて取得することです。したがって、10 分の結果セットは次のようになります。

guid     myDate
-------  ---------------------
1        2013-01-10 11:00:00.0
3        2013-01-10 11:10:00.0
5        2013-01-10 11:20:00.0
7        2013-01-10 11:30:00.0
9        2013-01-10 11:40:00.0
11       2013-01-10 11:55:00.0

定数は変数として渡されるため、何でもかまいません。23 分だったとします。結果セットは次のようになります。

guid     myDate
-------  ---------------------
1        2013-01-10 11:00:00.0
6        2013-01-10 11:25:00.0
10       2013-01-10 11:50:00.0

最後の例は、行 0 の時刻 (11:00:00) から開始して 23 分を追加し、次の >= 行である 11:25:00 を取得し、新しい行の時刻に 23 分を追加してから次の ( 11:50:00) など。

私はCTEでこれをやろうとしましたが、すべての時間を簡単に取り戻すことができますが、必要な行を取得する方法がわかりません。WHERE句にハードコードされた23分を使用した現在のテストコード:

WITH myCTE AS
(
    SELECT guid,
           myDate,
           ROW_NUMBER() OVER (PARTITION BY guid ORDER BY myDate ASC) AS rowNum
    FROM myTable
    WHERE fkGuid = 100
)

SELECT currentRow.guid, currentRow.myDate
FROM myCTE AS currentRow
LEFT OUTER JOIN
    myCTE AS previousRow
    ON currentRow.guid = previousRow.guid
    AND currentRow.rowNum = previousRow.rowNum + 1
WHERE
    currentRow.myDate > DATEADD(minute, 23, previousRow.myDate)
ORDER BY
    currentRow.myDate ASC

これは何も返しません。句を省略すると、WHEREすべての行が返されます (明らかに、フィルタリングしていないためです)。

私は何が欠けていますか?

いつものように、すべての助けをいただければ幸いです。

4

2 に答える 2

2

@gilly3、ほとんどSQLブードゥー教ではありません

WITH CTE
AS
(
  SELECT TOP 1
         guid 
        ,fkGuid
        ,myDate
        ,ROW_NUMBER() OVER (ORDER BY myDate) RowNum
  FROM MyTable
  UNION ALL
  SELECT mt.guid
        ,mt.fkGuid
        ,mt.myDate
        ,ROW_NUMBER() OVER (ORDER BY mt.myDate)
  FROM  MyTable mt
        INNER JOIN
        CTE ON mt.myDate>=DATEADD(minute,23,CTE.myDate)
  WHERE RowNum=1
)
SELECT guid
       ,fkGuid
       ,myDate
FROM   CTE
WHERE  RowNum=1

SQL フィドルはこちら

于 2013-02-08T06:06:12.553 に答える
0

まず、where句に関係なく、結合によって行が返されることはありません。GuidとrowNumはどちらも行ごとに一意のキーであるため、guidが同じである場合は、rowNumも同じになります。からフィールドを選択リストに追加し、句previousRowなしでクエリを実行すると、結合が常に失敗することがわかります。where

次に、onに参加すると、rowNum + 1行がスキップされなくなります。日付フィルターを満たす隣接する行のみを選択します。

これを機能させる再帰クエリを使用したSQLブードゥーが存在する可能性がありますが、パフォーマンスが大幅に低下します。アプリケーションコードでデータをフィルタリングします。たとえば、C#の場合:

List<DataRow> FilterByInterval(IEnumerable<DataRow> rows, string dateColumn, int minutes)
{
    List<DataRow> filteredRows = new List<DataRow>();
    DateTime lastDate = DateTime.MinValue;
    foreach (DataRow row in rows)
    {
        DateTime dt = row.Field<DateTime>(dateColumn);
        TimeSpan diff = dt - lastDate;
        if (diff.TotalMinutes >= minutes)
        {
            filteredRows.Add(row);
            lastDate = dt;
        }
    }
    return rows;
}
于 2013-02-08T03:52:35.727 に答える