【问题标题】:SQL build table using results of count(*) from other table使用来自其他表的 count(*) 结果的 SQL 构建表
【发布时间】:2018-11-07 16:02:42
【问题描述】:

我正在构建一个 Pokemon 数据集,并希望对其运行一些查询。 这是数据库的设置:

create table pokedex(
    name varchar(20) not null,
    weigth int not null,
    height int not null,
    primary key(name)
);
create table trainer(
    name varchar(20) not null,
    location varchar(20) not null,
    gender varchar(10) not null,
    birth_year int not null,
    primary key(name)
);

create table trainer_pokemon(
    trainer_name varchar(20) not null,
    pokemon_name varchar(20) not null,
    level int not null,
    year_obtained int not null,
    primary key(trainer_name, pokemon_name, level, year_obtained),
    foreign key(trainer_name) references trainer(name),
    foreign key(pokemon_name) references pokedex(name)
);
create table type(
    name varchar(20) not null,
    primary key(name)
);
create table poke_type(
    pokemon_name varchar(20) not null,
    type_name varchar(20) not null,
    primary key(pokemon_name, type_name),
    foreign key(pokemon_name) references pokedex(name),
    foreign key(type_name) references type(name)
);

这个想法是数据集不应该有冗余数据,所以如果我想为每个训练师获取一个包含最常用口袋妖怪类型的表,我需要为每种类型获取一个表,或者至少这是我认为 atm 的表:

with psychics as (
    select trainer_name, count(type_name) psychic from trainer_pokemon as tp
    inner join poke_type as pt on pt.pokemon_name = tp.pokemon_name
    group by tp.trainer_name, pt.type_name
    having pt.type_name = 'Psychic'
),
waters as (
    select trainer_name, count(type_name) water from trainer_pokemon as tp
    inner join poke_type as pt on pt.pokemon_name = tp.pokemon_name
    group by tp.trainer_name, pt.type_name
    having pt.type_name = 'Water'
),
select tp.trainer_name, w.water, p.psychic from trainer_pokemon as tp
inner join waters as w on w.trainer_name = tp.trainer_name
inner join psychics as p on p.trainer_name = tp.trainer_name
group by tp.trainer_name, w.water, p.psychic

但是,这不会导致训练师没有特定类型的口袋妖怪(本例中为水/通灵)。

有没有人能指出我正确的方向来建立训练师表,其中包含特定类型在他们的口袋妖怪收藏中的次数?

【问题讨论】:

    标签: postgresql count create-table


    【解决方案1】:

    假设您使用的是相对更新的 Postgresql 版本(您已经标记了 Mysql 和 Postgres,它们是完全不同的数据库)

    SELECT tp.trainer_name,
      COUNT(*) FILTER (WHERE pt.type_name = 'Psychic') as psychic,
      COUNT(*) FILTER (WHERE pt.type_name = 'Water')   as water
    FROM trainer_pokemon tp, poke_type pt
    WHERE tp.pokemon_name = pt.pokemon_name
    GROUP BY 1
    

    在您的问题中发布的查询可能会作为对表的多次扫描执行,但如果您确实想要这样做,您想使用“LEFT OUTER JOIN”(OUTER 关键字是可选的):

    with psychics as (
        select trainer_name, count(type_name) AS psychic
        from trainer_pokemon as tp
          inner join poke_type as pt on pt.pokemon_name = tp.pokemon_name
        group by tp.trainer_name, pt.type_name
        having pt.type_name = 'Psychic'
    ), waters as (
        select trainer_name, count(type_name) AS water
        from trainer_pokemon as tp
          inner join poke_type as pt on pt.pokemon_name = tp.pokemon_name
        group by tp.trainer_name, pt.type_name
        having pt.type_name = 'Water'
    )
    select tp.trainer_name, w.water, p.psychic
    from trainer_pokemon as tp
      left join waters as w on w.trainer_name = tp.trainer_name
      left join psychics as p on p.trainer_name = tp.trainer_name
    

    或者如果您获得两种以上的类型,可能会更好地扩展:

    with trained as (
        select trainer_name, pt.type_name, count(*) as num
        from trainer_pokemon as tp
          inner join poke_type as pt on pt.pokemon_name = tp.pokemon_name
        group by tp.trainer_name, pt.type_name
    )
    select tp.trainer_name, w.num as water, p.num as psychic
    from trainer_pokemon as tp
      left join trained as w on tp.trainer_name = w.trainer_name and w.type_name = 'Water'
      left join trained as p on tp.trainer_name = p.trainer_name and p.type_name = 'Psychic'
    

    【讨论】:

    • 哇,非常感谢!我真的需要开始更多地了解哪些类型的连接在某些时候有用;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    相关资源
    最近更新 更多