开发者

efficient join needed against a virtual table used multiple times in a subquery

I am trying to run a query similar to this one:

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 

In this query I would like the get the products week average based on the daycode param for a product family.

A product belongs to a product family.

  • If daycode = 1 I want to get for the same product family the average of the previous week.
  • else I want to get average on the current week for the same product family.

As you see f,f2,f3 are similar virtual ta开发者_Go百科bles, that helps us to link against existing products based on product family.

How could this query be rewritten so to not compute f2, f3 tables, which is a very slow process.


I don't have a mysql environment available to me atm, this is from memory and not run against some mocked up tables.

first, i would try to stick to just joins, as the only filtering done against familycode is a 'distinct' marker. I do not know the data in familycode, so compare a working slow query to the new one and watch for a 'sales spike' from duplicates!

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

becomes

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

My second approach, and if you get duplicates sales spike issue, would be to try an 'exists' clause instead of a 'distinct' clause. that solution would look like this:

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)


I guess I'm a bit confused, but here's my go at it. It would have been helpful if you showed some sample output with your question. I also don't see any correlation with ardate8n nor do I completely understand how ss.weekno = s.weekno - 1 works for you. I hope this helps somehow. If it isn't working towards your goals please expand you answer to include expected output, table definitions, and what exactly you are trying to accomplish.

Basically it sounds like you have a sales, product, and productfamily table and need to report on the average sales of all products in a product family during a given week (whether it is the current week or the previous one). If I understand this correctly, the following SELECT should work out and be pretty fast, however it will get you all products and every week.

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

Now, turn this into a view.

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;

Then query the view/report how you need. From your example, I think you would query it like this:

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

For me this reports out the following table:

prodno  custno  sales_avg
1       1       37.3333333333333
2       1       12.0
3       1       78.0
8       1       12.0
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