复杂查询的逻辑,涉及在SQL中进行分组和平均

时间:2013-06-26 16:27:54

标签: sql sql-server

我有2张桌子 以下是我需要遵循以获得所需输出的步骤。我可以跟进第3步。请帮助我,因为它有点复杂,我无法理解如何继续前进。

表1

Site  Code FailFlag  Comments  ModifiedDate  ModifiedBy
ABT   A01     F      Dfasdf    10/11/2011    Anna
ABT   A01     F      dsfsdf    15/12/2012    Mand
ABT   A01            Rds       30/03/2011    Tim
ABT   A01            GHDs      02/12/2012    Andy
ABT   A02     F      dfd       09/05/2012    Anna
ABT   A02            sdada     11/02/2013    Kathy
ABT   A02            Dfg       15/05/2011    Rob
AFL   A02     F      asda      13/02/2011    Dan
AFL   A02            dsaa      24/12/2010    Ryan
TRG   A01            sdasd     16/04/2010    Richard
TRG   K05            jksdh     23/04/2012    Mark
KLD   K05     F      sd        18/05/2013    Jim
KLD   K05            dsfsd     10/03/2012    James
KLD   K05            sdsd      12/05/2011    Luther
KTY   K05     F      saq       09/09/2012    Ryan
KTY   K05            asd       04/04/2010    Kathy
KMD   C02     F      nas       29/02/2012    Rob
KMD   C02            asda      11/11/2011    Andy

表2:

Site  Code   Freq     StartDate   EndDate
ABT   A01    43       01/01/2011  01/02/2012
ABT   A02    254      01/01/2011  19/02/2011
ABT   A02    109      20/02/2011  01/01/2012
ABT   A02    12       02/01/2012  01/01/2013
AFL   A02    13       01/01/2011  01/02/2012
TRG   A01    122      01/01/2011  01/02/2012
TRG   K05    61       01/01/2011  01/02/2012
KLD   KO5    33       01/01/2011  15/05/2012
KLD   K05    79       16/05/2012  01/01/2013
KTY   K05    52       01/01/2011  01/02/2012
KMD   C02    78       01/01/2011  01/02/2012
ZYT   G01    11       01/01/2011  01/02/2012
PYN   A01    15       01/01/2011  01/02/2012
DYN   F08    122      01/01/2011  01/02/2012

