微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从许多表格中找到相交的组合?

如何解决如何从许多表格中找到相交的组合?

我有一个不同渠道的列表,这些渠道可能会潜在地将用户带到一个网站(有机,SEO,在线营销等)。我想找到一种有效的方法来计算来自这些渠道的组合的每日活跃用户。每个频道都有自己的表并跟踪其各自的用户

这些表如下所示,

channel A
date         user_id
2020-08-01   A
2020-08-01   B
2020-08-01   C

channel B
date         user_id
2020-08-01   C
2020-08-01   D
2020-08-01   G

channel C
date         user_id
2020-08-01   A
2020-08-01   C
2020-08-01   F

我想知道以下组合

  1. 仅访问频道A
  2. 仅访问频道A和B
  3. 仅访问B&C频道
  4. 仅访问频道B

但是,当频道很多(我有大约8个频道)时,组合就很多。我所做的大致就是这样简单(这个包含通道A)

SELECT 
    a.date,COUNT(disTINCT IF(b.user_id IS NULL AND c.user_id IS NULL,a.user_id,NULL)) AS dau_a,COUNT(disTINCT IF(b.user_id IS NOT NULL AND c.user_id IS NULL,NULL)) AS dau_a_b,...
FROM a LEFT JOIN b ON a.user_id = b.user_id AND a.date = b.date 
LEFT JOIN c ON a.user_id = c.user_id AND a.date = c.date
GROUP BY 1

但是在总频道数为8(2种组合有28种变化,3种有56种,4种有70种,还有更多)时非常繁琐。

有什么聪明的想法可以解决这个问题吗?我本来打算使用FULL OUTER JOIN,但似乎无法掌握它。答案非常感谢。

解决方法

我将使用 <Autocomplete multiple id="tags-outlined" options={top100Films} getOptionLabel={(option) => option.title} defaultValue={[top100Films[13]]} filterSelectedOptions size="small" renderInput={(params) => ( <TextField {...params} variant="outlined" placeholder="Enter Transshipment Ports" /> )} /> 和两个聚合级别来解决这个问题:

union all
,

但是,当频道很多(我大约有8个频道)时,组合很多

当通道总数为8时非常繁琐(2个组合包含28个变体,3个组合具有56个,4个组合具有70个,等等)。

有什么聪明的想法可以解决这个问题吗?

以下是用于BigQuery标准SQL的地址,并且恰好解决了OP所关注的问题

#standardSQL
CREATE TEMP FUNCTION generate_combinations(a ARRAY<INT64>) 
RETURNS ARRAY<STRING>
LANGUAGE js AS '''
  var combine = function(a) {
    var fn = function(n,src,got,all) {
      if (n == 0) {
        if (got.length > 0) {
          all[all.length] = got;
        } return;
      }
      for (var j = 0; j < src.length; j++) {
        fn(n - 1,src.slice(j + 1),got.concat([src[j]]),all);
      } return;
    }
    var all = []; for (var i = 1; i < a.length; i++) {
      fn(i,a,[],all);
    }
    all.push(a);
    return all;
  } 
  return combine(a)
''';
with users as (
    select distinct date,user_id,'A' channel from channel_A union all
    select distinct date,'B' from channel_B union all
    select distinct date,'C' from channel_C 
),visits as (
  select date,string_agg(channel,' & ' order by channel) combination
  from users
  group by date,user_id
),channels AS (
  select channel,cast(row_number() over(order by channel) as string) channel_num
  from (select distinct channel from users)
),combinations as (
  select string_agg(channel,' & ' order by channel_num) combination
  from unnest(generate_combinations(generate_array(1,(select count(1) from channels)))) AS items,unnest(split(items)) AS channel_num
  join channels using(channel_num)
  group by items
)
select date,combination as channels_visited_only,count(distinct user_id) dau
from visits
join combinations using (combination)
group by date,combination
order by combination

如果要应用于您的问题的样本数据-输出为

enter image description here

一些使用上述说明的解释

  • CTE users只需合并所有表并添加通道列即可区分相应行来自哪个表

  • CTE visits提取每个用户日期组合的所有访问频道的列表

  • CTE channels只是准备频道列表并分配编号供以后使用

  • CTE combinations使用JS UDF生成频道编号的所有组合,然后将它们重新组合回频道以生成频道组合

  • 和最终的SELECT语句仅查找那些访问频道列表与上一步中生成的频道组合匹配的用户

一些建议进一步精简上述代码

  • 假设您的频道表名称遵循channel_*模式

您可以在users CTE中使用通配符表功能,而不是

select distinct date,'A' channel from channel_A union all
select distinct date,'B' from channel_B union all
select distinct date,'C' from channel_C 

您可以使用类似下面的内容-因此只需一行,而不是您的针脚那么多

select distinct date,_TABLE_SUFFIX as channel from channel_*      
,

我认为您可以使用集合运算符来回答您的问题:https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#set_operators

例如

  1. 是(除了B以外的A)C
  2. 是A与B相交

,

我在考虑full join和聚合:

select date,a.channel_a,b.channel_b,c.channel_c,count(*) cnt
from      (select 'a' channel_a,a.* from channel_a) a
full join (select 'b' channel_b,b.* from channel_b b) b using (date,user_id)
full join (select 'c' channel_c,c.* from channel_c c) c using (date,user_id)
group by date,c.channel_c

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。