按年度对数据透视表上的多个计数进行分组

时间:2014-06-27 14:10:22

标签: sql-server

我刚开始学习SQL。我写了以下内容:

DECLARE @DateFrom Date = '01-Jan-2014', @DateTo Date = '31-Dec-2014'

SELECT TotalCalls, UniqueCalls, TotalEmails, UniqueEmails, AgentsContacted, Instructed FROM 

(   SELECT *, 

(SELECT YEAR(EventDate)) AS year,

(SELECT COUNT(*) FROM Events JOIN dbo.ContactType 
                    ON EventContactType=ContactTypeID 
                    WHERE ContactTypeName = 'Call' AND EventDate >= @DateFrom AND EventDate <= @DateTo) AS TotalCalls,

(SELECT COUNT(Distinct EventAgentID) FROM Events JOIN dbo.ContactType 
                    ON EventContactType=ContactTypeID
                     WHERE ContactTypeName = 'Call' AND EventDate >= @DateFrom AND EventDate <= @DateTo) AS UniqueCalls,

(SELECT COUNT(*) FROM Events JOIN dbo.ContactType 
                    ON EventContactType=ContactTypeID 
                    WHERE ContactTypeName = 'Email' AND EventDate >= @DateFrom AND EventDate <= @DateTo) AS TotalEmails,

(SELECT COUNT(Distinct EventAgentID) FROM Events JOIN dbo.ContactType 
                    ON EventContactType=ContactTypeID 
                    WHERE ContactTypeName = 'Email' AND EventDate >= @DateFrom AND EventDate <= @DateTo) AS UniqueEmails,

(SELECT COUNT(DISTINCT EventAgentID)
FROM Events 
JOIN dbo.ContactType 
ON EventContactType=ContactTypeID
LEFT JOIN (SELECT AgentID, (SELECT CASE WHEN AgentDateOfRecentInstruction Is Null OR 
                    AgentDateOfRecentInstruction < DATEADD(month, -12, @DateFrom) --for sp change get date to @FromDate
                    THEN 'NO' ELSE 'YES' END) AS InstructedWithinPastYear FROM Agents) ti
ON Events.EventAgentID=ti.AgentID
WHERE EventToFrom='1' 
AND (ContactTypeName = 'Email' OR ContactTypeName = 'Call')
AND InstructedWithinPastYear = 'NO'
AND (EventDate >= @DateFrom AND EventDate <= @DateTo)) AS AgentsContacted,

(SELECT COUNT(DISTINCT EventAgentID)
    FROM Events 
    Join dbo.AGents
    ON EventAgentID=AgentID
    JOIN dbo.ContactType 
    ON EventContactType=ContactTypeID
    LEFT JOIN (SELECT AgentID, (SELECT CASE WHEN AgentDateOfRecentInstruction Is Null OR 
                        AgentDateOfFirstIntsruction < @DateFrom --for sp change get date to @FromDate
                        THEN 'NO' ELSE 'YES' END) AS InstructedWithinPastYear FROM Agents) ti
    ON Events.EventAgentID=ti.AgentID
    WHERE EventToFrom='1' 
    AND (ContactTypeName = 'Email' OR ContactTypeName = 'Call')
    AND (AgentDateOfRecentInstruction <= @DateTo AND AgentDateOfRecentInstruction >= @DateFrom)
    AND (EventDate >= @DateFrom AND EventDate <= @DateTo)) AS Instructed    

    FROM Events
    JOIN dbo.ContactType 
    ON EventContactType=ContactTypeID
    Join dbo.AGents
    ON EventAgentID=AgentID
) 
as s

PIVOT (count(EventAgentID) FOR year
IN ([2013],[2014]) ) pvt

返回数千行:

TotalCalls | UniqueCalls | TotalEmails | UniqueEmails | AgentsContacted | Instructed
169        | 106     | 202         | 125          | 24              | 15
169        | 106     | 202         | 125          | 24              | 15
169        | 106     | 202         | 125          | 24              | 15

我想要它返回:

Year | TotalCalls | UniqueCalls | TotalEmails | UniqueEmails | AgentsContacted
2014 | 169        | 106         | 202         | 125      | 24
2013 | 69         | 68          | 112         | 86       | 13

我很确定我在这里犯了一些错误,但我无法简洁地写出我的问题,以便从搜索中找出解决方法。

(注意:我在编写程序时暂时存在局部变量)

1 个答案:

答案 0 :(得分:2)

您可以通过将所有内容放入一个查询语句而不是SELECT语句中的一系列单个查询来大大简化此查询。现在,你有&#34; SELECT (SELECT Blah1FROM X), (SELECT Blah2 FROM X)&#34;在那里你可以轻松地写下#34; SELECT Blah1, Blah2 FROM X&#34;有点创造力。

您的代码中存在一些导致问题的基本缺陷 - 您正在聚合每个SELECT查询中的每一行,因此您返回的数据实际上是所有记录中的计数,不是你想要的那一年。此外,您从不对结果进行分组(查找GROUP BY语句),以便您返回数千行,每个详细记录一行,而不是每年我想要的单行。

考虑编写更类似于以下内容的内容,它使用GROUP BY对单个查询进行聚合。

DECLARE @DateFrom Date = '01-Jan-2014', @DateTo Date = '31-Dec-2014'
SELECT 
    YEAR(EventDate) AS [Year],
    COUNT(CASE WHEN ContactTypeName = 'Call' THEN EventAgentID END) AS TotalCalls, -- You might need the "EventDate >= @DateFrom AND EventDate <= @DateTo" as part of this CASE statement
    COUNT(DISTINCT CASE WHEN ContactTypeName = 'Call' THEN EventAgentID END) AS UniqueCalls, 
    COUNT(CASE WHEN ContactTypeName = 'Email' THEN EventAgentID END) AS TotalEmails,
    COUNT(DISTINCT CASE WHEN ContactTypeName = 'Email' THEN EventAgentID END) AS UniqueEmails, 
    COUNT(DISTINCT 
        CASE 
            WHEN    
                EventToFrom='1' AND 
                ContactTypeName IN ('Call', 'Email') AND 
                (AgentDateOfRecentInstruction IS NULL OR  AgentDateOfRecentInstruction < DATEADD(month, -12, @DateFrom)) AND 
                (EventDate >= @DateFrom AND EventDate <= @DateTo)
            THEN EventAgentID
        END) AS AgentsContacted, 
    COUNT(DISTINCT 
        CASE 
            WHEN    
                EventToFrom='1' AND 
                ContactTypeName IN ('Call', 'Email') AND 
                AgentDateOfRecentInstruction <= @DateTo AND AgentDateOfRecentInstruction >= @DateFromAND 
                (EventDate >= @DateFrom AND EventDate <= @DateTo)
            THEN EventAgentID
        END) AS AgentsContacted

FROM 
    dbo.Events
     INNER JOIN 
    dbo.ContactType ON 
        EventContactType=ContactTypeID
     INNER JOIN 
    dbo.Agents ON 
        EventAgentID=AgentID
GROUP BY YEAR(EventDate)

缺少任何样本数据甚至是模板,我无法保证此转换无需任何调整即可 - 您可能必须使用此代码,检查拼写或语法错误,然后转到通过每个陈述,以确保它实际上做你想要的。但是,它应该让你开始。