Reputation: 35
Could someone please advise on how to repeat the query if it returned no results. I am trying to generate a random person out of the DB using RAND
, but only if that number was not used previously (that info is stored in the column "allready_drawn").
At this point when the query comes over the number that was drawn before, because of the second condition "is null"
it does not display a result.
I would need for query to re-run once again until it comes up with a number.
DECLARE @min INTEGER;
DECLARE @max INTEGER;
set @min = (select top 1 id from [dbo].[persons] where sector = 8 order by id ASC);
set @max = (select top 1 id from [dbo].[persons] where sector = 8 order by id DESC);
select
ordial,
name_surname
from [dbo].[persons]
where id = ROUND(((@max - @min) * RAND() + @min), 0) and allready_drawn is NULL
The results (two possible outcomes):
Any suggestion is appreciated and I would like to thank everyone in advance.
Upvotes: 0
Views: 242
Reputation: 88852
@gbn that's a correct solution, but it's possible it's too expensive. For very large tables with dense keys, randomly picking a key value between the min and max and re-picking until you find a match is also fair, and cheaper than sorting the whole table.
Also there's a bug in the original post, as the min and max rows will be selected only half as often as the others, as each maps to a smaller interval. To fix generate a random number from @min to @max + 1, and truncate, rather than round. That way you map the interval [N,N+1) to N, ensuring a fair chance for each N.
For this selection method, here's how to repeat until you find a match.
--drop table persons
go
create table persons(id int, ordial int, name_surname varchar(2000), sector int, allready_drawn bit)
insert into persons(id,ordial,name_surname,sector, allready_drawn)
values (1,1,'foo',8,null),(2,2,'foo2',8,null),(100,100,'foo100',8,null)
go
declare @min int = (select top 1 id from [dbo].[persons] where sector = 8 order by id ASC);
declare @max int = 1+ (select top 1 id from [dbo].[persons] where sector = 8 order by id DESC);
set nocount on
declare @results table(ordial int, name_surname varchar(2000))
declare @i int = 0
declare @selected bit = 0
while @selected = 0
begin
set @i += 1
insert into @results(ordial,name_surname)
select
ordial,
name_surname
from [dbo].[persons]
where id = ROUND(((@max - @min) * RAND() + @min), 0, 1) and allready_drawn is NULL
if @@ROWCOUNT > 0
begin
select *, @i tries from @results
set @selected = 1
end
end
Upvotes: 0
Reputation: 432180
Just try this to remove the "id" filter so you only have to run it once
select TOP 1
ordial,
name_surname
from [dbo].[persons]
where allready_drawn is NULL
ORDER BY NEWID()
Upvotes: 1