用于计算中值和分组依据的SQL查询
我有下表用于计算中值和分组依据的SQL查询,sql,sql-server-2008,tsql,Sql,Sql Server 2008,Tsql,我有下表 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周内到达的潜在客户并
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周,依此类推
还是我能做得更好?看来你解决了问题的难点 为了得到您想要的,您需要引入一个分组变量。在本例中,我测量过去的周数,然后除以10,SQL Server会进行整数除法,因此生成一个整数 然后在partitionby和groupby语句中明智地使用它:
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
我还没有对此进行测试,因此它可能有一两个语法错误。在不优化查询的情况下,如果您需要在多个10周期间生成相同的结果,您可以根据需要将当前10周前到今天的范围扩展到任意多个范围,在整个查询中使用PeriodEndDate,如下所示 MS SQL Server 2012架构设置: 问题1:
不,这不需要光标。你能澄清你所说的“周”是什么意思吗?你是从1月1日开始,然后69天后就是10周的结束时间吗?或者周是由ISO周定义的?或者由脚本向后运行的日期定义?最初,当我编写查询时,我只需要最后10周的时间,所以我根据脚本运行的日期向后运行了10周。例如,如果脚本在4/18运行,则开始日期为02/07。@user1828125。如果你对我的答案投了反对票,为什么?实际上我没有——我按下了“向上”按钮,只是仔细检查了一下ಠ_ಠ 认真地你要买inb4徽章吗?@swasheckԾԾԾ相当奇怪至少底部的派生表中缺少groupnum。如果一个查询足够复杂,对新手来说就像魔术一样,那么一两个语法错误就越来越不可能被OP修复,答案的值也会急剧下降。@RichardTheKiwi。答案是针对提问者的。他/她似乎对SQL非常精通。我认为我在解释解决问题的方法方面做得相当好。SQL就是一个例子。@user1828125。理查德:谢谢你的回复,但我认为这并没有给我10周加起来的中位数。我预计在整个10周内,每个校园都会有一排学生。每个校园每周都没有一排。我从你的查询中得到的结果实际上是每周每个校园的中位数。结果是每10周每个校园一行。每个数据点是一个校园/10周期间的中位数,这是您最初拥有的。例如,如果说今天结束的校园A时段中位数为100,则意味着今天结束的校园A的10周时段中位数为100。Richard-您建议的解决方案实际上是将中位数移动一周,然后计算10周。很抱歉,我原来的问题没有澄清这一点。但我实际上也要做另一份关于移动中间值的报告,所以你们实际上已经回答了我的第二个问题。再次感谢你!
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;