sql >> データベース >  >> RDS >> PostgreSQL

PostgresのネストされたJSONB列をフラット化する

    私はこれをpsqlで使用するように開発しました 。コードを確認するために、小さなビューt1を作成します :

    CREATE VIEW t1 AS (
           SELECT 1 AS id, '{"brother": {"first_name":"Sam", "last_name":"Smith"}, "sister": {"first_name":"Sally", "last_name":"Smith"}}'::jsonb AS jsonb
     UNION SELECT 2, '{"sister": {"first_name":"Jill", "last_name":"Johnson"}}'
     UNION SELECT 3, '{"sister": {"first_name":"Jill", "x_name":"Johnson"}}'
    );
    

    最初のタスクは、可能なキーのリストを見つけることです:

    WITH fields AS (
         SELECT DISTINCT jff.key
           FROM t1,
                jsonb_each(jsonb) AS jf,
                jsonb_each(jf.value) AS jff
    )
    SELECT * FROM fields;
    

    結果は次のとおりです。

        key     
    ------------
     first_name
     last_name
     x_name
    

    次のステップはクエリの生成です:

    SELECT 'SELECT id, jf.key as sibling, ' || (
        WITH fields AS (
             SELECT DISTINCT jff.key
               FROM t1,
                    jsonb_each(jsonb) AS jf,
                    jsonb_each(jf.value) AS jff
        )
        SELECT string_agg('jf.value->>''' || key || ''' as "' || key || '"', ',' ORDER BY key)
          FROM fields
    )
    || ' FROM t1, jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;' AS cmd;
    

    戻ります:

                                                                                      cmd                                                                                   
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     SELECT id, jf.key as sibling,jf.value->>'first_name' as "first_name",jf.value->>'last_name' as "last_name",jf.value->>'x_name' as "x_name" FROM t1, jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;
    (1 row)
    

    結果をpsql変数として設定するには、gsetを使用します :

    \gset
    

    その後、クエリを呼び出すことができます:

    :cmd
    
     id | sibling | first_name | last_name | x_name  
    ----+---------+------------+-----------+---------
      1 | brother | Sam        | Smith     | 
      1 | sister  | Sally      | Smith     | 
      2 | sister  | Jill       | Johnson   | 
      3 | sister  | Jill       |           | Johnson
    (4 rows)
    

    外部言語から実行するには、SQLコマンドを返すよりもpostgres関数を作成できます:

    CREATE OR REPLACE FUNCTION build_query(IN tname text, OUT cmd text)  AS $sql$
    BEGIN 
        EXECUTE $cmd$
                SELECT 'SELECT id, jf.key as sibling, ' || (
                        WITH fields AS (
                            SELECT DISTINCT jff.key
                              FROM t1,
                                   jsonb_each(jsonb) AS jf,
                                   jsonb_each(jf.value) AS jff
                        )
                        SELECT string_agg('jf.value->>''' || key || ''' as "' || key || '"', ',' ORDER BY key)
                          FROM fields
                    )
            || ' FROM $cmd$ || quote_ident(tname) || $cmd$ , jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;'$cmd$ INTO cmd;
        RETURN;
    END;
    $sql$ LANGUAGE plpgsql;
    
    SELECT * FROM build_query('t1');
                                                                                                   cmd                                                                                               
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     SELECT id, jf.key as sibling, jf.value->>'first_name' as "first_name",jf.value->>'last_name' as "last_name",jf.value->>'x_name' as "x_name" FROM t1 , jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;
    (1 row)
    



    1. CSVからMySQLにデータをインポートするにはどうすればよいですか?

    2. Dockerを使用してTimescaleDBをデプロイするためのガイド

    3. PythonCGIMySQLスクリプトの出力を返す

    4. 添付ファイル付きの電子メールの複数送信-再投稿