我在数据库中有四个表:City,User,CityRating,CityGreeting。 CityRating表具有UserID和CityID作为PK,它们是USer和City表的FK。 CityGreeting表没有PK,但是UserID和CityID是FK(想法是用户可以根据需要多次问候城市,但只对城市评分一次)。
我正在尝试编写一个查询,它将返回整个城市的平均评分,以及特定用户对该城市的欢迎时间:
select City.CityID, City.CityName, City.CityStateOrProvince,
ROUND(AVG(Cast(RateCity.Rating as float)), 2) as AverageRating,
(select COUNT(HelloCity.CityID) from HelloCity where HelloCity.UserID like '<guid>') as TimesVisited
from City
right join RateCity
on City.CityID = RateCity.CityID
right join HelloCity
on City.CityID = HelloCity.CityID
group by City.CityID, City.CityName,
City.CityStateOrProvince, City.CityCountry, City.CityImageUri
即使我能按预期工作(目前还没有),我觉得它真的很乱。就最佳实践而言,编写两个查询会更好吗?这个操作将在api中执行,不确定在编写两个单独的查询时性能是否会更好,或者像这样复杂的一个。有关此问题的任何见解或如何使查询按预期工作?
***编辑:添加图片以澄清:平均评分是所有评分用户的平均评分,而TimesVisited是特定用户访问该城市的次数。
答案 0 :(得分:3)
我认为除了city
之外,您需要分别汇总表格才能使其正常运行:
select c.*, rc.AverageRating, coalesce(hc.TimesVisited, 0) as TimesVisited
from City c join
(select CityId, ROUND(AVG(Cast(RateCity.Rating as float)), 2) as AverageRating
from RateCity rc
group by CityId
) rc
on c.CityID = rc.CityID left join
(select CityId, count(*) as TimesVisited
from HelloCity hc
where hc.UserID like '<guid>'
group by CityId
) hc
on c.CityId = hc.CityId;
注意:
right join
。这意味着其他两个表中的CityId
不在City
中。left join
表HelloCity
,因为并非所有城市都有访问者。left join
表RateCity
。答案 1 :(得分:2)
为什么不使用CTE然后在每个CTE中执行各个部分,这有助于将其分解而不是尝试将多个连接混合在一起:例如:
DECLARE @userId VARCHAR(10) = 'userid1' ;
WITH
CITY_RATING_CTE (cityId, AverageRating) AS
( SELECT cityId,
AVG(Rating) AS rating
FROM RateCity
GROUP BY cityId),
TIMES_VISITED_CTE AS
( SELECT cityId,
count(*) AS TimesVisited
FROM HelloCity
WHERE UserId = @userId
GROUP BY cityId)
SELECT c.CityId,
c.CityName,
c.CityStateOrProvince,
c.CityImageUri,
cr.AverageRating,
tv.TimesVisited
FROM City c
JOIN CITY_RATING_CTE cr ON cr.cityId = c.CityId
JOIN TIMES_VISITED_CTE tv ON cr.cityId = cr.cityId;