SQL查询如何无需将所有字段写入GROUP BY子句即可展示表全部列
解决方案
有两种成熟方案可以避免在GROUP BY子句中写入全部查询字段,具体如下:
方案1:预聚合评论表后关联(全版本兼容,推荐使用)
你需要的聚合结果只有每个餐厅的平均评分,因此可以先单独对评论表做分组聚合,再和餐厅表关联,完全不需要对餐厅表字段做分组,逻辑更清晰,兼容所有SQL Server版本:
-- 先预聚合得到每个餐厅的平均评分 WITH RestaurantAvgRating AS ( SELECT RestaurantId, ROUND(AVG(Rates),2) Rating FROM [dbo].[RestaurantReviews] GROUP BY RestaurantId ) SELECT rr.Rating, dist.Distance, dist.DeliveryCharges, r.Id, r.IsActive, r.CreatedDate, r.Name, r.TagLine, r.ApproximateCostPerPerson, r.FullAddress2, r.FullAddress, r.Tags, r.IsRecommend, r.Longitude, r.DeliveryTime, r.IsOnline, r.Logo, r.ImageUrl, r.Latitude, r.ProductDiscount, r.IsApproved, r.Salt, r.Email, r.PhoneNumber, r.CityId, r.CountryId FROM [dbo].[Restaurants] r LEFT JOIN RestaurantAvgRating rr ON r.Id = rr.RestaurantId -- 用CROSS APPLY复用距离、配送费计算逻辑,不用重复写两次函数 CROSS APPLY ( SELECT [dbo].[Fun_distanceCalculate](r.Latitude,r.Longitude,@sourceLatitude,@sourceLongitude) AS Distance, [dbo].[Fun_calculate_delivery_fee](r.Latitude,r.Longitude,@sourceLatitude,@sourceLongitude) AS DeliveryCharges ) dist WHERE r.IsActive = 1 AND r.IsApproved=1 AND (r.CityId=@cityId OR @KM > dist.Distance) -- 后面的分页、排序逻辑直接加即可 -- ORDER BY Id DESC -- OFFSET @PageNumber ROWS -- FETCH NEXT @pageSize ROWS ONLY
方案2:利用主键特性简化GROUP BY(仅高版本兼容)
如果你的SQL Server版本为2019及以上,且数据库兼容级别设置为150及更高,由于r.Id是Restaurants表的主键,可以唯一确定该行所有字段的值,此时GROUP BY子句只需要保留主键r.Id即可,其余餐厅表字段不需要写入GROUP BY也可正常执行:
SELECT round(AVG(rr.Rates ),2) Rating, [dbo].[Fun_distanceCalculate](r.Latitude,r.Longitude,@sourceLatitude,@sourceLongitude) AS Distance, [dbo].[Fun_calculate_delivery_fee](r.Latitude,r.Longitude,@sourceLatitude,@sourceLongitude) AS DeliveryCharges, r.Id, -- 其余所有餐厅字段都可保留,不需要调整 r.IsActive, r.CreatedDate, Name, TagLine, ApproximateCostPerPerson, FullAddress2, FullAddress, Tags, IsRecommend, Longitude, DeliveryTime, IsOnline, Logo, ImageUrl, Latitude, ProductDiscount, TagLine, IsApproved, Salt, Email, PhoneNumber, CityId, CountryId FROM [dbo].[Restaurants] r LEFT JOIN [dbo].[RestaurantReviews] rr ON r.Id=rr.RestaurantId WHERE r.IsActive = 1 AND r.IsApproved=1 AND ((r.CityId=@cityId) OR @KM > [dbo].[Fun_distanceCalculate](r.Latitude,r.Longitude,@sourceLatitude,@sourceLongitude)) GROUP BY r.Id -- 仅保留主键即可
注意:该方案兼容性较差,数据库版本降级或者兼容级别调整都会导致语句报错,生产环境优先使用方案1。
内容的提问来源于stack exchange,提问作者ADEEL FAROOQ
相关产品推荐
相关产品推荐

