我在查询中使用多个左连接时有点麻烦。有些表与左表有一对一的关系,有些与一对多关系。查询如下所示:
Select
files.filename,
coalesce(count(distinct case
when dm_data.weather like '%clear%' then 1
end),
0) as clear,
coalesce(count(distinct case
when dm_data.weather like '%lightRain%' then 1
end),
0) as lightRain,
coalesce(count(case
when kc_data.type like '%bicycle%' then 1
end),
0) as bicycle,
coalesce(count(case
when kc_data.type like '%bus%' then 1
end),
0) as bus,
coalesce(count(case
when kpo_data.movement like '%walking%' then 1
end),
0) as walking,
coalesce(count(case
when kpo_data.type like '%pedestrian%' then 1
end),
0) as pedestrian
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
left join
kpo_data ON kpo_data.id = files.id
where
files.filename in (X, Y, Z, ........)
group by files.filename;
这里,dm_data表与'files'表有一对一的关系(这就是为什么我使用'Distinct'),而kc_data和kpo_data数据与'files'表有一对多的关系。 (对于一个files.id,kc_data和kpo_data可以有10到20行)。此查询工作正常。
当我使用另一个一对多表pd_markings(对一个files.id可以有100行)添加另一个左连接时,会出现问题。
Select
files.filename,
coalesce(count(distinct case
when dm_data.weather like '%clear%' then 1
end),
0) as clear,
coalesce(count(distinct case
when dm_data.weather like '%lightRain%' then 1
end),
0) as lightRain,
coalesce(count(case
when kc_data.type like '%bicycle%' then 1
end),
0) as bicycle,
coalesce(count(case
when kc_data.type like '%bus%' then 1
end),
0) as bus,
coalesce(count(case
when kpo_data.movement like '%walking%' then 1
end),
0) as walking,
coalesce(count(case
when kpo_data.type like '%pedestrian%' then 1
end),
0) as pedestrian,
**coalesce(count(case
when pd_markings.movement like '%walking%' then 1
end),
0) as walking**
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
left join
kpo_data ON kpo_data.id = files.id
left join
**kpo_data ON pd_markings.id = files.id**
where
files.filename in (X, Y, Z, ........)
group by files.filename;
现在所有的值都变成了彼此的倍数。有任何想法吗???
请注意,前两列返回1或0值。实际上这是理想的结果,因为一对一关系表对任何files.id只有1或0行,所以如果我不使用'Distinct'那么结果值是错误的(我猜是因为其他表对同一个文件返回多行一行.id)不幸的是,我的表没有自己的唯一ID列,除了'files'表。
答案 0 :(得分:4)
您需要flatten the results查询,才能获得正确的计数。
你说你从文件表到其他表有一对多的关系
如果SQL只有关键字LOOKUP
而不是在JOIN
关键字中填写所有内容,那么很容易推断表A和表B之间的关系是否是一对一的,使用{ {1}}会自动表示一对多。我离题了。无论如何,我应该已经推断出你的文件与dm_data是一对多的;而且,针对kc_data的文件也是一对多的。 JOIN
是另一个暗示第一个表和第二个表之间的关系是一对多的;但这并不是决定性的,有些程序员只是用LEFT JOIN
编写所有内容。您的查询中的LEFT JOIN没有任何问题,但如果查询中有多个一对多表,那肯定会失败,您的查询将产生针对其他行的重复行。
LEFT JOIN
因此,根据这些知识,您指出文件与dm_data是一对多的,并且对kc_data也是一对多。我们可以得出结论,将这些连接链接起来并将它们分组到一个单一的查询中会出现问题。
一个例子,如果你有三个表,即app(文件),ios_app(dm_data),android_app(kc_data),这就是ios的数据:
from
files
left join
dm_data ON dm_data.id = files.id
left join
kc_data ON kc_data.id = files.id
这是你的android的数据:
test=# select * from ios_app order by app_code, date_released;
ios_app_id | app_code | date_released | price
------------+----------+---------------+--------
1 | AB | 2010-01-01 | 1.0000
3 | AB | 2010-01-03 | 3.0000
4 | AB | 2010-01-04 | 4.0000
2 | TR | 2010-01-02 | 2.0000
5 | TR | 2010-01-05 | 5.0000
(5 rows)
如果您只是使用此查询:
test=# select * from android_app order by app_code, date_released;
.android_app_id | app_code | date_released | price
----------------+----------+---------------+---------
1 | AB | 2010-01-06 | 6.0000
2 | AB | 2010-01-07 | 7.0000
7 | MK | 2010-01-07 | 7.0000
3 | TR | 2010-01-08 | 8.0000
4 | TR | 2010-01-09 | 9.0000
5 | TR | 2010-01-10 | 10.0000
6 | TR | 2010-01-11 | 11.0000
(7 rows)
输出错误:
select x.app_code,
count(i.date_released) as ios_release_count,
count(a.date_released) as android_release_count
from app x
left join ios_app i on i.app_code = x.app_code
left join android_app a on a.app_code = x.app_code
group by x.app_code
order by x.app_code
您可以将链式连接视为笛卡尔积,因此如果第一个表上有3行,第二个表上有2行,则输出为6
这是可视化,看到每个ios AB有2个重复的android AB。有3个ios AB,那么当你做COUNT(ios_app.date_released)时会有什么计数?那将成为6;与 app_code | ios_release_count | android_release_count
----------+-------------------+-----------------------
AB | 6 | 6
MK | 0 | 1
PM | 0 | 0
TR | 8 | 8
(4 rows)
相同,这也是6.同样,每个ios TR有4个重复的android TR,ios中有2个TR,所以这将给我们8个数。
COUNT(android_app.date_released)
因此,在将每个结果加入其他表和查询之前,应该将每个结果展平。
如果您的数据库能够进行CTE,请使用。它非常整洁,非常自我记录:
.app_code | ios_release_date | android_release_date
----------+------------------+----------------------
AB | 2010-01-01 | 2010-01-06
AB | 2010-01-01 | 2010-01-07
AB | 2010-01-03 | 2010-01-06
AB | 2010-01-03 | 2010-01-07
AB | 2010-01-04 | 2010-01-06
AB | 2010-01-04 | 2010-01-07
MK | | 2010-01-07
PM | |
TR | 2010-01-02 | 2010-01-08
TR | 2010-01-02 | 2010-01-09
TR | 2010-01-02 | 2010-01-10
TR | 2010-01-02 | 2010-01-11
TR | 2010-01-05 | 2010-01-08
TR | 2010-01-05 | 2010-01-09
TR | 2010-01-05 | 2010-01-10
TR | 2010-01-05 | 2010-01-11
(16 rows)
如果你的数据库还没有CTE功能,比如MySQL,你应该这样做:
with ios_app_release_count_list as
(
select app_code, count(date_released) as ios_release_count
from ios_app
group by app_code
)
,android_release_count_list as
(
select app_code, count(date_released) as android_release_count
from android_app
group by app_code
)
select
x.app_code,
coalesce(i.ios_release_count,0) as ios_release_count,
coalesce(a.android_release_count,0) as android_release_count
from app x
left join ios_app_release_count_list i on i.app_code = x.app_code
left join android_release_count_list a on a.app_code = x.app_code
order by x.app_code;
该查询和CTE样式的查询将显示正确的输出:
select x.app_code,
coalesce(i.ios_release_count,0) as ios_release_count,
coalesce(a.android_release_count,0) as android_release_count
from app x
left join
(
select app_code, count(date_released) as ios_release_count
from ios_app
group by app_code
) i on i.app_code = x.app_code
left join
(
select app_code, count(date_released) as android_release_count
from android_app
group by app_code
) a on a.app_code = x.app_code
order by x.app_code
实时测试
答案 1 :(得分:0)
我在这里质疑你的不同用法 - 它的编写方式将返回1或0.这意味着count distinct只会返回0,1或2。
我假设您在每个表中都有唯一的ID列。您可以更改大小写以返回ID值,然后计算不同的值。如果您的联接返回pd_markings表中同一行的多个,则ID上的非重复计数将返回,而且只返回非常多的行数。