我有3个表,这些表包含我要获取计数然后进行计算的数据。我有一个有效的查询,但是重复。
SELECT person_id,
(SELECT COUNT(*) from place_to_go where people.person_id=person_id) as 'Num_To_Go',
(SELECT COUNT(*) from place_been where people.person_id=person_id) as 'Num_Visited',
((SELECT COUNT(*) FROM place_been WHERE people.person_id=person_id) / (SELECT COUNT(*) FROM place_to_go WHERE people.person_id=person_id)) * 100 AS 'Perc_Visited'
FROM people;
我要完成的工作是没有重复的子查询来计算百分比。为此,我所做的任何更改都将导致语法错误,并且令人沮丧。
我可能已经可以使用
SELECT person_id,
(SELECT COUNT(*) from place_to_go where people.person_id=person_id) as 'Num_To_Go',
(SELECT COUNT(*) from place_been where people.person_id=person_id) as 'Num_Visited',
(CONVERT(DECIMAL(3,0), 'Num_To_Go'))/(CONVERT(DECIMAL(3,0), 'Num_Visited')) * 100 AS 'Perc_Visited'
FROM people;
但这最终导致将数据类型varchar转换为数字时出错
非常感谢任何指针。
答案 0 :(得分:2)
我会使用APPLY
:
SELECT person_id, Num_To_Go, Num_Visited, (Num_To_Go * 1.0 / Num_Visited) * 100 AS Perc_Visited
FROM people p OUTER APPLY
( SELECT COUNT(*) AS Num_To_Go
FROM place_to_go pg
WHERE P.person_id = pg.person_id
) pg OUTER APPLY
( SELECT COUNT(*) AS Num_Visited
FROM place_been pb
WHERE p.person_id = pb.person_id
) pb;
答案 1 :(得分:1)
您可以尝试使用子查询
select *, (CONVERT(DECIMAL(3,0), Num_To_Go))/(CONVERT(DECIMAL(3,0), Num_Visited)) * 100.00 AS 'Perc_Visited'
from
(
SELECT person_id,
(SELECT COUNT(*) from place_to_go where people.person_id=person_id) as 'Num_To_Go',
(SELECT COUNT(*) from place_been where people.person_id=person_id) as 'Num_Visited',
FROM people
)A
答案 2 :(得分:0)
这在黑暗中有点刺痛,也许是:
SELECT p.person_id,
COUNT(DISTINCT p2g.{id_column}) AS NumToGo,
COUNT(DISTINCT pb.{id_column}) AS NNumVisited,
((COUNT(DISTINCT pb.{id_column}) * 1.0) / COUNT(DISTINCT p2g.{id_column})) * 100 AS Perc_Visited --* 1.0 due to integer math. I.e. 99/100 = 0
FROM people p
LEFT JOIN place_to_go p2g ON p.person_id = p2g.person_id
LEFT JOIN place_been pb ON p.person_id = pb.person_id
GROUP BY person_id;
答案 3 :(得分:0)
这是我要解决的方法:Runnable Example
select ppl.person_id
, coalesce(ptg.cnt,0) as 'Num_To_Go'
, coalesce(pb.cnt,0) as 'Num_Visited'
, case
when coalesce(ptg.cnt,0) = 0 then 100 --avoid /0 error ; if there are no places to go let's say we've been to them all
else 100.0 * coalesce(pb.cnt,0) / ptg.cnt
end 'Perc_Visited'
from people ppl
left outer join (select person_id, count(1) cnt from place_to_go group by person_id) ptg on ptg.person_id = ppl.person_id
left outer join (select person_id, count(1) cnt from place_been group by person_id) pb on pb.person_id = ppl.person_id
left outer join
,因此即使某人在任何一个表中都没有记录,我们仍然会在结果中看到该人。coalesce(cnt,0)
来确保没有与我们看到的0
(而不是null
)相关的人相关的记录。case
语句来计算百分比,因为涉及除法并且除数可能为0,从而导致被零除的错误。此案例声明可确保在这种情况下我们返回100%;并且仅在我们可以避免此异常的情况下使用计算。100.0 *
而不是100 *
来确保我们的解决方案可以返回非整数结果;也就是说,我们不会被截断为0个小数位。但是,您的设计也存在问题。它假定您去过的每个地方都在去的地方表中列出。如果这个假设是正确的,那么最好为places_to_go
创建一个表,并在其中添加一个字段来标记您是否去过。这样,您就可以在代码中强制执行该规则,提高性能并减少空间。
create table places_to_go
(
place_id bigint not null foreign key references places(place_id)
, person_id bigint not null foreign key references people(person_id)
, have_been bit not null default (0)
--& indexes / primary key field for this table / whatever else as required
)
select ppl.person_id
, coalesce(ptg.cnt_to_go,0) as 'Num_To_Go'
, coalesce(ptg.cnt_have_been,0) as 'Num_Visited'
, case
when coalesce(ptg.cnt_to_go,0) = 0 then null --avoid /0 error ;
else 100.0 * ptg.cnt_have_been / ptg.cnt_to_go
end 'Perc_Visited'
from people ppl
left outer join
(
select person_id
, count(1) cnt_to_go
, count(case when have_been = 1 then 1 end) cnt_have_been
from place_to_go
group by person_id
) ptg
on ptg.person_id = ppl.person_id
答案 4 :(得分:0)
将查询包装在派生表中。对结果进行最终计算:
select person_id, [Num_To_Go], [Num_Visited],
[Num_To_Go] * 100.0 / [Num_Visited] AS [Perc_Visited]
from
(
SELECT person_id,
(SELECT COUNT(*) from place_to_go where people.person_id=person_id) as [Num_To_Go],
(SELECT COUNT(*) from place_been where people.person_id=person_id) as [Num_Visited]
FROM people
) dt
或者具有CTE(公用表表达式):
with cte as
(
SELECT person_id,
(SELECT COUNT(*) from place_to_go where people.person_id=person_id) as [Num_To_Go],
(SELECT COUNT(*) from place_been where people.person_id=person_id) as [Num_Visited]
FROM people
)
select person_id, [Num_To_Go], [Num_Visited],
[Num_To_Go] * 100.0 [Num_Visited] AS [Perc_Visited]
from cte