步骤:

  1. 表1中两列“网站”和“代码”的组合将在Tabel2中查看“网站”和“代码”列的组合。

  2. 在“失败”列中过滤相同的内容并找出失败次数

    以下是查询和输出:

    SELECT Site,Code,COUNT(*) as [Count],
    FailFlagCount= SUM(CASE WHEN F = 'F' THEN 1 ELSE 0 END) FROM Table1 
    GROUP BY Site,Det
    
    
    Site Code    Count   FailFlagCount
    ABT   A01     4      2
    ABT   A02     3      1
    AFL   A02     2      1
    TRG   A01     1      0
    TRG   K05     1      0      
    KLD   KO5     3      1
    KTY   K05     2      1
    KMD   C02     2      1
    
  3. 我们检查表2中的相同组合。即,步骤2输出的站点和代码在表2中查看以获得其频率

  4. 计算:

    一个。 CC%= [1-(失败数/计数)] * 100 = [1-(2/4)] * 100

    湾B.P.O%= [1-(FailCount / Freq)] * 100 = [1-(2/43)] * 100

    c.Forecast%=

    让我们假设当前月份是3月。

    计算过去3年的失败次数并找出平均值,假设为“X”。
    计算剩余月份的失败,'Y'=(X *剩余月数/ 12)
    超过12个月的总失败=当前失败+ Y

    因此预测%= [1-(超过12个月/频率的总故障)] * 100。

    对于我们的例子,让我们假设X = 2的值 因此Y =(2 * 9/12)

    预测%= [1-(1 + 1.5)] * 100

  5. 上述计算将针对网站和代码的所有可能组合进行。

    Site    Code    CC  B.P.O   Forecast   StartDate    EndDate
    ABT   A01                                  01/01/2011  01/02/2012
    ABT   A02                                  01/01/2011  19/02/2011
    ABT   A02                                  20/02/2011  01/01/2012
    ABT   A02                                  02/01/2012  01/01/2013
    AFL   A02                                  01/01/2011  01/02/2012
    TRG   A01                                  01/01/2011  01/02/2012
    TRG   K05                                  01/01/2011  01/02/2012
    KLD   K05                                  01/01/2011  15/05/2012
    KLD   K05                                  16/05/2012  01/01/2013
    KTY   K05                                  01/01/2011  01/02/2012
    KMD   C02                                  01/01/2011  01/02/2012
    
  6. 上表的分组是在网站类型上完成的,即网站的首字母。 然后在分组后完成所有计算(cc,BPO,预测)的平均值 例如: - 'A'代表'ABT','T'代表'TRG'。 (我假设我们要么为多种类型创建多个表,然后进行联合以获得以下查询)
    示例: -

    Site     Code                             CC     B.P.O    Forecast          
     A    A01  
     A    A02 
        [i.e.,Avg value of (ABT and A02) 
             and (AFL and A02)]  
     T    A01 
     T    K05 avg
        [i.e., Avg value of (KLD and K05) 
             and (KTY and K05)]  
     K    K05 
     K    C02 
    
  7. 这应该是我的最终输出。请帮助。

    添加表格的脚本以便于提供帮助:

    表1脚本:

    CREATE TABLE Table1
        (
        ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
        Site VARCHAR(5),
        Code VARCHAR(5),
        FailFlag CHAR(1),
        Comments VARCHAR(100),
        ModifiedDate  DATETIME,
        ModifiedBy   VARCHAR(50)
        );
    
    INSERT INTO Table1 
          (Site,  Code,  FailFlag, Comments, ModifiedDate, ModifiedBy)
    SELECT 'ABT', 'A01',   'F',    'Dfasdf', '10/11/2011', 'Anna'    UNION ALL
    SELECT 'ABT', 'A01',   'F',    'dsfsdf', '15/12/2012', 'Mand'    UNION ALL
    SELECT 'ABT', 'A01',   NULL,   'Rds',    '30/03/2011', 'Tim'     UNION ALL
    SELECT 'ABT', 'A01',   NULL,   'GHDs',   '02/12/2012', 'Andy'    UNION ALL
    SELECT 'ABT', 'A02',   'F',    'dfd',    '09/05/2012', 'Anna'    UNION ALL
    SELECT 'ABT', 'A02',   NULL,   'sdada',  '11/02/2013', 'Kathy'   UNION ALL
    SELECT 'ABT', 'A02',   NULL,   'Dfg',    '15/05/2011', 'Rob'     UNION ALL
    SELECT 'AFL', 'A02',   'F',    'asda',   '13/02/2011', 'Dan'     UNION ALL
    SELECT 'AFL', 'A02',   NULL,   'dsaa',   '24/12/2010', 'Ryan'    UNION ALL
    SELECT 'TRG', 'A01',   NULL,   'sdasd',  '16/04/2010', 'Richard' UNION ALL
    SELECT 'TRG', 'K05',   NULL,   'jksdh',  '23/04/2012', 'Mark'    UNION ALL
    SELECT 'KLD', 'K05',   'F',    'sd',     '18/05/2013', 'Jim'     UNION ALL
    SELECT 'KLD', 'K05',   NULL,   'dsfsd',  '10/03/2012', 'James'   UNION ALL
    SELECT 'KLD', 'K05',   NULL,   'sdsd',   '12/05/2011', 'Luther'  UNION ALL
    SELECT 'KTY', 'K05',   'F',    'saq',    '09/09/2012', 'Ryan'    UNION ALL
    SELECT 'KTY', 'K05',   NULL,   'asd',    '04/04/2010', 'Kathy'   UNION ALL
    SELECT 'KMD', 'C02',   'F',    'nas',    '29/02/2012', 'Rob'     UNION ALL
    SELECT 'KMD', 'C02',   NULL,   'asda',   '11/11/2011', 'Andy';
    

    表2脚本:

    CREATE TABLE Table2
        (
        ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
        Site VARCHAR(5),
        Code VARCHAR(5),
        Freq  int,
        StartDate  DATETIME,
        EndDate  DATETIME
        );
    
    INSERT INTO Table2 (Site, Code, Freq, StartDate, EndDate)
    SELECT 'ABT', 'A01', 43,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'ABT', 'A02', 254, '01/01/2011', '19/02/2011' UNION ALL
    SELECT 'ABT', 'A02', 109, '20/02/2011', '01/01/2012' UNION ALL
    SELECT 'ABT', 'A02', 12,  '02/01/2012', '01/01/2013' UNION ALL
    SELECT 'AFL', 'A02', 13,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'TRG', 'A01', 122, '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'TRG', 'K05', 61,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'KLD', 'KO5', 33,  '01/01/2011', '15/05/2012' UNION ALL
    SELECT 'KLD', 'K05', 79,  '16/05/2012', '01/01/2013' UNION ALL
    SELECT 'KTY', 'K05', 52,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'KMD', 'C02', 78,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'ZYT', 'G01', 11,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'PYN', 'A01', 15,  '01/01/2011', '01/02/2012' UNION ALL
    SELECT 'DYN', 'F08', 122, '01/01/2011', '01/02/2012';
    

