2

データベースを利用したゲームを作成するプロジェクトがあります。

データベースには、次のように入力されたデータがあります。

(ID、名前) || (1,PhotoID)、(1,PhotoID)、(1,PhotoID)、(2,PhotoID)、(2,PhotoID)など。何千ものエントリがあります。

これは私の現在のSQLステートメントです:

$sql = "SELECT TOP 8 * FROM Image WHERE Hidden = '0' ORDER BY NEWID()";

ただし、これは一致する ID を持つ結果を生成することもできます。この場合、各結果に一意の ID を持たせる必要があります (つまり、各グループから 1 つの結果が必要です)。

各グループから 1 つの結果を取得するようにクエリを変更するにはどうすればよいですか?

ありがとう!

4

5 に答える 5

4

いずれにしてもtablescanORDER BY NEWID()になるため、row_number() を使用してグループ内で最初に分離することができます。

; with randomizer as (
  select id,
         name,
         row_number() over (partition by id
                            order by newid()) rn
    from Image
   where hidden = 0
)
select top 8
       id,
       name
  from randomizer
 where rn = 1
-- Added by mellamokb's suggestion to allow groups to be randomized
order by newid()

mellamokb のおかげで Sql Fiddle プレイグラウンド。

于 2012-07-31T22:42:29.927 に答える
2

これはうまくいくように見えますが、パフォーマンスを保証することはできません:

SELECT TOP 8 ID,
  (select top 1 name from image i2
   where i2.id = i1.id order by newid())
FROM Image i1
WHERE hidden = '0'
group by ID
ORDER BY NEWID();

デモ: http://www.sqlfiddle.com/#!3/657ad/6

于 2012-07-31T22:39:43.487 に答える
2

列にインデックスがあり、インデックスIDを利用してフル テーブル スキャンを回避したい場合は、最初にキー値のランダム化を行います。

WITH IDs AS
(
  SELECT DISTINCT ID
  FROM Image
  WHERE Hidden = '0'
),
SequencedIDs AS
(
  SELECT ID, ROW_NUMBER() OVER (ORDER BY NEWID()) AS Seq
  FROM IDs
),
ImageGroups AS
(
  SELECT i.*, ROW_NUMBER() OVER (PARTITION BY i.ID ORDER BY NEWID()) Seq
  FROM SequencedIDs s
  INNER JOIN Image i
    ON i.ID = s.ID
  WHERE s.Seq < 8
  AND i.Hidden = '0'
)
SELECT *
FROM ImageGroups
WHERE Seq = 1

これにより、テーブルスキャンアプローチよりもコストが大幅に削減されるはずですが、テストできるほど大きなスキーマがないため、SSMS でいくつかの統計を実行してみてID、これが効果的になるように実際にインデックスが作成されていることを確認してください。

于 2012-07-31T23:13:39.900 に答える
1
select * from (select * from photos order by rand()) as _SUB group by _SUB.id;
于 2012-07-31T22:32:53.693 に答える
0
 select ID, Name from (select ID, Name, row_number() over 
 (partition by ID, Name order by ID) as ranker from Image where Hidden = 0 ) Z where ranker = 1
 order by newID()
于 2012-07-31T22:39:38.510 に答える