开发者

New help with SQL Server select statement

I need help with select statement in SQL Server / T-SQL

My table looks like this:

Id (int)  
QuestionId (int)  
GenreId (int)  
QuestionScore (int)

I want to select random N rows from this table so that maximum number of same GenreId in the result set is less than X for all GenreId-s except one. For that one GenreId, I need row count with that GenreId to be equal to Y.

UPDATE

I made up this query from suggestions below, it works exactly as i wanted (except for one genre, but thats no problem, let it be this way, ill have 2 queries)

select top @N * from
(select Id,GenreId,Rank() over (Partition BY GenreId order by newId()) as Rank,QuestionScore from Questions) t
where t.Rank <= @X
order by newId()

now i need to select rows so that average QuestionScore is between 1.7 AND 2.3

how can i do that? i need all columns returned in result set.

thanks in advanc开发者_运维百科e :)


For SQL Server 2005+, use:

SELECT TOP (@n) c.*
  FROM (
SELECT a.id,
       a.questionid,
       a.genreid
  FROM (SELECT t.*,
               ROW_NUMBER() OVER (PARTITION BY t.genreid) AS rank
          FROM TABLE t
         WHERE t.genreid NOT IN (SELECT TOP 1 --ensure only one genre, see order by
                                        t.genreid
                                   FROM TABLE t
                               GROUP BY t.genreid
                                 HAVING COUNT(*) = @y 
                               ORDER BY t.genreid) 
      ) a
 WHERE a.rank < @x
UNION ALL
SELECT b.id,
       b.questionid,
       b.genreid
  FROM TABLE b
 WHERE b.genreid IN (SELECT TOP 1 --ensure only one genre, see order by
                            t.genreid
                       FROM TABLE t
                   GROUP BY t.genreid
                     HAVING COUNT(*) = @y
                   ORDER BY t.genreid ) ) c


In SQL Server, you can do that with nested subqueries and top clauses:

select  top (@n) * 
from    (
        -- Retrieve @y rows from the special genre
        -- The prio field is used to ensure all these rows make it inside @n
        select  top (@y) 1 as prio, genreid, questionid
        from    @t
        where   genreid = @the_one

        -- And up to @x rows per non-special genre
        union all
        select  2 as prio, genreid, questionid
        from    (
                select  *
                ,       row_number() over (partition by genreid 
                                           order by newid()) as rownr
                from    @t
                where   genreid <> @the_one
                ) sub
        where rownr < @x
        ) sub2
order by
        prio, newid()

Sample data:

declare @t table (id int identity, QuestionId int, GenreId int)

insert @t (GenreId, QuestionId) values 
    (1,1),
    (2,1),(2,1),
    (3,1),(3,1),(3,1),
    (4,1),(4,1),(4,1),(4,1),
    (5,1),(5,1),(5,1),(5,1),(5,1)

declare @n int
declare @x int
declare @y int
declare @the_one int

set @n = 7 -- Total rows
set @x = 3 -- With less then 3 per genre
set @y = 3 -- Except three rows from genre @the_one
set @the_one = 3

Results in (one example, output differs on each run:

prio  genreid  questionid
1     3        1
1     3        3
1     3        2
2     4        1
2     1        1
2     5        1
2     5        4
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