5

私は次の問題のSQLクエリの形で洗練された解決策を見つけようとしています。

新しいレコードがログテーブルに挿入されます。以前に見たことがない新しいレコード(過去1時間に挿入された)を検出し、アラートを生成する必要があります(たとえば、これらのレコードの数> 0)

ID, Url, DOB
1, site1.com/page1, "5/06/2012 20:01"
2, site2.com/page2, "5/06/2012 21:20"
3, site1.com/page1, "6/06/2012 10:05"

「now」が2012年6月6日10:40の場合-1つの新しいレコード(id = 3)が挿入されたことがわかりますが、以前にこのURLを見たことがあるため(id = 1)アラートを生成したくありません。

4、site3.com / pageX、 "6/06/2012 10:08"がある場合、この行は過去1時間に挿入されたものであり、表示されていないため、アラート(return count = 1)を生成します。前。

それを実装するための最良の方法は何ですか?ネストされたクエリなしが理想的

4

5 に答える 5

5

これがあなたが求めているものだと思います。これにより、過去1時間に新しいエントリが取得されます(新規とは、過去1時間に同じURLにアクセスされていないことを意味します)

SELECT  *
FROM    Log
WHERE   DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
AND     NOT EXISTS
        (   SELECT  1
            FROM    Log T1
            WHERE   T1.URL = Log.URL 
            AND     T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
        )

SQLフィドルの実例

編集

カウントだけが必要なコメントを見たばかりです。

SELECT  COUNT(*)
FROM    Log
WHERE   DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
AND     NOT EXISTS
        (   SELECT  1
            FROM    Log T1
            WHERE   T1.URL = Log.URL 
            AND     T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP)
        )

編集2

単一の選択のみである必要がある理由はわかりませんが、単一の選択に最も近いのは次のとおりです。

SELECT  COUNT(*)
FROM    (   SELECT  *, MIN(DOB) OVER(PARTITION BY URL) [FirstViewed]
            FROM    Log
        ) Log
WHERE   FirstViewed >= DATEADD(HOUR, -1, CURRENT_TIMESTAMP)

過去1時間に同じページに2回アクセスした場合でも、2が返されます。

http://sqlfiddle.com/#!3/5a8bc/1

于 2012-06-07T13:10:48.053 に答える
2

これは別の方法を実行します。最初にグループ化して一意のURLを検索し、次に過去1時間にそれらを抽出します。

SELECT x1.*
FROM
  (SELECT URL,
          COUNT(ID) AS urlcount,
          MAX(DOB) AS uniqueurl
   FROM Log
   GROUP BY URL HAVING count(ID) = 1
   OR MIN(DOB) > dateadd(HOUR ,-1 , CURRENT_TIMESTAMP)) AS x1
WHERE x1.uniqueurl > dateadd(HOUR ,-1 , CURRENT_TIMESTAMP);

http://sqlfiddle.com/#!3/250e0/45/0

説明を見ないと、これが許容できるパフォーマンスであるかどうかはわかりませんが、groupbyに含まれるソート操作がボトルネックになる可能性があると思います。

于 2012-06-07T13:35:24.487 に答える
1

ネストされたクエリなし(SQLFiddle):

SELECT COUNT(DISTINCT T0.URL) 
FROM Log AS T0 
LEFT OUTER JOIN Log AS T1 ON 
    T1.URL = T0.URL 
    AND T1.DOB < DATEADD(HOUR, -1, CURRENT_TIMESTAMP) 
WHERE 
    T0.DOB > DATEADD(HOUR, -1, CURRENT_TIMESTAMP) 
    AND T1.ID IS NULL

しかし、それは実際にはGarethDと同じソリューションであり、パフォーマンスの面で優れています。

于 2012-06-07T13:45:17.060 に答える
0

これを試して:

SELECT DISTINCT a.id, a.url, a.dob
FROM Log a JOIN Log b ON (a.url = b.url)
WHERE UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(a.DOB)<=3600 
  AND UNIX_TIMESTAMP(NOW())-UNIX_TIMESTAMP(b.DOB)>3600;

質問で指定したパターンに従うすべてのレコードが返されるはずです。

日付を秒に変換するために使用UNIX_TIMESTAMPしていることに注意してください。これにより、減算によって秒数で表される時間の差が返されます。また、3600秒に対して比較する必要があります。

編集

文が修正されました。しかし、それはMySQL用です(sql-server2005タグが表示されませんでした)

于 2012-06-07T12:58:59.557 に答える
-1
select distinct(a.url) from tbl a, tbl b where a.dob>(now-hour) and b.dob<=(now-hour) and a.url=b.url; 

(時間操作を選択したデータベースの何かに置き換えます。URLとdobにインデックスを付けます)

また、データベースが、インデックスを使用して結合および結合する前にdob-comparisonを実行するのに十分な意味があることを期待してください。

于 2012-06-07T12:46:26.023 に答える