Select random rows and stop when a specific sum/total is reached

狂风中的少年 提交于 2019-12-11 01:04:14

问题


I'm using SQL Server 2012 and I'm trying to do something like this:

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
*/

So in other words, I want to select random rows from a table that have a specified from and to date and stop when the sum of miles is at or over the number: 3250


回答1:


Since you're using SQL Server 2012, here is a much easier approach that doesn't require looping.

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 - hit "Run SQL" multiple times to see random results.




回答2:


You can do SELECT TOP x ... ORDER BY newid() to get a sum of random rows. The problem lies in determining 'x'. You can't even be sure that the largest value of 'x' (number of rows that match the query) will have a total large enough to meet your requirements without testing that first:

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

Just a note about this - the algorithm starts and 1 and increments up until a suitable match is found. A more efficient approach (for larger sets of data) might include a binary type search that caches the lowest suitable result and returns when the deepest node (or an exact match) is found.




回答3:


I can't think of a way without a TSQL While... loop. This in combination with the TSQL paging with ROW_NUMBER() should get you there.

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

In the ROW_NUMBER query, sum the Miles into another MileSum column, then in the while loop select the set all the rows that correspond with the ROW_NUMBER query while accumulating these MileSum values into a variable. Terminate when the variable exceeds 3250.




回答4:


Try

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

and then you can add a TOP 5 or whatever you want. You get those in random order for sure.




回答5:


Just a sample code for you to understand the concept.

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

The reason for this approach is that paging would not return wide spread result unless and until you have thousands of records because in it the data is grouped into pages and with less records, the same page is hit multiple number of times giving the same result.

Also, there might be cases when a blank page is hit giving 0 as the result.(i don't know why sometimes a blank page is hit.)



来源:https://stackoverflow.com/questions/15278143/select-random-rows-and-stop-when-a-specific-sum-total-is-reached

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!