ユーザーとそれぞれのドメインを IP アドレスに割り当てるクエリを作成しています。重複するユーザーを持つ IP アドレスはありません。
SQL Fiddle でこれまでに得たものは次のとおりです。http://sqlfiddle.com/#!2/39c51/2/0
現在のすべての割り当て (数十万) を含むテーブルがあります。小規模な例は次のようになります。
mysql> select * from test.usermap;
+-------------+-------+-------------------+
| vip | user | domain |
+-------------+-------+-------------------+
| 100.50.20.1 | joe | joesdomain.com |
| 100.50.20.1 | bob | joesdomain.com |
| 100.50.20.2 | tom | domain2.com |
| 100.50.20.2 | fred | domain2.com |
| 100.50.20.2 | sally | domain2.com |
| 100.50.20.3 | admin | athriddomain.com |
| 100.50.20.4 | admin | numberfour.com |
| 100.50.20.3 | sally | fivewithsally.com |
| 100.50.20.4 | jim | thesix.com |
| 100.50.20.1 | admin | seven.com |
| 100.50.20.1 | sally | seven.com |
| 100.50.20.1 | sue | seven.com |
| 100.50.20.5 | | |
| 100.50.20.6 | | |
+-------------+-------+-------------------+
14 rows in set (0.00 sec)
まだ割り当てられていないユーザーを含む別のテーブルがあります。これも小規模な例です。
mysql> select * from test.newusers;
+-------+-----------+
| user | domain |
+-------+-----------+
| jim | eight.com |
| sally | eight.com |
| admin | nine.com |
| james | ten.com |
| jane | ten.com |
+-------+-----------+
5 rows in set (0.00 sec)
ここでの考え方は、「jim」も「sally」も持たない最も古い IP であるため、eight.com の下のすべてのユーザーを .5 に割り当て、次に、nine.com を .2 に、ten.com を .1 に割り当てることです。それぞれのユーザーの競合 (またはその欠如)。
私が探している結果は次のようになります。
+-------------+-------+-----------+
| vip | user | domain |
+-------------+-------+-----------+
| 100.50.20.1 | james | ten.com |
| 100.50.20.1 | jane | ten.com |
| 100.50.20.2 | admin | nine.com |
| 100.50.20.5 | jim | eight.com |
| 100.50.20.5 | sally | eight.com |
+-------------+-------+-----------+
5 rows in set (0.01 sec)
次のように、相関サブクエリ内のサブクエリでこれを行うことができます。
mysql> select
(
select vip
from test.usermap
where vip not in
(
select distinct vip
from test.usermap
where user in
(
select user
from test.newusers
where domain = n.domain
)
)
order by inet_aton(vip) asc
limit 1
) as vip, n.user, n.domain
from test.newusers n
order by inet_aton(vip) asc;
+-------------+-------+-----------+
| vip | user | domain |
+-------------+-------+-----------+
| 100.50.20.1 | james | ten.com |
| 100.50.20.1 | jane | ten.com |
| 100.50.20.2 | admin | nine.com |
| 100.50.20.5 | jim | eight.com |
| 100.50.20.5 | sally | eight.com |
+-------------+-------+-----------+
5 rows in set (0.00 sec)
しかし、それは非常に非効率的であり、私のプロダクション マッピングと newusers テーブルはそれぞれ 30 万行と 5 万行なので、これは問題外です。
ネストされたサブクエリの代わりに結合を使用してこれをより効率的にしようとしているので、内側のクエリを結合に置き換え、外側のクエリの列を ON 句にリストしましたが、これは不可能のようです:
mysql> select
(
select distinct vip
from test.usermap u
join test.newusers r
on r.domain = n.domain
and r.user != u.user
order by inet_aton(vip) asc limit 1
) as vip, n.user, n.domain
from test.newusers n;
ERROR 1054 (42S22): Unknown column 'n.domain' in 'on clause'
mysql>
クエリ自体のロジックは理にかなっていますが、外側のクエリ参照をそれが表す文字列定数に置き換えるとうまく機能するためです。
mysql> select
(
select distinct vip
from test.usermap u
join test.newusers r
on r.domain = 'ten.com'
and r.user != u.user
order by inet_aton(vip) asc limit 1
) as vip, n.user, n.domain
from test.newusers n
where domain = 'ten.com';
+-------------+-------+---------+
| vip | user | domain |
+-------------+-------+---------+
| 100.50.20.1 | james | ten.com |
| 100.50.20.1 | jane | ten.com |
+-------------+-------+---------+
2 rows in set (0.00 sec)
私の質問は: 内部クエリの結合内で外部クエリから列を参照する方法はありますか? そうでない場合、非効率的な方法でサブクエリをネストせずに、どのような代替手段が存在しますか?
ここでもフィドルがあります: http://sqlfiddle.com/#!2/39c51/2/0