SQL - 即使存在少于X的记录,也可以检索顶级(X)记录

时间:2013-11-26 18:09:45

标签: sql random

在我的应用程序中,有几个地方会向用户显示一组随机的X项。 UI要求显示正好X项。但是,无法保证表中会有X项。所以,如果没有X项,我需要用随机副本填充结果。

我需要写一个基本上是的查询:

SELECT TOP(@count) *
FROM Things
ORDER BY NEWID()

我希望能够向SQL索取X记录,并且每次都能获得准确的X记录。有没有一种简单的方法可以在SQL中实现这一点?

谢谢。

4 个答案:

答案 0 :(得分:8)

嗯,我有一个解决方案,但我仍然认为这些要求很荒谬。这假定源表(在我的情况下,@t)至少有一行。如果你有零行,你究竟在演示什么?

DECLARE @count INT = 17; -- here is whatever your 'X' is; pick any value


DECLARE @t TABLE(i INT);

-- just insert 10 arbitrary values; test with @count = 5, @count = 247, etc.

INSERT @t VALUES(150),(170),(50),(100),(200),(230),(20),(800),(180),(632);

DECLARE @x INT; SELECT @x = COUNT(*) FROM @t;

SELECT TOP (@count) x.* FROM 
(
  -- limit this set to @count:
  SELECT TOP (@count) * FROM @t ORDER BY NEWID()
) AS x 
OUTER APPLY 
(
  -- limit this set the ratio of @count to rows in @t
  -- add one to round up for integer division:
  SELECT TOP (@count/@x+1) * FROM sys.all_objects 
  WHERE @count > @x -- only evaluate this subquery if we don't have enough rows
) AS y
ORDER BY NEWID(); -- need a 2nd ORDER BY in my tests to avoid pockets of same values

@billinkc提示the CROSS APPLY idea

答案 1 :(得分:2)

我最终创建了自己的解决方案。

DECLARE @count INT = 10; 

DECLARE @ids TABLE(id INT);

WHILE ((SELECT COUNT(*) FROM @ids) < @count)
BEGIN
    INSERT INTO @ids
        SELECT TOP(@count) ID
        FROM Things
        ORDER BY NEWID()
END

SELECT TOP(@count) t.*
FROM Things t
JOIN @ids ON t.ID = [@ids].id

答案 2 :(得分:1)

快速了解表数据有助于解决查询性能问题, 它可以帮助识别重复值,空值并理解数据。

我认为Aaron有最好的答案,但只是提到,使用TOP的答案... ORDER BY NEWID()对于大表有很大的性能问题, 他们至少诱导完整的索引(聚集或非聚集)扫描, 因为TOP是在SORT之后完成的 所有记录的NEWID。

另一个解决方案here 使用BINARY_CHECKSUM,RAND但根据评论似乎有缺陷。

另一个简单的解决方案是使用已添加到Sql2005的TABLESAMPLE选项

SELECT * FROM Sales.SalesOrderDetail TABLESAMPLE (1000 ROWS)

请参阅here

然而,它们是使用它的条件 “..样本不必是单个行级别的真正随机样本。     表的各个页面上的行与同一页面上的其他行不相关。 “ 并且根据描述和注释,输出似乎不是完全随机的。 而且,输出并不总是具有所需的行数see

答案 3 :(得分:0)

可以在T-SQL中完成:

SELECT *
FROM (
 SELECT TOP(@count) *
 FROM Things
 ORDER BY NEWID()
) x
UNION ALL
SELECT DummyValuesHere
FROM Numbers
WHERE Numbers.ID <= (@count - (SELECT COUNT(*) FROM Things))

你需要一个Numbers表。我们只需追加(UNION ALL)正确数量的虚拟行。

现在你看到查询有多可怕,考虑在应用程序中完成这项工作。 SQL不是这种查询的好工具。