2011-01-27 7 views
3

다음과 같은 두 개의 테이블이 있습니다.테이블에서 고유 한 행 쌍을 임의로 선택하려면 어떻게합니까?

CREATE TABLE people (
    id INT NOT NULL, 
    PRIMARY KEY (id) 
) 

CREATE TABLE pairs (
    person_a_id INT, 
    person_b_id INT, 
    FOREIGN KEY (person_a_id) REFERENCES people(id), 
    FOREIGN KEY (person_b_id) REFERENCES people(id) 
) 

사람들 테이블에서 사람 쌍을 무작위로 선택하고 해당 테이블을 선택한 후 무작위로 선택 쌍을 쌍 테이블에 추가합니다. person_a_id는 쌍의 하위 ID를 가진 사람을 항상 참조합니다 (쌍의 순서는 관련이 없으므로).

문제는 내가 같은 쌍을 두 번 선택하고 싶지 않기 때문에 무작위로 선택한 쌍을 반환하기 전에 쌍 테이블을 검사해야합니다.

합리적이고 효율적으로 단일 SQL 쿼리를 사용하여이 작업을 수행 할 수 있습니까?

(Java Persistence API를 사용하여이 작업을 수행하고 있지만 잘하면 응답을 JPA 코드로 변환 할 수 있음)

+0

그것은 가능할 수도 있지만 예쁘지 않을 것입니다. – Matchu

+0

세트 기반 접근 방식에서 이것이 어떻게 가능할 지 모르겠습니다. 커서를 사용하여이를 해결할 수 있습니다 (그래서 단일 저장 프로 시저에서 수행 할 수 있습니다). 가장 큰 장애물은 쌍 테이블에 추가하는 임의의 쌍마다 선택 풀이 줄여야한다는 것입니다. – Matthew

+0

MySQL의 체크 제약에 대한 지원이 부족한 부분입니다.이것은 person_a_id Thomas

답변

4
select a.id, b.id 
from people1 a 
inner join people1 b on a.id < b.id 
where not exists (
    select * 
    from pairs1 c 
    where c.person_a_id = a.id 
     and c.person_b_id = b.id) 
order by a.id * rand() 
limit 1; 

Limit 1 반환 한 쌍의 당신은 "추첨"한 번에 하나의 경우. 그렇지 않으면 필요한 쌍의 수를 제한하십시오.

위의 쿼리

는 당신이 얻을 수 있다고 가정
1 - 2 
2 - 7 

과가 존재하지 않기 때문에 페어링 2 - 7 2 다시 기능을 갖춘 경우에도 유효하다

. 당신은 단지 multiple pairs 대상 테이블은 여전히 ​​비어, 하나 개의 쿼리에서 생성 될 경우 사람이 다음

select a.id, b.id 
from people1 a 
inner join people1 b on a.id < b.id 
where not exists (
    select * 
    from pairs1 c 
    where c.person_a_id in (a.id, b.id)) 
    and not exists (
    select * 
    from pairs1 c 
    where c.person_b_id in (a.id, b.id)) 
order by a.id * rand() 
limit 1; 

only one의 쌍을, 기능하려면이 단일 쿼리를 사용할 수 있습니다. LIMIT 6은 3 쌍만 반환합니다.

select min(a) a, min(b) b 
from 
(
    select 
     case when mod(@p,2) = 1 then id end a, 
     case when mod(@p,2) = 0 then id end b, 
     @p:[email protected]+1 grp 
    from (
     select id 
     from (select @p:=1) p, people1 
     order by rand() 
     limit 6 
    ) x 
) y 
group by floor(grp/2) 
+0

이것은 모든 조합의 무작위 순열 목록을 반환합니다. 그것은 여전히 ​​반복 될 필요가 있습니다. 'LIMIT 1 '이외의 다른 것을 사용하는 것은 안전하지 않습니다. 왜냐하면 같은 사람을 한 번에 두 번 페어링 할 수 있기 때문입니다. 편집 : 귀하의 편집이 주소. – Matthew

+0

'SELECT' 앞에'INSERT INTO tbl'을 추가 하시겠습니까? 반복 할 필요가있는 것은 무엇입니까? 그것은 동일 쌍입니까 또는 동일인입니까? 만약 같은 쿼리에서 1-2와 2-7이 유효하면 명확하지 않다. – RichardTheKiwi

+0

@cyberwiki 아마도 모호한 질문 ... 만약 그가 (모든 가능한 쌍과 반대되는) 랜덤 한 쌍을 생성하고 싶다면' 쌍 '은 처음으로 들여다 보면 비게됩니다. – Matthew

1

하는 방식 때문에 기반 설정하십시오 set은 쌍이 쌍 테이블에 삽입 된 것을 알 수 없습니다. 타의 추종을 불허하는 사람들이있는 동안

대신 루프

WHILE EXISTS(SELECT * FROM people 
    WHERE id NOT IN (SELECT person_a_id FROM pairs) 
    AND id NOT IN (SELECT person_b_id FROM pairs) 

이 의지 루프를해야한다. 그러면 1에서 2 개의 난수를 의 테이블 으로 가져야합니다. 동일한 숫자를 두 번 얻으면 다시 굴러갑니다. (당신이 걱정한다면, 세트의 두 반쪽에서 숫자를 무작위로 추출하십시오. 그러나 정렬 기준에 따라 임의성을 잃을 것입니다.)

그 쌍을 쌍으로 만듭니다.

워시, 린스, 반복 .... 동일한 임의 번호를 두 번 생성하면 유일한 "재실행"이됩니다 ... 사람들이 거의 없지만 25 %의 확률로 보다 나은 1/N^2)

관련 문제