使用 Redshift/SQL 中的多值列进行过滤

Filter with multivalue columns in Redshift/SQL

我有一篇 table 的新闻文章。这些新闻文章有许多描述标题、图片等的栏目。一些列可以有多个值,例如类别可以设置为 "sports" 和 "hockey".

假设我有这个 table:

articlekey | category
---------------------
article1   | sports, hockey  

实际table包含很多文章,所有文章只出现一次。我试图实现的是根据类别的两个值过滤此 table。为了能够做到这一点,我将它们分成几行并生成一个 filter-table 像这样:

articlekey | category
---------------------
article1   | sports
article1   | hockey

(顺便说一句,我们将 Tableau 用作 visualization/BI-tool,这就是我过滤的地方)

当我将这些加入 tables 并仅在 "hockey" 上过滤(包括)时,我将得到正确的结果,因为文章 1 只有一行类别设置为 "hockey".

articlekey | category         | category-filter
-----------------------------------------------
article1   | sports, hockey   | sports          <-- this will be excluded
article1   | sports, hockey   | hockey          <-- this is included

但是,如果我尝试排除 "hockey",则文章将显示类别设置为 "sports",因为它会保留在类别 "sports" 的结果中。我希望它完全排除文章的结果。

articlekey | category         | category-filter
-----------------------------------------------
article1   | sports, hockey   | sports          <-- this is included, but should also be gone
article1   | sports, hockey   | hockey          <-- this will be excluded

如果可能的话,当我每列有多个值并且需要过滤(包括和排除)以便每篇文章只剩下一行时,我应该如何处理这样的数据。

我。如果类别的数据结构为 'normalized',即类别字段中没有多个值(如 'filter-table'):

我认为解决此问题的首选方法是用 1 代替 'hockey',用 0 代替其他所有内容,然后按 articlekey 对组中的这些数字求和。总和为 0 的文章关键字是没有 'hockey' 类别的文章。

所以这是对没有 'hockey' 类别的文章的查询:

select articlekey
from articles 
group by articlekey 
having sum(case when category = 'hockey' then 1 else 0 end) = 0;

您可以概括这一点:例如,如果您需要既没有 'hockey' 也没有 'sports' 但同时具有 'soccer' 和 'boxing' 类别的文章:

select articlekey
from articles 
group by articlekey 
having sum(
  case when category = 'hockey' then 1
       when category = 'sports' then 1
       else 0 
  end
) = 0
and sum(
  case when category = 'soccer' then 1
       when category = 'boxing' then 1
       else 0 
  end
) = 2;

不过你也可以 1. 过滤类别(曲棍球) 2. group by on articleKey 3. 计数匹配 4.左加入

所以这是另一个解决方案:

select * from articles left join (
  select articlekey, count(articlekey) as countOfHockey 
  from articles where category = 'hockey' group by articlekey
) hhh on articles.articlekey=hhh.articlekey where countOfHockey is null;

Sql fiddle: http://sqlfiddle.com/#!17/27ae1/33

二.如果您有非规范化的类别字段,即类别列表作为逗号分隔的值列表(如您原来的 table),您可以使用 SQL like %% operator on them and write queries like these:

create table if not exists articles(articlekey varchar, category varchar);
insert into articles values('article1', 'sports, hockey');
insert into articles values('article2', 'sports');
insert into articles values('article3', 'soccer, boxing, sprint');
insert into articles values('article4', 'soccer, sprint');

select * from articles where ', '||category||',' not like '%, hockey,%';

如果您需要既没有 'hockey' 也没有 'sports' 但同时具有 'soccer' 和 'boxing' 类别的文章,您也可以概括这一点:

select * from articles where 
', '||category||',' not like '%, hockey,%' and
', '||category||',' not like '%, sports,%' and
', '||category||',' like '%, soccer,%' and
', '||category||',' like '%, boxing,%';

但是请注意,这种方法通常不是处理关系数据库中数据的首选方法。