use tempdb
go
if exists (select * from sysobjects where type = 'U' and name = 'tableA')
drop table tableA
create table tableA(group_id int , [rand] int)
go
insert into tableA values(11, 2)
insert into tableA values(12, 4)
insert into tableA values(13, 1)
go
if exists (select * from sysobjects where type = 'U' and name = 'tableB')
drop table tableB
create table tableB(group_id int , id varchar(10))
go
insert into tableB values(11, '개똥이')
insert into tableB values(11, '말똥이')
insert into tableB values(11, '소똥이')
insert into tableB values(11, '땡칠이')
insert into tableB values(12, '옥동자')
insert into tableB values(12, '아무개')
insert into tableB values(12, '홍길동')
insert into tableB values(12, '고길동')
insert into tableB values(12, '김길동')
insert into tableB values(12, '박길동')
insert into tableB values(13, '개뿔')
insert into tableB values(13, '소뿔')
go
select * from tableA
/*
group_id rand
----------- -----------
11 2
12 4
13 1
*/
select * from tableB
/*
group_id id
----------- ----------
11 개똥이
11 말똥이
11 소똥이
11 땡칠이
12 옥동자
12 아무개
12 홍길동
12 고길동
12 김길동
12 박길동
13 개뿔
13 소뿔
*/
Group_id 가 11인 것은 랜덤으로 2개를 가져오고, Group_id가 12인 것은 랜덤으로 4개를 가져오는 형태이다. 랜덤한 것을 보장하기 위해서 아래와 같은 뷰를 생성하였다.
create view v_tableB
as
select top 100 percent group_id, id
from tableB
order by NewID()
--다소 부하가 있다.
--SQL Server 2005 버전에서는 TableSample 키워드를 사용하면 된다.
그리고 한번에 처리하기 위해서 동적 쿼리를 작성하였다. 실제로 커서를 돌면서 SQL문이 만들어지는 과정이다.
DECLARE
@group_id int
, @rand int
, @count int
, @cursor_count int
, @sql varchar(1000)
SET @cursor_count = 1
BEGIN
DECLARE table_cursor CURSOR FOR
SELECT group_id, rand FROM tableA
SELECT @count = COUNT(*) FROM tableA
OPEN table_cursor
FETCH NEXT FROM table_cursor INTO @group_id, @rand
SET @sql =
'SELECT TOP ' + CAST(@rand AS VARCHAR) +
' group_id, id FROM v_tableB ' +
'WHERE group_id = ' + CAST(@group_id AS VARCHAR) +
' UNION ALL '
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM table_cursor INTO @group_id, @rand
IF(@count <> @cursor_count)
BEGIN
SET @sql = @sql +
'SELECT TOP ' + CAST(@rand AS VARCHAR) +
' group_id, id FROM v_tableB ' +
'WHERE group_id = ' +
CAST(@group_id AS VARCHAR) + ' '
Print @count
Print @cursor_count
END
SET @cursor_count = @cursor_count + 1
IF(@count > @cursor_count)
SET @sql = @sql + 'UNION ALL '
END
CLOSE table_cursor
DEALLOCATE table_cursor
PRINT @sql
EXEC(@sql)
END
/*
group_id id
----------- ----------
11 개똥이
11 말똥이
12 옥동자
12 아무개
12 홍길동
12 고길동
13 개뿔
*/
실제로 @sql을 프린트 해보면 다음과 같이 쿼리문이 동적으로 만들어진 것을 볼 수 있다.
SELECT TOP 2 group_id, id FROM v_tableB WHERE group_id = 11
UNION ALL
SELECT TOP 4 group_id, id FROM v_tableB WHERE group_id = 12
UNION ALL
SELECT TOP 1 group_id, id FROM v_tableB WHERE group_id = 13
실제로 v_tableB라는 뷰를 3번이나 접근한다. 즉, 뷰의 내용대로 tableB는
NewID()로 정렬이 되어 랜덤한 값을 얻기는 하지만 group_id가 많은 값이라면 성능은 점차 나빠질 것이다. 또한 WHERE 조건이 group_id에 의해 결정되므로 실제로는 group_id에 반드시 인덱스가 잡혀 있어야 하겠다.