Помогите со сложным SQL-запросом - PullRequest
1 голос
/ 21 апреля 2010

Короче говоря, я создаю самообучающуюся систему управления баннерами. Пользователи смогут вставлять эти баннеры на свой сайт, когда баннеры будут показываться на основе соотношения продаж / показов.

У меня есть 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, который есть у того же пользователя. Поэтому мне нужно получить сумму показов и продаж для каждого bannerID в SmartBannerArray.

Все, что мне приходит в голову, - это использовать двойной курсор, цикл будет повторяться при мысли, что SmartBannerArrays получит необходимые значения для суммы показов и продаж, а затем внутренний цикл, который будет обращаться к каждому SmartBanner и изменять его процент «видимости» на основе (продажи / показы) / (sumOfSales / sumOfImpressions) * 100

Надеюсь, вы получите картину ...

Есть ли другой способ создания лучших таблиц или не использовать двойной курсор, чтобы избежать перегрузки сервера?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ Каждая продажа записывается в таблицу статистики, поле обновляется, потому что мне нужна ежедневная сумма за баннер, а не каждую продажу. Пользователь создает BannerArray, выбирает продукты, которые он хотел бы продвигать. Каждый выбранный продукт записывается в таблицу баннеров с соответствующим изображением и другой информацией. В таблице SmartBanners хранится bannerID, а также таблица статистики, а в таблице BannerArray эта группа баннеров назначается определенному пользователю.

Ответы [ 3 ]

2 голосов
/ 21 апреля 2010

Картинка не очень четкая. Зачем вообще курсоры, что с этим не так?

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 голос
/ 21 апреля 2010

Во многих случаях использование курсоров можно избежать с помощью производных таблиц.Введение в их использование можно найти здесь .

0 голосов
/ 21 апреля 2010

Я думаю, что вы задаете правильный вопрос: есть ли способ разработать лучшие таблицы? Мой совет: не беспокойтесь о перегрузке сервера, что не составляет большого труда, если вы выполняете запросы только один раз в день Беспокойся больше о понятной структуре.

Как насчет этого:

 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 для целых чисел, а не в процентах. Вам понадобится двойной. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...