PostgreSQL 9.4 - 选择JSONB字段的动态子集

时间:2015-11-23 00:10:32

标签: postgresql-9.4

假设我有一些带有一些JSONB列的表。 JSON相当庞大,在大多数情况下,我只需要按字段名称检索其内容的5%(只是为了提高性能)。所需字段的集合因具体情况而异,但它仍然占整个JSON数据的5%左右。

我知道如何为硬编码字段执行此操作。问题是 - 是否可以为外部提供的字段组成。这需要作为存储函数实现。

以下是带有'硬编码字段组的示例':

CREATE TABLE test_data (
  json_data jsonb NOT NULL
);

INSERT INTO test_data(json_data)
VALUES ('{"row_id": 1, "f1": 1, "f2": 2, "f3": 3, "f4": 4}'),
       ('{"row_id": 2, "f1": 1, "f2": 2, "f3": 3, "f4": 4}');


CREATE OR REPLACE FUNCTION get_important_data(IN data_set varchar = 'row_id,f1,f2')
  RETURNS table (data json)
  LANGUAGE plpgsql AS $$
BEGIN
  RETURN QUERY 
  SELECT (SELECT row_to_json(data_row) FROM (
        -- this needs to be dynamic
        select json_data->>'row_id' as "row_id",
               json_data->>'f1' as "f1",
               json_data->>'f2' as "f2"
      ) data_row ) as data
  FROM test_data;
END $$;

SELECT get_important_data(/* use default data set*/);
SELECT get_important_data('row_id,f2,f4');

1 个答案:

答案 0 :(得分:0)

虽然我认为(虽然我不确定)你可以在没有任何动态SQL和一些繁琐的连接和类似枢轴的查询的情况下离开,我认为这里最直接且可能正在执行的方式是一个小动态查询你的功能。

这将是我对您的解决方案的快速看法。请注意显式转换为text,以重新创建->>运算符的效果:

CREATE OR REPLACE FUNCTION get_important_data(data_set text DEFAULT 'row_id,f1,f2') RETURNS TABLE (
    data    json
) AS $$
BEGIN
    RETURN QUERY EXECUTE format('SELECT row_to_json(j.*) FROM test_data, LATERAL jsonb_to_record(json_data) AS j(%s);', 
        (SELECT array_to_string(array_agg(trim(field)), ' text, ') || ' text'
            FROM unnest(string_to_array(data_set, ',')) AS field)
    );
END;
$$ LANGUAGE plpgsql;

但在我看来,由于您最终还是以json格式归档json归档的子集,因此您最好不要接触它。我更喜欢以下版本,它也应该运行得更快:

CREATE OR REPLACE FUNCTION get_important_data(data_set text DEFAULT 'row_id,f1,f2') RETURNS TABLE (
    data    json
) AS $$
DECLARE
    rec_fields  record;
    arr_fields  text[];
BEGIN
    FOR rec_fields IN 
        SELECT trim(unnest(string_to_array(data_set, ','))) AS field 
    LOOP
        arr_fields :=  arr_fields || format('json_data->%1$L AS %1$I', rec_fields.field);
    END LOOP;
    RETURN QUERY EXECUTE format('SELECT row_to_json(r) FROM (SELECT %s FROM test_data) AS r', array_to_string(arr_fields, ','));
END;
$$ LANGUAGE plpgsql;

最后的触摸是放弃text输入参数,而不是json一个'["row_id", "f1", "f2"]',但我会离开对你而言。