2011-01-27 2 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を持つ人物を参照します(ペアの順序は関係ないため)。

私は決して同じペアを2回選択したくないので、ランダムに選択したペアを返す前に、ペアテーブルをチェックする必要があります。

これは、合理的に効率的でエレガントな方法で単一の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組あなたは、一度に1つの「くじ引き」している場合。さもなければ、あなたが必要とする多くのペアに限ります。

上記のクエリは、

1 - 2 
2 - 7 

を取得し、それが存在しないため、ペアリング2 - 7は2を再度紹介されていても、有効であることができることを前提としています。あなただけの人がこれまでonly oneペアで特色にしたい場合はmultiple pairsは、1つのクエリで生成される場合、その後、

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; 

先テーブルはまだ空である、あなたは、この単一のクエリを使用することができます。 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 '以外のものを使用することは安全ではありません。なぜなら、同じ人を1回の繰り返しで2回ペアリングすることができるからです。編集:あなたの編集はこれに対処します。 – 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つの乱数をテーブル のCNT(*)に渡すと、それはあなたに比類のない人数を与えます。同じ数字を2回取得すると、再びロールバックします。 (あなたがこれを心配している場合は、セットの2つの半分から数値をランダム化しますが、ソート基準に基づいてランダム性を失います)

これらのペアをペアにします。

ウォッシュ、すすぎ、繰り返し.... 同じ乱数を2回生成するとあなたの唯一の「やり直し」となります...少数しか得ることはできませんが、たいていは25% 1/N^2)

関連する問題