【问题标题】:Filter Query to List Resources based on Tags Field Conditions. Filter Query for Many-to-Many SQL Relation Tables根据标签字段条件过滤查询以列出资源。多对多 SQL 关系表的过滤查询
【发布时间】:2020-09-03 18:22:19
【问题描述】:

编写查询以根据多个标签字段条件过滤资源列表,例如:WHERE tag_name != fabric or tag_name = user

基本上,我有分配了多个标签{名称:值}的资源列表。需要一种方法来查询基于标签字段 {name & value} 的资源过滤列表,并具有各种操作,如相等和不相等的值。

三个表:

  1. 资源表:Res_ID、Res_Name
  2. 标签表:Tag_ID、Tag_Name、Tag_Value
  3. Ref_Res_Tag:Res_ID、Tag_ID

我提出的问题:

查询 1:

SELECT "sample_t"."name", "tag_t"."tag_name" from "sample" as sample_t
LEFT JOIN "ref_sample_tag" as ref_sample_tag_t on "ref_sample_tag_t"."from" = "sample_t"."uuid"
LEFT JOIN "tag" as tag_t on "tag_t"."uuid" = "ref_sample_tag_t"."to"
WHERE ("tag_t"."tag_name" != 'fabric');

Q1 的问题:此查询为上述查询返回 Sample1、Sample2。 期望:{Empty}:结果应该是空的,因为所有资源都被标记为结构。

查询 2:

SELECT "sample_t"."name" FROM "sample" as sample_t
WHERE sample_t.uuid NOT IN
         (SELECT ref_sample_tag.FROM from ref_sample_tag
          LEFT JOIN tag AS tag_t ON ref_sample_tag.to = tag_t.uuid WHERE tag_t.tag_name = 'fabric')

结果:{}:没有资源全部标记为结构。预期结果。

问题:如何使用多个不同的标签字段条件,如((tag_name != 'fabric') or (tag_name = 'user'))

如果需要更多详细信息,请告诉我。

【问题讨论】:

  • Postgresql 和 mysql 是两种不同的数据库产品,具有不同的 sql 实现。删除了冲突的产品标签。请添加您使用的那个。
  • 我同时使用两种 SQL 变体。 MySQL 和 Postgres。这两种变体解决方案中的任何一种都适合我。
  • 示例数据最好显示为formatted text,以便在测试答案时可以复制使用。请参阅here,了解有关如何创建漂亮表格的一些提示。
  • 谢谢@a_horse_with_no_name。那是错字,我已经更新了用户。在查询 2:WHERE tag_name != fabric 或 tag_name = abc 中,这不起作用。预期结果:{} - 空列表,因为所有资源都标记为 fabric。

标签: sql postgresql


【解决方案1】:

根据提供的额外数据,我认为这应该可行

SELECT * FROM "sample" as sample_result 
WHERE NOT EXISTS
(

SELECT 1
    from "sample" as sample_t 
    INNER JOIN "ref_sample_tag" as ref_sample_tag_t 
          on "ref_sample_tag_t"."from" = "sample_t"."uuid" 
    INNER JOIN "tag" as tag_t 
           on "tag_t"."uuid" = "ref_sample_tag_t"."to" 
    WHERE ("tag_t"."tag_name" = 'name')
    AND  "sample_t"."uuid" ="sample_result"."uuid"
) 
AND EXISTS
(

SELECT 1
    from "sample" as sample_t 
    INNER JOIN "ref_sample_tag" as ref_sample_tag_t 
          on "ref_sample_tag_t"."from" = "sample_t"."uuid" 
    INNER JOIN "tag" as tag_t 
           on "tag_t"."uuid" = "ref_sample_tag_t"."to" 
    WHERE ("tag_t"."tag_name" = 'fabric')
    AND  "sample_t"."uuid" ="sample_result"."uuid"
) 

;

【讨论】:

  • @NikunjGupta 查看更新后的答案。这有两个 EXISTS 检查,检查标签的缺失和存在
  • 感谢@DhruvJoshi,您的回答。是的,它正在工作,但在性能方面,它似乎需要太多时间来处理大量记录。
【解决方案2】:

我认为在 Postgres 中更容易将标签聚合到一个数组中,然后在数组上应用条件:

所以查询 1 将是:

select *
from (
  select r.res_id, r.res_name,  
         array_agg(distinct t.tag_name) as tags
  from resource r
    join ref_res_tag rrt on rrt.res_id = r.res_id
    join tag t on t.tag_id = rrt.tag_id
  group by r.res_id, r.res_name
) t  
where 'fabric' <> all(tags)

对于查询 2,您只需添加:

   or 'user' = any(tags);

如果您需要查询标签名称标签值,可以将标签聚合成JSON数组,然后使用JSON运算符,例如查找所有具有“fabric: one”的资源:

select *
from (
  select r.res_id, r.res_name,  
         jsonb_agg(jsonb_build_object(t.tag_name, t.tag_value)) as tags
  from resource r
    join ref_res_tag rrt on rrt.res_id = r.res_id
    join tag t on t.tag_id = rrt.tag_id
  group by r.res_id, r.res_name
) t  
where tags @> '[{"fabric": "one"}]';

这也将返回具有例如的资源织物二也是。

要获得那些具有结构一的,您需要在聚合期间进行过滤并在最后的 WHERE 子句中使用相等性:

select *
from (
  select r.res_id, r.res_name,  
         jsonb_agg(jsonb_build_object(t.tag_name, t.tag_value)) as tags
  from resource r
    join ref_res_tag rrt on rrt.res_id = r.res_id
    join tag t on t.tag_id = rrt.tag_id
  where t.tag_name = 'fabric'
  group by r.res_id, r.res_name
) t  
where tags = '[{"fabric": "one"}]';

【讨论】:

  • 感谢您的回答。我不明白你上面所说的 - 对于查询 2' 或 'user = any(tags);'' ?在您的最后一个查询中,如果 where 子句是 'fabric:one' ,则面料二不应该出现。
  • 对于第二个查询,只需将条件or 'user' = any(tags) 添加到 WHERE 子句中即可。
  • @NikunjGupta "fabric two should not come" - 这是否意味着可以为资源分配具有不同值的相同标签?
  • T1: {name: fabric, value:one} 和 T2: {name: fabric, value: two} :这两个是不同的标签。是的,任何标签都可以分配给资源。假设 T1 和 T2 都可以分配给资源。这与标记具有 {key:value} 对的任何资源的标记相同
  • 非常感谢您的努力。单个查询应该适用于多个不同的标签组合。 1. 条件:where (tag_name = "fabric" and tag_value = "one") 预期结果:{Sample1} 2. 条件:where (tag_name = "fabric") 预期结果:{Sample1, Sample2, Sample3} 3. 条件: where (tag_name != "fabric") 预期结果:{} 4. 条件:where ((tag_name = fabric) or (tag_name != user)) 预期结果:{Sample3}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-24
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 2018-01-05
  • 2020-04-16
  • 1970-01-01
相关资源
最近更新 更多