SELECT users.*,(SELECT COUNT(user_id) AS mutual_connection FROM
(SELECT user_id
FROM (
SELECT sender_id AS user_id
FROM `connections`
WHERE receiver_id=users.id AND status='2'
UNION
SELECT receiver_id AS user_id
FROM `connections`
WHERE sender_id=users.id AND status='2'
) tempUser
WHERE user_id IN (
SELECT sender_id AS user_id
FROM `connections`
WHERE receiver_id='4' AND status='2'
UNION
SELECT receiver_id AS user_id
FROM `connections` WHERE sender_id='4' AND status='2')
GROUP BY user_id)
as mutualConnection)
FROM users
エラー:
#1054-「where句」の不明な列「users.id」
値をサブクエリに使用する方法
MySQLは、1レベルのネストよりも深い外部レベルの列を参照することを禁止しています。ただし、クエリはusers.id
を3レベル深く参照しています。
したがって、ネストされたクエリを使用しても、外部レベルとの相関がネストされないように、相関サブクエリを次のように書き直す必要があります。
(
SELECT
COUNT(*)
FROM
(
SELECT ...
) AS mutualConnection
WHERE
... = users.id
)
サブクエリがメインクエリと相関しているように見えるため、タスクは非常に困難です。私がそれを正しく理解すると、ロジックは次のようになります。
すべてのユーザーについて、特定の他のユーザー(この場合はユーザー
ID='4'
)にも接続している個別の接続(ユーザー)の数を見つけます。
したがって、2つのconnections
列sender_id
とreceiver_id
のどちらかから収集された列を取得しています。これは、もう一方はusers.id
に一致します。取得後、取得したsender_id
またはreceiver_id
がユーザー4の接続の中にあることを確認しています。最後に、すべてのdistinct結果の列の出現(これは繰り返しますが、sender_id
とreceiver_id
の混合です)。
これは、多くのネストレベルを使用せずにすべての相関を同じレベルに維持することなく、これを行う方法です。
SELECT
u.*,
(
SELECT
COUNT(DISTINCT CASE u.id WHEN c.sender_id THEN c.receiver_id ELSE c.sender_id END)
FROM
connections AS c
WHERE
c.status = '2'
AND u.id IN (c.sender_id, c.receiver_id)
AND (CASE u.id WHEN c.sender_id THEN c.receiver_id ELSE c.sender_id END)
IN (
SELECT sender_id AS user_id
FROM connections
WHERE receiver_id = '4' AND status = '2'
UNION
SELECT receiver_id AS user_id
FROM connections
WHERE sender_id = '4' AND status= '2'
)
) AS mutual_connection_count
FROM
users AS u
;
CASE式は、クエリのtempUser
派生テーブルのuser_id
列です。 COUNT関数およびWHERE句(IN述語)で使用されます。通常、このようなコードの繰り返しは、入れ子にすることで解消されます。ただし、この投稿の冒頭で述べたMySQLの制限のため、ここではネストを使用できません。したがって、コードの繰り返しは、コードを回避するために支払わなければならない代償です。幸いなことに、この特定のケースではそれほど多くありません。
WHERE user_id = users.id
句を最初の相関サブクエリに追加します。
create table connections(user_id int, sender_id int, receiver_id int, status int);
create table users(id int);
SELECT users.*, (SELECT sender_id FROM connections WHERE receiver_id = users.id ) 1_level FROM users;
id | 1_level -:| ------:
SELECT users.*, (SELECT sender_id FROM (SELECT receiver_id as sender_id FROM connections WHERE sender_id = users.id ) 2_level ) 1_level FROM users;
「where句」の不明な列「users.id」
SELECT users.*, (SELECT COUNT(user_id) AS mutual_connection FROM (SELECT user_id FROM (SELECT sender_id AS user_id FROM connections WHERE status = '2' UNION SELECT receiver_id AS user_id FROM connections WHERE status = '2' ) tempUser WHERE user_id IN (SELECT sender_id AS user_id FROM connections WHERE receiver_id = '4' AND status = '2' UNION SELECT receiver_id AS user_id FROM connections WHERE sender_id = '4' AND status= '2') GROUP BY user_id) as mutualConnection WHERE user_id = users.id #<<<-------------- Here ) uid FROM users
id | uid -:| -:
dbfiddle ここ