необходимо эффективное соединение с виртуальной таблицей, используемой несколько раз в подзапросе - PullRequest
0 голосов
/ 07 марта 2011

Я пытаюсь выполнить запрос, подобный этому:

SELECT s.custno, 
       s.prodno, 
       IF(daycode = 1, (SELECT avg(sell) 
                        FROM   sales ss 
                               JOIN (SELECT DISTINCT `prodno` 
                                     FROM   `familycode` 
                                     WHERE  prodfamily = 101) f2 
                                 ON f2.prodno = ss.prodno 
                        WHERE  ss.CUSTNO = 800 
                               AND ss.weekno = s.weekno - 1), (SELECT avg(sell) 
                                                               FROM   sales ss 
                                                                      JOIN (SELECT DISTINCT `prodno`
                                                                            FROM   `familycode`
                                                                            WHERE  prodfam = 101) f3
                                                                        ON f3.prodno = ss.prodno
                                                               WHERE  ss.CUSTNO = 800 
                                                                      AND ss.weekno = s.weekno)) AS weekavg
FROM   sales s 
       JOIN product p 
         ON p.prodno = s.prodno 
       JOIN (SELECT DISTINCT `prodno` 
             FROM   `familycode` 
             WHERE  prodfamily = 101) f 
         ON f.prodno = s.prodno 
WHERE  s.CUSTNO = 800 
ORDER  BY ardate8n ASC, 
          s.CUSTNO, 
          s.prodno 

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

Продукт принадлежит семейству продуктов.

  • Если daycode = 1, я хочу получить для того же семейства продуктов среднее значение за предыдущую неделю.
  • иначе я хочу получитьсреднее значение за текущую неделю для одного и того же семейства продуктов.

Как видите, f, f2, f3 являются похожими виртуальными таблицами, что помогает нам связываться с существующими продуктами на основе продукта.family.

Как можно переписать этот запрос, чтобы не вычислять f2, f3 таблиц, что является очень медленным процессом.

Ответы [ 2 ]

0 голосов
/ 07 марта 2011

Полагаю, я немного запутался, но вот мой выбор.Было бы полезно, если бы вы показали пример вывода с вашим вопросом.Я также не вижу никакой связи с ardate8n и не совсем понимаю, как ss.weekno = s.weekno - 1 работает для вас.Надеюсь, это поможет как-то.Если это не отвечает вашим целям, пожалуйста, расширите свой ответ, включив в него ожидаемый результат, определения таблиц и то, что именно вы пытаетесь достичь.

По сути это звучит так, как будто у вас есть sales, productи productfamily таблица и необходимо сообщать о средних продажах всех продуктов в семействе продуктов за данную неделю (будь то текущая неделя или предыдущая).Если я правильно понимаю, следующий SELECT должен сработать и быть довольно быстрым, однако он даст вам все продукты и каждую неделю.

SELECT p.prodno, f.familycode, s.custno, s.weekno, AVG( s.sell ) as sales_avg
    FROM sale s
    JOIN product p USING(prodno)
    JOIN productfamily f USING(prodno)
GROUP BY s.weekno, f.familycode, p.prodno
ORDER BY s.weekno

Теперь, превратите это в представление.

CREATE VIEW "main"."view_weekly_product_sales_avg" AS 
SELECT p.prodno, f.familycode, s.custno, s.weekno, AVG( s.sell ) as sales_avg
    FROM sale s
    JOIN prod p USING(prodno)
    JOIN prodfamily f USING(prodno)
GROUP BY s.weekno, f.familycode, p.prodno
ORDER BY s.weekno;

Затем запросите представление / отчет, как вам нужно.Из вашего примера, я думаю, вы бы запросили его так:

SELECT prodno, custno, sales_avg
    FROM view_weekly_product_sales_avg
WHERE familycode = 1 AND custno = 1 AND weekno = 1

Для меня это выдает следующую таблицу:

prodno  custno  sales_avg
1       1       37.3333333333333
2       1       12.0
3       1       78.0
8       1       12.0
0 голосов
/ 07 марта 2011

У меня нет доступной для меня среды mysql, она из памяти и не работает с некоторыми макетированными таблицами.

Во-первых, я бы попробовал придерживаться только объединений, поскольку единственная фильтрация, выполняемая для семейного кода, - это «отдельный» маркер. Я не знаю данных в семейном коде, поэтому сравните работающий медленный запрос с новым и наблюдайте «всплеск продаж» из дубликатов!

FROM   sales ss 
JOIN (SELECT DISTINCT `prodno` 
FROM   `familycode` 
 WHERE  prodfamily = 101) f2 
ON f2.prodno = ss.prodno 
WHERE  ss.CUSTNO = 800 

становится

 FROM   sales ss 
JOIN familycode f2 
ON f2.prodno = ss.prodno 
WHERE  ss.CUSTNO = 800 and f2.prodfamily = 101

Мой второй подход, и если у вас возникнет проблема с дублированием продаж, будет использовать предложение «существует» вместо предложения «отдельный». это решение будет выглядеть так:

FROM   sales ss 
    JOIN familycode f2 
    ON f2.prodno = ss.prodno 
    WHERE  ss.CUSTNO = 800 and exists (select 1 from familycode f2 where f2.prodno = ss.prodno and f2.prodfamily= 101)
...