5

2つの識別列を使用するテーブルがあります。それらをidとuseridと呼びましょう。IDはすべてのレコードで一意であり、useridはユーザーに固有ですが、多くのレコードにあります。

私がする必要があるのは、ユーザーIDでユーザーのレコードを取得し、そのレコードをユーザーの最初のレコードに結合することです。クエリのロジックは次のとおりです。

SELECT v1.id, MIN(v2.id) AS entryid, v1.userid
FROM views v1
INNER JOIN views v2
  ON v1.userid = v2.userid

コードのmin()部分を処理するサブクエリにテーブルを結合する必要がないことを望んでいます。これは、非常に遅いように思われるためです。

4

3 に答える 3

13

私はあなたがすべてのユーザーのために見つけたいと思うと思います、最小のテーブルの行、つまりidユーザーごとに1つの行。

その場合、サブクエリ(派生テーブル)を使用して、それをテーブルに結合します。

SELECT v.*
FROM views AS v
  JOIN
    ( SELECT userid, MIN(id) AS entryid
      FROM views
      GROUP BY userid
    ) AS vm
    ON  vm.userid = v.userid 
    AND vm.entryid = v.id ;

上記は、必要に応じて、共通テーブル式(CTE)を使用して記述することもできます。

; WITH vm AS
    ( SELECT userid, MIN(id) AS entryid
      FROM views
      GROUP BY userid
    )
  SELECT v.*
  FROM views AS v
    JOIN vm
      ON  vm.userid = v.userid 
      AND vm.entryid = v.id ;

のインデックスを使用すると、どちらも非常に効率的(userid, id)です。

ROW_NUMBER()SQL-Serverでは、ウィンドウ関数を使用してこれを記述できます。

; WITH viewsRN AS
    ( SELECT *
           , ROW_NUMBER() OVER (PARTITION BY userid ORDER BY id) AS rn
      FROM views
    ) 
  SELECT *                      --- skipping the "rn" column
  FROM viewsRN
  WHERE rn = 1 ;
于 2012-12-03T17:39:08.100 に答える
1

MINこの関数を非集計列と一緒に使用するには、ステートメントをグループ化する必要があります。それはあなたが持っているクエリで可能です...(追加情報に基づいて編集)

SELECT MIN(v2.id) AS entryid, v1.id, v1.userid
FROM views v1
INNER JOIN views v2
  ON v1.userid = v2.userid      
GROUP BY v1.id, v1.userid

...ただし、これが単なる例であり、このクエリを使用してより多くのデータを取得しようとしている場合、すぐに実行不可能なソリューションになります。

必要と思われるのは、このビューのすべてのユーザーデータのリストであり、各行に同じユーザーに存在する「最初の」レコードに戻るリンクがあります。上記のクエリで必要なものが得られますが、各ユーザーの最初のレコードを決定するためのはるかに簡単な方法があります。

SELECT v1.id, v1.userid
FROM views v1
ORDER BY v1.userid, v1.id

各一意のユーザーの最初のレコードは、「エントリポイント」です。なぜあなたが指定した方法でそれをやりたいのか理解していると思います、そして私が与えた最初のクエリはかなり実行可能ですが、正しい答えを得るためにorderby句を使用する必要がないかどうかを考慮する必要があります。

于 2012-12-03T17:32:22.200 に答える
-2

edit-1:コメントで指摘されているように、このソリューションもサブクエリを使用します。ただし、(データベースによっては)パフォーマンスに大きな影響を与える可能性のある集計関数は使用しません。


サブクエリなしで達成できます(以下を参照)。明らかに、のインデックスviews.useridはパフォーマンスにとって非常に価値があります。

SELECT      v1.*
FROM        views v1
WHERE       v1.id = (
        SELECT  TOP 1 v2.id
        FROM    views v2
        WHERE   v2.userid = v1.userid
        ORDER BY v2.id ASC
    )
于 2012-12-03T17:39:37.140 に答える