针对在子查询中多次使用的虚拟表所需的高效连接

时间:2011-03-07 16:59:06

标签: mysql sql stored-procedures join average

我正在尝试运行类似于此的查询:

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 

在此查询中,我希望根据产品系列的日代码参数获取产品周平均值。

产品属于产品系列。

  • 如果日期代码= 1,我希望获得相同产品系列的前一周的平均值。
  • 否则我希望在同一产品系列的当周获得平均值。

如您所见ff2f3是类似的虚拟表格,可帮助我们根据产品系列与现有产品进行关联。

如何重写此查询以便不计算f2f3表,这是一个非常缓慢的过程。

2 个答案:

答案 0 :(得分:0)

我没有可用的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

我的第二种方法,如果你得到重复的销售峰值问题,那就是尝试'exists'子句而不是'distinct'子句。该解决方案看起来像这样:

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)

答案 1 :(得分:0)

我想我有点困惑,但这是我的理由。如果您在问题中显示一些示例输出,那将会很有帮助。我也没有看到与ardate8n的任何关联,也不完全理解ss.weekno = s.weekno - 1对你的影响。我希望这会有所帮助。如果它不符合您的目标,请扩展您的答案,包括预期的输出,表格定义以及您要完成的目标。

基本上,您有salesproductproductfamily表,并且需要报告某一产品系列中所有产品的平均销售额(无论是它是当前一周或前一周)。如果我理解正确的话,下面的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