2016-09-16 63 views
1

我在数据库中有四个表:City,User,CityRating,CityGreeting。 CityRating表的UserID和CityID作为PK,这些都是FK的USer和City表。 CityGreeting表没有PK,但具有用户ID和城市ID作为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是一个特定用户访问该城市的次数。

Added picture to clarify: Average Rating is the average of all users who rated, and TimesVisited is the amount of times one specific user has visited the city.

+0

什么你是否像使用UserId一样使用?你不应该在说UserID =和City.CityId = HelloCity.CityId吗? – MacWise

+0

您可以添加样本数据和预期结果 –

+0

我添加了一张图片来说明结果 - 图片中唯一不正确的是TimesVisited列 - 它应该显示特定用户访问过每个城市的次数 – KateMak

回答

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 s不在City中。
  • 通过为每个其他表进行聚合,您不需要外部查询中的聚合。
  • 我的确认为HelloCity表需要left join,因为不是所有的城市都可能有访问者。
  • 对于RateCity表,您可能还需要left join表,如果不是所有城市都有评分。
+0

这真是令人印象深刻。谢谢你。很好的解释,以及 – KateMak

+0

我希望询问有关查询的语法 - 我看到c是城市的别名 - 你能解释括号中的部分在做什么吗?它是否只是获得由括号中的select所定义的别名的“列”? – KateMak

+1

@KateMak。 。 。括号中的部分是子查询。 –

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; 
+0

在查询中添加了userid – MacWise

相关问题