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(即我需要每个组的一个结果)。

如何更改我的查询以从每个组中获取一个结果?

谢谢!

4

5 回答 5

4

由于ORDER BY NEWID()无论如何都会导致 tablescan,您可以使用 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 回答