SQL 使用来自其他 table 的计数 (*) 结果构建 table
SQL build table using results of count(*) from other table
我正在构建一个 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)
);
这个想法是数据集不应该有冗余数据所以如果我想得到一个 table 包含每个训练师最常用的口袋妖怪类型我需要为每种类型获得一个 table ,或者至少我相信 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
但是,这不会导致训练员没有特定类型的口袋妖怪(本例中为water/psychic)。
有没有人能给我指出正确的方向来建立 table 训练师以及特定类型在他们的口袋妖怪 collection 中出现的次数?
假设您使用的是相对更新的 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
您问题中发布的查询可能会作为 table 的多次扫描执行,但如果您真的想这样做,您需要使用 "LEFT OUTER JOIN"s(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'
我正在构建一个 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)
);
这个想法是数据集不应该有冗余数据所以如果我想得到一个 table 包含每个训练师最常用的口袋妖怪类型我需要为每种类型获得一个 table ,或者至少我相信 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
但是,这不会导致训练员没有特定类型的口袋妖怪(本例中为water/psychic)。
有没有人能给我指出正确的方向来建立 table 训练师以及特定类型在他们的口袋妖怪 collection 中出现的次数?
假设您使用的是相对更新的 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
您问题中发布的查询可能会作为 table 的多次扫描执行,但如果您真的想这样做,您需要使用 "LEFT OUTER JOIN"s(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'