1 个答案:

答案 0 :(得分:1)

“有点复杂。”是。

从顶部开始,这是你的第2步。 这可能有一个关键的缺陷,因为它不会限制任何过去3年或过去12个月。从你的问题中不清楚这是意图,所以我们将使用它。

SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site,Code;

需要将其与Table2连接以获取频率字段。我已经将它包装在子选择中并调用该子查询S2,因为它是第2步。

SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, Table2.Freq
FROM
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site,Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
;

然后计算CC和BPO相对容易。以上是一个名为S3的子查询。

请注意,我在这里阻止了零除错。

SELECT Site, Code, [Count], FailFlagCount, Freq,
CASE WHEN [Count]=0 THEN 0 ELSE  ( 1-(FailFlagCount / [Count]))*100 END  CC,
CASE WHEN Freq = 0 THEN 0 ELSE ( 1-(FailFlagCount / Freq))*100 END BPO

FROM
(
SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, ISNULL(Table2.Freq, 1) AS Freq
FROM   
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site,Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
) s3
;

好的,这里有一些实验,围绕SQL月份函数,如何计算剩下几个月,以及今年1月。

select GETDATE(), month(GETDATE()), 12-MONTH(GETDATE()),
DATEADD(YEAR, -3, GETDATE()),
DATEFROMPARTS (YEAR(GETDATE()),1,1)
;

所以现在我们可以计算Y数 - 这是表1的整体,但过滤了过去36个月,然后计算月平均值。当你在月中运行时,隐含的错误可能会在这里蔓延 - 它不会在月份边界上破坏,它将在过去的3年内完成,而不是在本月之外的最后36个完成月份。

请注意,我必须将count(*)转换为浮点数,否则它是一个整数,在除法中将其舍入为0。

SELECT SITE, CODE, count(*) tot, cast(count(*) as float)/36 avg, (cast(count(*) as float)/36) * ((12-MONTH(GETDATE()))/12) Y
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEADD(YEAR, -3, GETDATE())
GROUP BY SITE, CODE;

我们今年以同样的方式计算失败。

SELECT SITE, CODE, COUNT(*) currFails 
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEFROMPARTS (YEAR(GETDATE()),1,1)
GROUP BY SITE, CODE;

