选择随机行并在达到特定总和/总数时停止

时间:2013-03-07 17:46:44

标签: sql sql-server sql-server-2012

我正在使用SQL Server 2012而我正在尝试这样做:

SELECT SUM(MILES) from tblName WHERE 
mDate > = '03/01/2012' and 
mDate <= '03/31/2012' 
-- and...
/* 
   now I want to add here do until the SUM of Miles 
   is equal to or greater then '3250' and get the 
   results rows randomly
*/

换句话说,我想从表格中选择具有指定日期和日期的随机行,并在英里总和达到或超过该数字时停止:3250

5 个答案:

答案 0 :(得分:3)

由于您使用的是SQL Server 2012,因此这是一种更简单的方法,不需要循环。

DECLARE @tbl TABLE(mDate DATE, Miles INT)

INSERT @tbl VALUES
('20120201', 520),  ('20120312', 620),
('20120313', 720),  ('20120314', 560),
('20120315', 380),  ('20120316', 990),
('20120317', 1020), ('20120412', 520);

;WITH x AS 
(
 SELECT 
   mDate, 
   Miles, 
   s = SUM(Miles) OVER 
   (
     ORDER BY NEWID() ROWS UNBOUNDED PRECEDING
   )
 FROM @tbl
 WHERE mDate >= '20120301' 
 AND mDate < '20120401'
)
SELECT 
  mDate, 
  Miles, 
  s
FROM x 
WHERE s <= 3250
ORDER BY s;

SQLfiddle demo - 多次点击“运行SQL”以查看随机结果。

答案 1 :(得分:2)

您可以SELECT TOP x ... ORDER BY newid()获取随机行的总和。问题在于确定'x'。您甚至不能确定'x'的最大值(与查询匹配的行数)总数大到足以满足您的要求而不先测试:

DECLARE @stopAt int
DECLARE @x int
DECLARE @result int

SET @stopAt = 3250
SET @x = 1

SELECT @result = SUM(MILES) from tblName 
WHERE 
  mDate >= '03/01/2012' and 
  mDate <= '03/31/2012'

IF (@result < @stopAt)
  SELECT NULL -- this can't be done
ELSE
  BEGIN
    WHILE (1=1)
    BEGIN
      SELECT TOP (@x) @result = SUM(MILES) FROM tblName
      WHERE 
        mDate >= '03/01/2012' and 
        mDate <= '03/31/2012'
      ORDER BY newid()
      IF @result >= @stopAt
        BREAK
      SET @x = @x + 1
    END
    SELECT @result
  END

关于这一点的注释 - 算法启动并且1递增直到找到合适的匹配。更有效的方法(对于更大的数据集)可能包括二进制类型搜索,它缓存最低的合​​适结果,并在找到最深节点(或完全匹配)时返回。

答案 2 :(得分:0)

只是一个示例代码,供您理解这个概念。

create table temp(intt int)
insert into temp values(1)
insert into temp values(2)
insert into temp values(3)
insert into temp values(4)
insert into temp values(5)
insert into temp values(6)
insert into temp values(7)
insert into temp values(8)
insert into temp values(9)
insert into temp values(10)
insert into temp values(11)
insert into temp values(12)
insert into temp values(13)
insert into temp values(14)
insert into temp values(15)
insert into temp values(16)
insert into temp values(17)
insert into temp values(18)
insert into temp values(19)
insert into temp values(20)
insert into temp values(21)

declare @sum int = 0;
declare @prevInt int = 0;
while(@sum<50)
begin
set @prevInt = (select top(1) intt from temp order by newid());
set @sum = @sum + @prevInt;
end
set @sum = @sum-@prevInt;
select @sum
drop table temp

这种方法的原因是分页不会返回广泛传播的结果,除非并且直到你有数千条记录,因为在其中数据被分组到页面并且记录较少,同一页面被多次命中给出同样的结果。

此外,可能会出现一个空白页面被命中为0的情况。(我不知道为什么有时会出现空白页面。)

答案 3 :(得分:0)

我想不出没有TSQL While ...循环的方法。这与使用ROW_NUMBER()的TSQL分页相结合可以帮助您实现目标。

http://www.mssqltips.com/sqlservertip/1175/page-through-sql-server-results-with-the-rownumber-function/

在ROW_NUMBER查询中,将Miles与另一个MileSum列相加,然后在while循环中选择与ROW_NUMBER查询对应的所有行,同时将这些MileSum值累积到变量中。当变量超过3250时终止。

答案 4 :(得分:0)

尝试

SELECT MILES
     , RANK() OVER (ORDER BY NEWID()) yourRank
FROM @tblName 
WHERE miles>3250
  AND mDate >= '03/01/2012' 
  AND mDate <= '03/31/2012'
ORDER BY yourRank

然后你可以添加TOP 5或任何你想要的。 你肯定会以随机顺序得到那些。