帮助复杂的SQL查询

时间:2010-04-21 12:33:15

标签: sql sql-server-2005

为了简短起见,我正在建立自学横幅管理系统。当根据销售/展示比率显示横幅时,用户可以将这些横幅插入其网站。

我有4张桌子

Banners 
bannerID      int
bannerImage   varchar....

SmartBanners
smartBannerID      int
smartBannerArrayID int
bannerID           int
impressionsCount   int
visibility         tinyint (percents)

SmartBannerArrays 
smartBannerArrayID int
userID             int

Statistics
bannerID          int
saleAmountPerDay  decimal...

每晚我需要为每个SmartBanner基于同一用户拥有的整个SmartBannerArray生成新的“可见性”。因此,我需要获取SmartBannerArray中每个bannerID的总展示次数和销售额。

所有我想到的是使用双光标,一个将循环认为SmartBannerArrays获得印象和销售总和所需的值,然后内循环将访问每个SmartBanner并更改它的“可见性”百分比基于 (销售/展示)/(sumOfSales / sumOfImpressions)* 100

希望你能得到照片......

有没有其他方法可以设计更好的表或不使用双光标来避免服务器过载?

更多信息 每个销售写入统计表,字段更新,因为我需要每个横幅而不是每个销售每日总和。用户创建BannerArray,选择他想要推广的产品。他选择的每个产品都写在Banners表中,附有适当的图像和其他信息。 SmartBanners表将bannerID存储为Statistics表,而BannerArray表将此组横幅分配给某个用户。

3 个答案:

答案 0 :(得分:2)

图片不太清楚。为什么游标呢,这有什么问题?

SELECT SUM(saleAmountPerDay)/SUM(impressionsCount) 
FROM SmartBanners sb        INNER JOIN
     SmartBannerArrays sba  ON sb.smartBannerArrayID = sba.smartBannerArrayID INNER JOIN
     Statistics ss          ON sb.bannerID = ss.bannerID 
GROUP BY smartBannerArrayID

然后可以将其用作子查询来直接计算“可见性”。

EDIT2: 说明原则(SQL未优化),为什么不:

UPDATE SmartBanners
SET visibility = 
    ROUND( 100. * 
    (
    SELECT SUM(saleAmountPerDay)/SUM(impressionsCount) 
    FROM SmartBanners sb        INNER JOIN
         Statistics ss          ON sb.bannerID = ss.bannerID 
    WHERE sb.smartBannerID = SmartBAnners.smartBannerID
    ) /
    (
    SELECT SUM(saleAmountPerDay)/SUM(impressionsCount) 
    FROM SmartBanners sb        INNER JOIN
         SmartBannerArrays sba  ON sb.smartBannerArrayID = sba.smartBannerArrayID INNER JOIN
         Statistics ss          ON sb.bannerID = ss.bannerID 
    WHERE sb.smartBannerArrayID = SmartBAnners.smartBannerArrayID
    ) )

如果你想避开游标。

另外,不要忘记 - 如果这些数据不会经常更新(统计表更新的频率是多少?我想你会从某些日志中定期更新它)并且如果你想要最大限度地提高读取性能你可能会考虑触发器。

EDIT3: 在MS SQL中,您还可以使用OVER子句,只是一个简短的例子

SELECT 
       SUM(saleAmountPerDay) OVER(PARTITION BY BannerID) AS 'TotalSalesByBanner',
       SUM(impressionsCount) OVER(PARTITION BY BannerID) AS 'TotalImpressionsByBanner',
       SUM(saleAmountPerDay) OVER(PARTITION BY smartBannerArrayID) AS 'TotalSalesByArray',
       SUM(impressionsCount) OVER(PARTITION BY smartBannerArrayID) AS 'TotalImpressionsByBanner'    
FROM   
       SmartBanners sb INNER JOIN
       Statistics ss   ON sb.bannerID = ss.bannerID
GROUP BY
       SmartBannerID

此SQL未经过测试。

答案 1 :(得分:1)

在许多情况下,使用派生表可以避免使用游标。可以找到使用它们的介绍here

答案 2 :(得分:0)

我认为你问的是正确的问题,那就是:有没有办法设计更好的表格?我的建议:不要担心服务器过载,如果你每天只运行一次查询,这没什么大不了的。更担心可理解的结构。

这个怎么样:

 Banners
 -------
 BannerID
 UserID
 BannerImage
 BannerVisibility  // A denormalized value that you calculate once a day

 Banner_Sales
 ------------
 BannerID
 Date
 SalesAmt

 Banner_Impressions
 ------------------
 BannerID
 Date
 Impressions

您不需要SmartBannerArray(或游标)来对销售额和展示次数求和。只需使用SQL总和:

 SELECT SUM(bs.SalesAmt) AS SALES, SUM(bi.Impressions) AS IMPRESSIONS, 
   SUM(bs.SalesAmt) / SUM(bi.Impressions) AS RATIO
 FROM Banners b
 JOIN Banner_Sales bs
 JOIN Banner_Impressions bi
 WHERE b.UserID = ? // For total sales / impressions for a user

替代

WHERE b.BannerID = ? // For total sales / impressions for a banner
祝你好运!

P.S。 tinyint是整数,而不是百分比。你需要一个双。 :)