所以现在我们可以结合以上3个步骤来获得一个Y表,当前年份失败。注意那里的ISNULL有LEFT JOIN来补偿今年没有失败的网站。

SELECT s3.Site, s3.Code, [Count], FailFlagCount, Freq,
CASE WHEN [Count]=0 THEN 0 ELSE  ( 1-(FailFlagCount / [Count]))*100 END  CC,
CASE WHEN Freq = 0 THEN 0 ELSE ( 1-(FailFlagCount / Freq))*100 END BPO,
ISNULL(YBIt.Y, 0) Y,
isnull(currBit.currFails, 0) as currFails

FROM
(
SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, ISNULL(Table2.Freq, 1) AS Freq
FROM   
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site,Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
) s3

LEFT JOIN
(
SELECT SITE, CODE, count(*) tot, cast(count(*) as float)/36 avg, (cast(count(*) as float)/36) * ((12-MONTH(GETDATE()))/12) Y
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEADD(YEAR, -3, GETDATE())
GROUP BY SITE, CODE
) YBit on S3.Site = Ybit.site AND S3.code = YBit.code 

LEFT JOIN
(
SELECT SITE, CODE, COUNT(*) currFails 
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEFROMPARTS (YEAR(GETDATE()),1,1)
GROUP BY SITE, CODE
) currBit ON s3.site = currBit.site and s3.code = currBit.code;

;

所以我们最终可以计算预测。

SELECT Site, code, [Count], FAilFlagCount, Freq,
   CC, BPO, Y, currFails, Y+currFails totF12,
    CASE WHEN Freq = 0 then 0 else (1-(( Y+currFails)/ Freq))*100 END Forecast
 FROM 
(
SELECT s3.Site, s3.Code, [Count], FailFlagCount, Freq,
CASE WHEN [Count]=0 THEN 0 ELSE  ( 1-(FailFlagCount / [Count]))*100 END  CC,
CASE WHEN Freq = 0 THEN 0 ELSE ( 1-(FailFlagCount / Freq))*100 END BPO,
ISNULL(YBIt.Y, 0) Y,
isnull(currBit.currFails, 0) as currFails

FROM
(
SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, ISNULL(Table2.Freq, 1) AS Freq
FROM   
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site, Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
) s3

LEFT JOIN
(
SELECT SITE, CODE, count(*) tot, cast(count(*) as float)/36 avg, (cast(count(*) as float)/36) * ((12-MONTH(GETDATE()))/12) Y
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEADD(YEAR, -3, GETDATE())
GROUP BY SITE, CODE
) YBit on S3.Site = Ybit.site AND S3.code = YBit.code 

LEFT JOIN
(
SELECT SITE, CODE, COUNT(*) currFails 
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEFROMPARTS (YEAR(GETDATE()),1,1)
GROUP BY SITE, CODE
) currBit ON s3.site = currBit.site and s3.code = currBit.code

) S4A
;

好的,我们突然又需要开始日期和结束日期。它们位于表2中,它似乎也可能是Site + Code的主列表。因此,让我们使用左连接进行初始化并将计算加入到计算中。我们还将计算网站类型。

这是您对每个网站+代码的详细计算。

select left (t2.site, 1) siteType, t2.site, t2.code, 
  [Count], FAilFlagCount, s4.Freq,
   CC, BPO, Forecast,
    T2.StartDate, T2.EndDAte

FROM 
 Table2 T2 
