【问题标题】:SQL variable group within another group另一个组中的 SQL 变量组
【发布时间】:2012-07-14 09:49:59
【问题描述】:

我正在寻找一种方法来匹配更大的其他结果列表中的一组结果,并计算匹配的数量。例如:

我有一组结果

Result 1
sub1
sub2
sub3

Result 2
sub1
sub2
sub3

我需要找出上述任何一组结果在下面更大的结果数据集中出现了多少次。

Result 1
sub1
sub2
sub3

Result 2
sub1
sub3
sub4

Result 2
sub1
sub2
sub3

Result 2
sub1
sub2
sub3
sub4

在上面的示例中,第一组的结果 1 将匹配第二组中的第一个结果,结果 2 将匹配第二组中的最后 2 个结果,因为它们包含第一组的所有子结果。因此,结果 1 将显示频率计数为 1,而结果 2 将显示频率计数为 2。

我对 SQL 比较陌生,但想找到解决上述问题的方法。

昨天的样本数据:

Group    Ad   Date
A        1    7/14
A        2    7/14
A        3    7/14
B        1    7/14
B        2    7/14
B        3    7/14
B        4    7/14
C        1    7/14
D        1    7/14
D        3    7/14
D        4    7/14

我需要了解过去一周 A 组广告 1-3 投放了多少次,但假设周一 A 组只投放了广告 1 和 3。我不希望返回此结果。星期二 A 组投放了广告 1、2、3、4。我想知道这个结果,星期三 A 组投放了 1、2、3 广告,我也想知道这个。

Group    Ad   Date
A        1    7/09
A        3    7/09
A        1    7/10
A        2    7/10
A        3    7/10
A        4    7/10
A        1    7/14
A        2    7/14
A        3    7/14

所以,鉴于这个例子,我希望看到这个:

Group    Ad   Date
A        1    7/10
A        2    7/10
A        3    7/10
A        1    7/14
A        2    7/14
A        3    7/14

【问题讨论】:

  • 什么是“子”?你能发布一些示例数据和可能想要的结果吗?
  • 您至少可以发布一个架构供我们使用吗?我们需要知道数据是如何表示的。每个组都有自己唯一的 id 吗?集合是在它们自己的表中还是由 id 表示?
  • @ZaneBien 样本数据是专有的,所以我不能发布它。我们有每天运行的广告集。这些广告在组内运行。示例中的“结果”是组,“子”是组内的广告。并非组内的每个广告都会每天投放。有时广告会添加到组中,有时广告会从组中删除。我需要了解在特定日期范围内,一组给定的广告在特定组中投放了多少次。
  • 我们不需要您的实际数据,但我们只需要知道您的表结构是如何布局的,这样我们就可以更好地了解您的情况。简单编造的数据非常好。
  • 好的,太好了!我们到了那里......还有一件事:你怎么知道什么时候以及什么广告在什么日期投放?它是存储在另一个表中还是一个表中的所有内容?

标签: mysql sql dataset sas


【解决方案1】:

这有点乱,但这是我能想到的:

SELECT a.*, b.*
FROM 
(
    SELECT 'A' AS grp, 1 AS ad UNION ALL
    SELECT 'A', 2 UNION ALL
    SELECT 'A', 3
) a 
CROSS JOIN
(
    SELECT DISTINCT date
    FROM tbl
    WHERE date >= CURDATE() - INTERVAL 1 WEEK
) b
LEFT JOIN tbl c ON a.grp = c.grp
               AND a.ad = c.ad
               AND b.date = c.date
INNER JOIN
(
    SELECT a.date
    FROM 
    (
        SELECT 'A' AS grp, 1 AS ad UNION ALL
        SELECT 'A', 2 UNION ALL
        SELECT 'A', 3
    ) a 
    CROSS JOIN
    (
        SELECT DISTINCT date
        FROM tbl
        WHERE date >= CURDATE() - INTERVAL 1 WEEK
    ) b
    LEFT JOIN tbl c ON a.grp = c.grp
                   AND a.ad = c.ad
                   AND b.date = c.date
    GROUP BY a.date
    HAVING COUNT(1) = COUNT(c.grp)
) d ON b.date = d.date

