37

次の表とその関係があります。client_services テーブルに JSON データを保存しています。次のような MySQL クエリを使用して JSON 値を取得する方法はありますか。

SELECT getJson("quota") as quota,
       client_id
FROM client_services
WHERE service_id = 1;     

または、 client_services テーブルをさらに正規化できますか?

Services:

+----+-----------------------+--------------------------------------------------------+
| id | name                  | description                                            |
+----+-----------------------+--------------------------------------------------------+
|  1 | MailBox               |                                                        |
|  2 | SMS                   |                                                        |
|  3 | FTP                   |                                                        |
+----+-----------------------+--------------------------------------------------------+

service_features:

+----+------------+----------------------------------+------------------------+
| id | service_id | name                             | description            |
+----+------------+----------------------------------+------------------------+
| 10 |          1 | Forwarding                       | Forward Mail           |
| 11 |          1 | Archive                          | Archive Mail           |
| 12 |          1 | WebMail                          | NULL                   |
| 13 |          1 | IMAP                             | NULL                   |
| 14 |          2 | Web SMS                          | NULL                   |
+----+------------+----------------------------------+------------------------+

client_services:

+-----+-----------+------------+-------------------------------------------------------------------------------------------+
| id  | client_id | service_id | service_values                                                                            |
+-----+-----------+------------+-------------------------------------------------------------------------------------------+
| 100 |      1000 |          1 |{ "quota": 100000,"free_quota":20000,"total_accounts":200,"data_transfer":1000000}         |
| 101 |      1000 |          2 |{ "quota": 200 }                                                                           |
| 102 |      1000 |          3 |{ "data_transfer":1000000}                                                                 |
| 103 |      1001 |          1 |{ "quota": 1000000,"free_quota":2000,"total_accounts":200,"data_transfer":1000000}         |
| 104 |      1001 |          2 |{ "quota": 500 }                                                                           |
| 105 |      1002 |          2 |{ "quota": 600 }                                                                           |
+-----+-----------+------------+-------------------------------------------------------------------------------------------+

client_feature_mappers:

+-----+-------------------+--------------------+-----------+
| id  | client_service_id | service_feature_id | client_id |
+-----+-------------------+--------------------+-----------+
|10000|                100|                 10 |       1000|
|10001|                100|                 11 |       1000|
|10002|                100|                 12 |       1000|
|10003|                100|                 13 |       1000|
|10004|                101|                 14 |       1000|
|10005|                103|                 10 |       1001|
|10006|                101|                 11 |       1001|
|10007|                101|                 12 |       1001|
|10008|                101|                 13 |       1001|
|10009|                105|                 14 |       1002|
+-----+-------------------+--------------------+-----------+
4

5 に答える 5

67

多くの人が個人的にこの質問をしてきたので、私はこの回答に 2 回目の修正を加えようと思いました。これは、SELECT、移行、およびビューの作成を含む完全な SQL、ライブ SQL フィドル (フィドルの可用性は保証されていません) を含む要点です。

次のようなテーブル (名前: TBL_JSON) があるとします。

 ID   CITY        POPULATION_JSON_DATA
-----------------------------------------------------------------------
 1    LONDON      {"male" : 2000, "female" : 3000, "other" : 600}
 2    NEW YORK    {"male" : 4000, "female" : 5000, "other" : 500}

各 json フィールドを選択するには、次のようにします。

SELECT 
    ID, CITY,
    json_extract(POPULATION_JSON_DATA, '$.male') AS POPL_MALE,
    json_extract(POPULATION_JSON_DATA, '$.female') AS POPL_FEMALE,
    json_extract(POPULATION_JSON_DATA, '$.other') AS POPL_OTHER
FROM TBL_JSON;

その結果:

ID  CITY      POPL_MALE  POPL_FEMALE   POPL_OTHER 
-----------------------------------------------------------------
1   LONDON    2000       3000          600
2   NEW YORK  4000       5000          500

これは、データ サイズと json の複雑さに基づいて実行すると、コストのかかる操作になる可能性があります。に使用することをお勧めします

  1. 分割データベースへのテーブルの移行 ( Gist のAppendix 2-B を参照)
  2. 少なくともビューを作成します (gist の付録 2-C を参照)。

気をつけてください: jsonが二重引用符で始まる場合があります(文字列化):

"{"male" : 2000, "female" : 3000, "other" : 600}"

Ubuntu および Mac OSX Sierra 上の Mysql 5.7 でテスト済み。

于 2016-07-25T00:31:42.340 に答える
4

MySQL 関数 SUBSTRING_INDEX を使用して、JSON 文字列を分解できます。

SELECT 
SUBSTRING_INDEX(
 SUBSTRING_INDEX(
  SUBSTRING_INDEX( service_values, 'quota', -1),
  '": ', -1),
 ' ', 1) AS quota,
client_id
FROM client_services
WHERE service_id=1;
于 2014-02-24T16:13:29.017 に答える
2

まず、上記のモデルは第 1 正規形ではないことに注意してください。つまり、各フィールドに値を 1 つだけ持つ必要があります。ただし、この定義は、アプリケーションのクエリ処理のニーズによって異なります。

したがって、大量の JSON データをフィールドに入れ、それをそのままアプリケーションに返すだけであれば問題ありません。JSON データ全体を返し、アプリケーションに必要な JSON 属性を選択させることができます。

しかし、あなたの場合のように、JSON データの詳細を調べる条件やフィールド式を持つクエリがある場合、それは間違いなく失敗です。クエリが複雑になり、処理が遅くなるのは悪夢です。

もちろん、JSON データ構造を完全に置き換えるために、テーブルをさらに正規化することもできます。ただし、アプリケーションが柔軟なスキーマを必要としており、おそらく NOSQL DB を使用する主な理由であるにもかかわらず、MySQL にこだわっている場合は、次の 2 つの解決策があります。

a) NoSQL サポートに MySQL 5.6 (または MariaDB v. ??) を使用します (詳細は調べていません) http://www.computerworld.com/s/article/9236511/MySQL_5.6_tackles_NoSQL_competitors MariaDB の動的列: https: //kb.askmonty.org/en/dynamic-columns/

b) 明示的なスキーマなしで mysql を使用します。スケーラビリティの問題がない非常によくできたソリューションについては、こちらを参照してください: http://backchannel.org/blog/friendfeed-schemaless-mysql

于 2013-03-30T21:17:04.393 に答える