如何从 PostgreSQL 查询中删除重复的冗余数据

How to remove repeating redundant data from PostgreSQL queries

我试图让下面的查询片段包含更少的重复数据并且看起来更优雅。能请教一下吗?

SELECT 
 (select gender from jsonb_to_recordset(audience) as x(gender text[]) where x.gender is not null) as gender,
 (select age from jsonb_to_recordset(audience) as x(age text[]) where x.age is not null) as age,
 (select ethnicity from jsonb_to_recordset(audience) as x(ethnicity text[]) where x.ethnicity is not null) as ethnicity,
 (select continent from jsonb_to_recordset(params) as x(continent text[]) where x.continent is not null) as continent,
 (select country from jsonb_to_recordset(params) as x(country text[]) where x.country is not null) as country,
 (select city from jsonb_to_recordset(params) as x(city text[]) where x.city is not null) as city
FROM user_data

是否可以使用数组或 CTE 返回 ['gender'、'age'、'ethnicity'、'continent'、'country'、'city'] 并模拟一些循环以避免重复上述 6 次选择?

SELECT jsonb_build_array(
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.gender) INTERSECT SELECT UNNEST(dpu2.gender)), COALESCE(dpu1.gender, ARRAY[]::text[]), COALESCE(dpu2.gender, ARRAY[]::text[])),
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.age) INTERSECT SELECT UNNEST(dpu2.age)), COALESCE(dpu1.age, ARRAY[]::text[]), COALESCE(dpu2.age, ARRAY[]::text[])),
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.ethnicity) INTERSECT SELECT UNNEST(dpu2.ethnicity)), COALESCE(dpu1.ethnicity, ARRAY[]::text[]), COALESCE(dpu2.ethnicity, ARRAY[]::text[])),
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.continent) INTERSECT SELECT UNNEST(dpu2.continent)), COALESCE(dpu1.continent, ARRAY[]::text[]), COALESCE(dpu2.continent, ARRAY[]::text[])),
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.country) INTERSECT SELECT UNNEST(dpu2.country)), COALESCE(dpu1.country, ARRAY[]::text[]), COALESCE(dpu2.country, ARRAY[]::text[])),
    jsonb_build_array(ARRAY(SELECT UNNEST(dpu1.city) INTERSECT SELECT UNNEST(dpu2.city)), COALESCE(dpu1.city, ARRAY[]::text[]), COALESCE(dpu2.city, ARRAY[]::text[]))
) as values
FROM data_per_user dpu1 CROSS JOIN data_per_user dpu2
WHERE dpu1.user_uuid <> dpu2.user_uuid

这是同一个故事 - 我找到了相交的数组元素,并且必须重复相同的转换 6 次。有没有更优雅的方法?

SELECT
jsonb_build_array(
    ARRAY[jsonb_array_length(values->0->0), jsonb_array_length(values->0->1), jsonb_array_length(values->0->2)],
    ARRAY[jsonb_array_length(values->1->0), jsonb_array_length(values->1->1), jsonb_array_length(values->1->2)],
    ARRAY[jsonb_array_length(values->2->0), jsonb_array_length(values->2->1), jsonb_array_length(values->2->2)],
    ARRAY[jsonb_array_length(values->3->0), jsonb_array_length(values->3->1), jsonb_array_length(values->3->2)],
    ARRAY[jsonb_array_length(values->4->0), jsonb_array_length(values->4->1), jsonb_array_length(values->4->2)],
    ARRAY[jsonb_array_length(values->5->0), jsonb_array_length(values->5->1), jsonb_array_length(values->5->2)]
) as scores
FROM matched_users

我在这里尝试计算二维数组中数组元素的数量 - 同样的故事。看起来冗余重复数据太多了。 请告知优化这些查询的任何方法。

我不要求确切的解决方案,我将不胜感激。

对于您的第一个查询,如果您的列 audienceparams 是类型 jsonb,那么您可以直接使用 json functions to extract some data. In particular you can read carefully the jsonpath chapters in the manual 8.14.7. jsonpath Type and 9.16.2. The SQL/JSON Path Language.

这是您查询的等效 json 版本:

SELECT 
  jsonb_path_query(audience, '$[*] ? (@.gender <> null)')->>'gender' :: text[] AS gender
, jsonb_path_query(audience, '$[*] ? (@.age <> null)')->>'age' :: text[] AS age
, jsonb_path_query(audience, '$[*] ? (@.ethnicity <> null)')->>'ethnicity' :: text[] AS ethnicity
, jsonb_path_query(params, '$[*] ? (@.continent <> null)')->>'continent' :: text[] AS continent
, jsonb_path_query(params, '$[*] ? (@.country <> null)')->>'country' :: text[] AS country
, jsonb_path_query(params, '$[*] ? (@.city <> null)')->>'city' :: text[] AS city
FROM user_data

并且应该简化如下,因为当 json 列中对应的 json 值为 null 时,结果数据将自动设置为 NULL audienceparams :

SELECT 
  aud->>'gender' :: text[] AS gender
, aud->>'age' :: text[] AS age
, aud->>'ethnicity' :: text[] AS ethnicity
, par->>'continent' :: text[] AS continent
, par->>'country' :: text[] AS country
, par->>'city' :: text[] AS city
FROM user_data
CROSS JOIN LATERAL jsonb_path_query(audience, '$[*]) AS aud
CROSS JOIN LATERAL jsonb_path_query(params, '$[*]) AS par

您的第三个查询

SELECT
jsonb_build_array(
    ARRAY[jsonb_array_length(values->0->0), jsonb_array_length(values->0->1), jsonb_array_length(values->0->2)],
    ARRAY[jsonb_array_length(values->1->0), jsonb_array_length(values->1->1), jsonb_array_length(values->1->2)],
    ARRAY[jsonb_array_length(values->2->0), jsonb_array_length(values->2->1), jsonb_array_length(values->2->2)],
    ARRAY[jsonb_array_length(values->3->0), jsonb_array_length(values->3->1), jsonb_array_length(values->3->2)],
    ARRAY[jsonb_array_length(values->4->0), jsonb_array_length(values->4->1), jsonb_array_length(values->4->2)],
    ARRAY[jsonb_array_length(values->5->0), jsonb_array_length(values->5->1), jsonb_array_length(values->5->2)]
) as scores
FROM matched_users

可以替换为

SELECT jsonb_array_agg(c.arr ORDER BY c.a) AS scores
FROM 
   (SELECT a, jsonb_array_agg(jsonb_array_length(values#>array[a :: text, b :: text]) AS arr
      FROM matched_users
     CROSS JOIN generate_series(0,5) AS a
     CROSS JOIN generate_series(0,2) AS b
     GROUP BY a
     ORDER BY b
   ) AS c