我有点太累了,写一个解释,但也许明天我醒来时,我会继续我的答案。

目前,您可以查看 SQLFiddle Example。请注意,我插入的值比您的示例数据中的值多四个,以展示当一组每天出现多次时查询是如何工作的。

^ 您可以在第二个执行的查询中看到,您还可以通过HAVING COUNT(1) >= 2 过滤该集合每天出现的频率。

【讨论】:

  • COUNT(CASE WHEN c.grp IS NULL THEN 1 END) = 0 可以简化为:COUNT(*) = COUNT(c.grp) 或者完全删除它,LEFT 加入 INNER 之一。
  • @ypercube,好点子,谢谢。它需要尽可能简化。
  • 这太棒了!有没有办法在其中添加更多的自动化?我在想像 Select * from table where date = Friday GROUP BY date, group, ad... 然后让该查询的结果为本周剩余时间提供查找。我正在查看的数据集每天会运行数万条广告。此外,一个组中并不总是正好有 3 个广告,有时会有一个,有时会有 2、3、4、5 个或更多。再次感谢您!
  • @Tom,如果所有内容都在同一个表中,我仍然对您如何定义“组”感到困惑。 A(1,2,3) 会是一个组吗? A(2,3,4,5,6) 会是另一个组吗?任何组合都是它自己的组吗?这取决于日期吗?如果有两列(组、广告)可以具有重复值,您如何区分?
【解决方案2】:

在 SAS SQL 中:

    proc sql;
    CREATE TABLE tbl (
      grp CHAR(1),
      ad INT,
      date DATE
    );

    INSERT INTO tbl 
    values('A', 1, '09jul2012'd) 
    values('A', 3, '09jul2012'd) 
    values('A', 1, '10jul2012'd) 
    values('A', 2, '10jul2012'd)
    values('A', 3, '10jul2012'd) 
    values('A', 4, '10jul2012'd) 
    values('A', 1, '14jul2012'd) 
    values('A', 2, '14jul2012'd) 
    values('A', 3, '14jul2012'd) 
    values('A', 1, '14jul2012'd) 
    values('A', 2, '14jul2012'd) 
    values('A', 3, '14jul2012'd) 
    ;
    quit;

    proc sql noprint; /* the set and upper date I'm interested in */
    CREATE TABLE my_set (
      grp CHAR(1),
      ad INT,
      date DATE
    );

    INSERT INTO my_set (grp, ad)
    VALUES ('A', 1)
    VALUES ('A', 2)
    VALUES ('A', 3)
    ;
    update my_set set date=today()-1;
    select count(*) into :my_set_size from my_set
    ;
    quit;

    proc sql;
    create table potential_dates as
     select t.date, s.grp, s.ad, count(*) as ad_occurrence
    from my_set s
     inner join tbl t 
        on s.grp = t.grp and s.ad = t.ad and s.date >= t.date
     group by t.date, s.grp, s.ad
    ;
    quit;

    proc sql;
        create table result as
            select a.* from potential_dates a
             inner join (select date from potential_dates
                        group by date
                        having count(*) = &my_set_size ) d
            on a.date = d.date
    ;
    quit;


 date     grp        ad  ad_occurrence
 10JUL12  A           1              1
 10JUL12  A           2              1
 10JUL12  A           3              1
 14JUL12  A           1              2
 14JUL12  A           2              2
 14JUL12  A           3              2

【讨论】:

    【解决方案3】:

    也许你可以排序和转置:

    proc sort data=mydata1;
      by group date;
    run;
    
    proc transpose data=mydata1 out=mydata2;
      by group date;
      var ad;
    run;
    
    data mydata3;
      set mydata2;
      if not missing(col1,col2,col3);
    run;
    

    每个日期您将有一行。如果需要,您可以将其合并回您的原始数据:

    data mydata4;
      merge mydata1 mydata3;
      by group date;
    run;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 2021-10-22
      相关资源
      最近更新 更多