在sql数据中查找唯一集

时间:2014-05-24 18:13:37

标签: mysql sql

我有三张桌子:

Modules

| ID | name |

Subscription
| module_id | user_id | ...

User
| ID | user_name |

我需要一个唯一订阅集列表。 (即x用户订阅模块(1),y用户订阅(1,2)等。我可以在SQL中执行此操作吗?

2 个答案:

答案 0 :(得分:0)

让我们设置一些表格。

create table modules (
  module_id integer not null,
  module_name varchar(15) not null,
  primary key (module_id),
  unique (module_name)
);

insert into modules values (1, 'First module');
insert into modules values (2, 'Second module');

create table users (
  user_id integer not null,
  user_name varchar(15) not null,
  primary key (user_id),
  unique (user_name)
);

insert into users values (100, 'First user');
insert into users values (101, 'Second user');

create table subscriptions (
  module_id integer not null,
  user_id integer not null,
  primary key (module_id, user_id),
  foreign key (module_id) 
    references modules (module_id),
  foreign key (user_id)
    references users (user_id)
);

insert into subscriptions values (1, 100);
insert into subscriptions values (1, 101);
insert into subscriptions values (2, 100);

要获得正确的计数,您只需要对表格进行查询"订阅"。

select module_id, count(*) as num_users
from subscriptions
group by module_id
order by module_id;
module_id  num_users
--
1          2
2          1

您可以在联接中使用该语句来获取模块名称而不是模块ID号。

select t1.module_name, t2.num_users
from modules t1
inner join (select module_id, count(*) as num_users
            from subscriptions
            group by module_id
           ) t2
        on t1.module_id = t2.module_id
order by t1.module_name;
module_name      num_users
--
First module     2
Second module    1

您需要使用Innodb引擎来强制执行外键约束。

要获得订阅了模块ID 1和2的用户,请使用WHERE子句选择模块ID号,使用GROUP BY子句获取计数,并使用HAVING子句将输出限制为仅那些计数为2的用户ID号。(这意味着他们已经在WHERE子句中订阅两者那些模块。)

select user_id, count(*) num_modules
from subscriptions
where module_id in (1, 2)
group by user_id
having count(*) = 2;

如果您需要报告所有可能的模块组合,这种要求会很快爆发。仅10个模块,有超过1000种可能的组合。通常,您希望将程序编写到

  • 生成动态SQL,
  • 为每种可能的组合生成静态SQL语句
  • 每次要求报告组合时都会写一个新的SQL语句(通常,大多数组合都不感兴趣)或
  • 重新协商要求。

答案 1 :(得分:0)

我的同事提出了一个有趣的解决方案

select module_combinations
    from (select user_id, group_concat(module_id separator ', ') as module_combinations from subscriptions group by user_id) a
    group by a.module_combinations

但这似乎更接近回答原来的问题。

select module_combinations, count(*) as num_users
from (select group_concat(module_id order by module_id) as module_combinations
      from subscriptions 
      group by user_id) a
group by a.module_combinations;