1

我有下表。

DECLARE @TBL_RESULT Table
(   
    ID varchar(10),
    CreateDate DateTime,
    PEOPLE_CODE_ID varchar(10), 
    CONVERSION_DATE DateTime,
    CAMPUS varchar(20),
    DAYS_TOOK int   
);

此表记录了从 2013 年 1 月 1 日至今已接收和转换的所有潜在客户的记录。

我最初需要找到转换过去 10 周内到达的潜在客户所需的中位数时间并按校园分组我能够使用下面的 SQL 查询做到这一点

WITH    CTE_RESULT
          AS ( SELECT   *
               FROM     @TBL_RESULT
               WHERE    CreateDate > DATEADD(WEEK, -10, GETDATE())
             )
    SELECT  Campus ,
            AVG(DAYS_TOOK) AS MedianTime
    FROM    ( SELECT    CAMPUS ,
                        Days_Took ,
                        ROW_NUMBER() OVER ( PARTITION BY Campus ORDER BY Days_Took ASC ) AS AgeRank ,
                        COUNT(*) OVER ( PARTITION BY CAMPUS ) AS CampusCount
              FROM      CTE_RESULT
            ) x
    WHERE   x.AgeRank IN ( x.CampusCount / 2 + 1, ( x.CampusCount + 1 ) / 2 )
    GROUP BY x.Campus   

我现在需要在图表上绘制这种趋势,即查找前 10 周的桶记录并在折线图上绘制中值 - 每条线都是一个校园。(按校区分组)

光标是我唯一的选择吗?从 1 月 1 日开始,我将在其中找到前 10 周的线索,执行上述 SQL 查询以获取中位数,将其推送到临时表,然后找到接下来的 10 周,依此类推。

或者有什么更好的我可以做的吗?

4

2 回答 2

3

在不尝试优化查询的情况下,如果您需要在多个 10 周期间产生相同的结果,您可以根据需要将当前(10 周前到今天)范围扩展到尽可能多的范围,在整个查询中线程化PeriodEndDate ,如图所示以下。

SQL小提琴

MS SQL Server 2012 架构设置

查询 1

DECLARE @TBL_RESULT Table
(   
    ID varchar(10),
    CreateDate DateTime,
    PEOPLE_CODE_ID varchar(10), 
    CONVERSION_DATE DateTime,
    CAMPUS varchar(20),
    DAYS_TOOK int   
);

-- fill the table with some dummy data from 2013-01-01
INSERT @TBL_RESULT (CreateDate, Campus, Days_Took)
SELECT DATEADD(D, A.Number, '20130101'), 'Campus' + Right(B.Number, 10),
       ABS(CAST(NEWID() AS binary(6)) % 130) + 1
FROM master..spt_values A
JOIN master..spt_values B on B.type='P' and B.number < 50 -- 50 campuses
WHERE A.type='P'
  AND DATEADD(D, A.Number, '20130101') <= GetDate();

-- This first CTE is used to create the required number of 10-week periods
WITH N(NUMBER) AS (
  SELECT 0
  union all
  select number+1 from N
  where Number <= DATEDIFF(WEEK, '20130101', GETDATE())
),
-- and from below here it's your query with the PeriodEndDate threaded through
CTE_RESULT AS (
  SELECT   DATEADD(WEEK, -Number, GETDATE()) PeriodEndDate,
           T.*
  FROM     @TBL_RESULT T
  CROSS    JOIN     N
           -- you see the range built up dynamically here
  WHERE    CreateDate > DATEADD(WEEK, -Number-10, GETDATE())
    AND    CreateDate < DATEADD(WEEK, -Number, GETDATE()) +1
)
SELECT  PeriodEndDate, Campus ,
        AVG(DAYS_TOOK) AS MedianTime
FROM    (
         SELECT PeriodEndDate,   CAMPUS ,
         Days_Took ,
         ROW_NUMBER() OVER ( PARTITION BY PeriodEndDate, Campus ORDER BY Days_Took ASC ) AS AgeRank ,
         COUNT(*) OVER ( PARTITION BY PeriodEndDate, CAMPUS ) AS CampusCount
         FROM      CTE_RESULT
        ) x
WHERE   x.AgeRank IN ( x.CampusCount / 2 + 1, ( x.CampusCount + 1 ) / 2 )
GROUP BY x.PeriodEndDate, x.Campus
ORDER BY x.PeriodEndDate, x.Campus;
于 2013-04-18T19:10:12.917 回答
0

看来你解决了问题的难点。

为了得到你想要的,你需要引入一个分组变量。在这种情况下,我测量过去的周数并除以 10(SQL Server 进行整数除法,因此这会产生一个整数)。

partition by然后您就可以在andgroup by语句中明智地使用它:

WITH CTE_RESULT AS (
       SELECT   t.*,
                DATEDIFF(week, CreateDate, GETDATE()) / 10 as groupnum
       FROM     @TBL_RESULT t
      )
SELECT Campus, groupnum, MIN(CreateDate), MAX(CreateDate),
       AVG(DAYS_TOOK) AS MedianTime
FROM (SELECT t.*,
              ROW_NUMBER() OVER (PARTITION BY groupnum, Campus ORDER BY Days_Took ASC ) AS AgeRank ,
              COUNT(*) OVER (PARTITION BY groupnum, CAMPUS) AS CampusCount
      FROM CTE_RESULT t
     ) x
WHERE x.AgeRank IN ( x.CampusCount / 2 + 1, ( x.CampusCount + 1 ) / 2 )
GROUP BY x.Campus, groupnum

我还没有测试过这个,所以它可能有一两个语法错误。

于 2013-04-18T18:20:24.230 回答