Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
ITTrucker
Yak Posting Veteran
64 Posts |
Posted - 2014-01-21 : 14:21:31
|
Is there a good way to do an AVG of a MAX value? I'm trying to get the average number of days it takes to receive paperwork from a vendor after the assignment is completed. I can use:SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, INV_DATE, DATEDIFF(dd,DEL_DATE, INV_DATE) FROM INVOICEto get the number of days between the Delivery and the Invoice dates. The problem is we have vendors that turn in paperwork at different times for one order. So INV_DATE above, is replaced with (SELECT MAX(INV_DATE) FROM INVOICE WHERE ORD_NUM = ORD_NUM AND ASGN_ID = ASGN_ID)Which works fine and grabs the latest date of an invoice for that order done by that vendor. When I replace INV_DATE with the MAX in the DATEDIFF selection, it works fine too.My problem is when I try to get an average of the datediff, I get the Cannot perform an aggregate function on an expression containing an aggregate or a subquery.I want to be able to get an average delay between the two dates which I can do using temp tables to load up the MAX before and then average later, but the query takes a while to run (23 sec) and when I run it through the analyzer, the two temp tables (one date range specified by user parameters, the other is YTD) take up nearly all the processing and I get a Missing Index recommendation which is understandable since my temp tables aren't indexed. Any thoughts?Thanks |
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2014-01-21 : 15:00:53
|
My first thought is to just make your query with the MAX in it a derived table/inline view. But, I'm not 100% that will work.Please post sample data in a consumable format along with your expected results and we should be able to help you quicker.http://www.sqlservercentral.com/articles/Best+Practices/61537/http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2014-01-22 : 07:03:21
|
Sounds to me as need of derived table to get record with max invdate for vendor and then applying datediff over it to get days elapsed. Finally you can apply GROUP BY on vendor fields and do AVG(dayselapsed)ie likeSELECT ASGN_ID, ASGN_NAME, AVG(DATEDIFF(dd,DEL_DATE, INV_DATE)*1.0) AS AvgDaysFROM(SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, INV_DATE,ROW_NUMBER() OVER (PARTITION BY ASGN_ID, ORD_NUM ORDER BY INV_DATE DESC) AS SeqFROM INVOICE)tWHERE Seq=1GROUP BY ASGN_ID, ASGN_NAME ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
 |
|
ITTrucker
Yak Posting Veteran
64 Posts |
Posted - 2014-01-22 : 10:55:58
|
That derived table works, I hadn't thought about the ROW_NUMBER PARTITION and then joining where the result was 1 to get the top result instead of MAX.I ended up using the original query to allow the user to pick a date range, and then I used the derived table as the last column to give a static YTD value (this is going into a SSRS report so they won't know that the YTD Average is being returned on every row) so right after the Where Seq=1 I added a AND T.ASGN_ID = P.ASGN_ID to put the YTD value on the row that matches based on the ASGN_ID and that took forever to run (2 Mins)SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, (SELECT MAX(INV_DATE) FROM INVOICE WHERE ORD_NUM = ORD_NUM AND ASGN_ID = ASGN_ID), DATEDIFF(dd,DEL_DATE, (SELECT MAX(INV_DATE) FROM INVOICE WHERE ORD_NUM = ORD_NUM AND ASGN_ID = ASGN_ID)) (SELECT ASGN_ID, ASGN_NAME, AVG(DATEDIFF(dd,DEL_DATE, INV_DATE)*1.0) AS AvgDaysFROM(SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, INV_DATE,ROW_NUMBER() OVER (PARTITION BY ASGN_ID, ORD_NUM ORDER BY INV_DATE DESC) AS SeqFROM INVOICE)tWHERE Seq=1 AND T.ASGN_ID = P.ASGN_IDGROUP BY ASGN_ID, ASGN_NAME)FROM INVOICEWHERE DEL_DATE >= @FROMDATE AND DEL_DATE < @TODATESo I moved the derived table from the column, and set it up as a LEFT OUTER JOIN in the FROM section and now it runs great. Which makes sense (I think). When I had the table in the top as a select, it had to select all the values in the range and then compare the ASGN ID's and restrict the results on every single row. By moving it down into the FROM section, it calculated the YTD Table once and was able to just grab matching values out in under 10 sec.SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, (SELECT MAX(INV_DATE) FROM INVOICE WHERE ORD_NUM = ORD_NUM AND ASGN_ID = ASGN_ID), DATEDIFF(dd,DEL_DATE, (SELECT MAX(INV_DATE) FROM INVOICE WHERE ORD_NUM = ORD_NUM AND ASGN_ID = ASGN_ID)) , YTD.AVGDAYSFROM INVOICE LEFT OUTER JOIN ((SELECT ASGN_ID, ASGN_NAME, AVG(DATEDIFF(dd,DEL_DATE, INV_DATE)*1.0) AS AvgDaysFROM(SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, INV_DATE,ROW_NUMBER() OVER (PARTITION BY ASGN_ID, ORD_NUM ORDER BY INV_DATE DESC) AS SeqFROM INVOICE)tWHERE Seq=1 AND T.ASGN_ID = P.ASGN_IDGROUP BY ASGN_ID, ASGN_NAME)) YTDWHERE DEL_DATE >= @FROMDATE AND DEL_DATE < @TODATEThanks |
 |
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2014-01-23 : 05:41:19
|
you still have some redundant logic.i think what you want is just thisSELECT ASGN_ID, ASGN_NAME,ORD_NUM, DEL_DATE,INV_DATE,DATEDIFF(dd,DEL_DATE, INV_DATE),AVG(DATEDIFF(dd,DEL_DATE, INV_DATE)*1.0) OVER (PARTITION BY ASGN_ID, ASGN_NAME) AS AvgDaysFROM(SELECT ASGN_ID, ASGN_NAME, ORD_NUM, DEL_DATE, INV_DATE,ROW_NUMBER() OVER (PARTITION BY ASGN_ID, ORD_NUM ORDER BY INV_DATE DESC) AS SeqFROM INVOICE)tWHERE Seq=1 AND DEL_DATE >= @FROMDATE AND DEL_DATE < @TODATE ------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
 |
|
|
|
|
|
|