web-dev-qa-db-ja.com

オブジェクトのネストされた配列を取得するための結合を使用したSQLクエリ

概要:まず、JSONスキーマから期待を説明します。オブジェクトのネストされた配列を持つロールに注意してください。単一のクエリをフェッチできる「スマートクエリ」を探しています。

_{
    "id": 1,
    "first": "John",
    "roles": [ // Expectation -> array of objects
        {
            "id": 1,
            "name": "admin"
        },
        {
            "id": 2,
            "name": "accounts"
        }
    ]
}
_

ユーザー

_+----+-------+
| id | first |
+----+-------+
|  1 | John  |
|  2 | Jane  |
+----+-------+
_

役割

_+----+----------+
| id |   name   |
+----+----------+
|  1 | admin    |
|  2 | accounts |
|  3 | sales    |
+----+----------+
_

user_role

_+---------+---------+
| user_id | role_id |
+---------+---------+
|       1 |       1 |
|       1 |       2 |
|       2 |       2 |
|       2 |       3 |
+---------+---------+
_

試行01

素朴なアプローチでは、接続文字列で_multipleStatements:true_を使用して、nodejsコードで2つのSQLクエリを実行します。 情報

_User.getUser = function(id) {
    const sql = "SELECT id, first FROM user WHERE id = ?; \
        SELECT role_id AS id, role.name from user_role \
        INNER JOIN role ON user_role.role_id = role.id WHERE user_id = ?";

    db.query(sql, [id, id], function(error, result){
        const data = result[0][0]; // first query result
        data.roles = result[1];  // second query result, join in code.
        console.log(data);
    });
};
_

問題:上記のコードは予期されるJSONスキーマを生成しますが、2つのクエリが必要です。複数のコードがあるため、コードの可能な最小単位で絞り込むことができましたステートメントですが、JavaまたはC#などのような他の言語ではそれほど贅沢ではありません。たとえば、C#の場合、2つの関数と2つのSQLクエリを作成する必要があります。そのため、1つのクエリソリューション。


試行02

以前の試みでは、SOコミュニティの助けを借りて、単一のクエリを使用して次のように近づけることができましたが、それは文字列の配列(オブジェクトの配列ではない)を生成するのにのみ役立ちます)。

_User.getUser = function(id) {
    const sql = "SELECT user.id, user.first, GROUP_CONCAT(role.name) AS roles FROM user \
        INNER JOIN user_role ON user.id = user_role.user_id \
        INNER JOIN role ON user_role.role_id = role.id \
        WHERE user.id = ? \
        GROUP BY user.id";
    db.query(sql, id, function (error, result) {
        const data = {
            id: result[0].id, first: result[0].first,
            roles: result[0].roles.split(",") // manual split to create array
        };
        console.log(data);
    });
};
_

試行02結果

_{
    "id": 1,
    "first": "John",
    "roles": [ // array of string
        "admin",
        "accounts"
    ]
}
_

オブジェクトの配列を生成することは非常に一般的な要件なので、SQLには気付かない何かがあるのではないかと思います。最適なクエリの助けを借りてこれをよりよく達成する方法はありますか?.

または、そのような解決策はないことを私に知らせてください、これはそれであり、これが2つのクエリを使用して実稼働コードで行われる方法です。


Attempt 03

GROUP_CONCAT(role.id)で_role.id_の代わりに_role.name_を使用すると、いくつかのIDを取得し、別のサブクエリを使用して関連するロール名を取得できます。

SQL(動作しませんが、何かを考えて何かを捨てるだけです)

_SELECT 
  user.id,  user.first,  
  GROUP_CONCAT(role.id) AS role_ids, 
  (SELECT id, name FROM role WHERE id IN role_ids) AS roles
FROM user 
INNER JOIN user_role ON user.id = user_role.user_id 
INNER JOIN role ON user_role.role_id = role.id 
WHERE user.id = 1
GROUP BY user.id;
_

編集

アミットの回答に基づいて、SQL Serverには_JSON AUTO_を使用した solution があることがわかりました。はい、これはMySQLで探しているものです。

正確に表現する。

テーブルを結合すると、最初のテーブルの列がルートオブジェクトのプロパティとして生成されます。 2番目のテーブルの列は、ネストされたオブジェクトのプロパティとして生成されます。

5
AppDeveloper

ここでは、mysqlに実装されている同様の問題の解決策を見つけることができます。

MySqlを使用したネストされたJSONオブジェクト

ここから始めて、最初にコンセプトに慣れることができます。

MySqlで結果テーブルをJSON配列に変換

0
Mostafa Medhat