LEFT JOIN
(

SELECT Site, code, [Count], FAilFlagCount, Freq,
   CC, BPO, Y, currFails, Y+currFails totF12,
    CASE WHEN Freq = 0 then 0 else (1-(( Y+currFails)/ Freq))*100 END Forecast
 FROM 
(
SELECT s3.Site, s3.Code, [Count], FailFlagCount, Freq,
CASE WHEN [Count]=0 THEN 0 ELSE  ( 1-(FailFlagCount / [Count]))*100 END  CC,
CASE WHEN Freq = 0 THEN 0 ELSE ( 1-(FailFlagCount / Freq))*100 END BPO,
ISNULL(YBIt.Y, 0) Y,
isnull(currBit.currFails, 0) as currFails

FROM
(
SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, ISNULL(Table2.Freq, 1) AS Freq
FROM   
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site, Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
) s3

LEFT JOIN
(
SELECT SITE, CODE, count(*) tot, cast(count(*) as float)/36 avg, (cast(count(*) as float)/36) * ((12-MONTH(GETDATE()))/12) Y
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEADD(YEAR, -3, GETDATE())
GROUP BY SITE, CODE
) YBit on S3.Site = Ybit.site AND S3.code = YBit.code 

LEFT JOIN
(
SELECT SITE, CODE, COUNT(*) currFails 
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEFROMPARTS (YEAR(GETDATE()),1,1)
GROUP BY SITE, CODE
) currBit ON s3.site = currBit.site and s3.code = currBit.code

) S4A
) S4 
on t2.site = s4.site and t2.code = s4.code
;

从那里,我们可以轻松创建平均值。

SELECT siteType, '' as site, '' as code, avg([count]) [count], avg(FailFlagCount) FailFlagCount, avg(Freq) Freq, 
    avg (CC) CC, avg(BPO) BPO, avg(Forecast) Forecast, '' StartDAte, '' EndDate
FROM 
(

select left (t2.site, 1) siteType, t2.site, t2.code, 
  [Count], FAilFlagCount, s4.Freq,
   CC, BPO, Forecast,
    T2.StartDate, T2.EndDAte

FROM 
 Table2 T2 
LEFT JOIN
(

SELECT Site, code, [Count], FAilFlagCount, Freq,
   CC, BPO, Y, currFails, Y+currFails totF12,
    CASE WHEN Freq = 0 then 0 else (1-(( Y+currFails)/ Freq))*100 END Forecast
 FROM 
(
SELECT s3.Site, s3.Code, [Count], FailFlagCount, Freq,
CASE WHEN [Count]=0 THEN 0 ELSE  ( 1-(FailFlagCount / [Count]))*100 END  CC,
CASE WHEN Freq = 0 THEN 0 ELSE ( 1-(FailFlagCount / Freq))*100 END BPO,
ISNULL(YBIt.Y, 0) Y,
isnull(currBit.currFails, 0) as currFails

FROM
(
SELECT s2.Site, s2.Code,s2.[Count], S2.FailFlagCount, ISNULL(Table2.Freq, 1) AS Freq
FROM   
(
SELECT Site,Code,COUNT(*) as [Count],
FailFlagCount= SUM(CASE WHEN FailFlag = 'F' THEN 1 ELSE 0 END)
FROM Table1 
GROUP BY Site, Code
) S2
LEFT JOIN Table2 on S2.Site = table2.Site and S2.Code = table2.Code
) s3

LEFT JOIN
(
SELECT SITE, CODE, count(*) tot, cast(count(*) as float)/36 avg, (cast(count(*) as float)/36) * ((12-MONTH(GETDATE()))/12) Y
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEADD(YEAR, -3, GETDATE())
GROUP BY SITE, CODE
) YBit on S3.Site = Ybit.site AND S3.code = YBit.code 

LEFT JOIN
(
SELECT SITE, CODE, COUNT(*) currFails 
FROM Table1 
WHERE FailFlag = 'F'
AND ModifiedDate >= DATEFROMPARTS (YEAR(GETDATE()),1,1)
GROUP BY SITE, CODE
) currBit ON s3.site = currBit.site and s3.code = currBit.code

) S4A
) S4 
on t2.site = s4.site and t2.code = s4.code
) S5
GROUP BY siteType
;

或者您可以使用详细计算填充表格,然后计算平均值,而不是使用我的最终计算。

我会把最后的工会留给你。