sql server 2014 group by date提取了几个字段

时间:2016-05-04 18:58:54

标签: sql-server datetime group-by

我有一个看起来像这样的表:

email

我需要在图表上显示信息,我需要按日期分组。

因此,如果我想按特定广告系列的ReadOn字段对详细信息进行分组,我会构建以下查询

Simple Registration - Joomla!

但我想在同一个查询中提取不仅是ReadOn字段,而且还提取其他字段,如ETS,ATS,Unsubscribed / Read&未读和退回

并得到类似的东西

CREATE TABLE dbo.Mails (
  ID int IDENTITY(1, 1) NOT NULL,
  Reference nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
  Email nvarchar(70) NOT NULL,
  ETS datetime NULL, --Estimated Time of Shipping
  ATS datetime NULL, --Actual Time of Shipping
  ReadOn datetime NULL,
  Unsubscribed datetime NULL,
  Bounced datetime NULL,
  BouncedReason nvarchar(30) COLLATE Latin1_General_CI_AS NULL,
  Active bit DEFAULT 1 NULL
)

是否有比构建6个不同查询更简单的方法?

至少可以指明要遵循的路径吗?

由于

2 个答案:

答案 0 :(得分:2)

你可以通过一些预处理和PIVOT来做到这一点。在这个例子中,我将查询放入存储过程中,以便包含它并且易于测试。我正在CTE中进行预处理,以保持主要查询的整洁。

首先,创建表并填充它。

CREATE TABLE dbo.Mails
(
    ID int IDENTITY(1, 1) NOT NULL,
    Reference nvarchar(20) COLLATE Latin1_General_CI_AS NULL,
    ETS datetime NULL, --Estimated Time of Shipping
    ATS datetime NULL, --Actual Time of Shipping
    ReadOn datetime NULL,
    Unsubscribed datetime NULL,
    Bounced bit DEFAULT 0 NULL,
    BouncedReason nvarchar(30) COLLATE Latin1_General_CI_AS NULL,
    Active bit DEFAULT 1 NULL
);
GO

INSERT INTO dbo.Mails (Reference, ETS, ATS, ReadOn, Unsubscribed, Bounced)
    VALUES
        (N'ABC', '2015-05-05', '2015-05-05', '2015-05-05', NULL, 0),
        (N'ABC', '2015-05-06', '2015-05-07', '2015-05-08', NULL, 0),
        (N'ABC', '2015-05-05', '2015-05-05', '2015-05-07', NULL, 0),
        (N'ABC', '2015-05-07', '2015-05-08', '2015-05-09', NULL, 0),
        (N'ABC', '2015-05-06', '2015-05-07', '2015-05-09', '2015-05-09', 0),
        (N'ABC', '2015-05-06', '2015-05-07', NULL, '2015-05-08', 0);

然后使用参数@Reference创建存储过程。我正在使用CTE创建一个两列行集,其中Date和Type作为列。然后,在主SELECT语句中,它将被旋转以提供您想要的结果。

CTE产生的行集如下所示。

enter image description here

注意:我没有包括Bounced列,因为我不清楚它的要求是什么;它不是日期列。但是,你应该能够很容易地扩展这个例子。

CREATE PROCEDURE dbo.up_ReportMails
(
    @Reference nvarchar(20)
)
AS
WITH cte AS
(
    SELECT CAST(ReadOn AS date) AS 'Date', 'R' AS 'Type'
        FROM dbo.Mails
        WHERE Reference = @Reference AND ReadOn IS NOT NULL
    UNION ALL
    SELECT CAST(ETS AS date), 'E'
        FROM dbo.Mails
        WHERE Reference = @Reference AND ETS IS NOT NULL
    UNION ALL
    SELECT CAST(ATS AS date), 'A'
        FROM dbo.Mails
        WHERE Reference = @Reference AND ATS IS NOT NULL
    UNION ALL
    SELECT CAST(Unsubscribed AS date), 'U'
        FROM dbo.Mails
        WHERE Reference = @Reference AND UNSUBSCRIBED IS NOT NULL AND ReadOn IS NOT NULL
    UNION ALL
    SELECT CAST(Unsubscribed AS date), 'V'
        FROM dbo.Mails
        WHERE Reference = @Reference AND UNSUBSCRIBED IS NOT NULL AND ReadOn IS NULL
)
SELECT [Date], [R] AS 'Read', [E] AS 'ETS', [A] AS 'ATS', [U] AS 'Unsub/Read', [V] As 'Unsub/Unread'
    FROM
        (SELECT [Date], [Type]
            FROM cte) AS C
    PIVOT
    (
        COUNT([Type])
        FOR [Type] IN ([R], [E], [A], [U], [V])
    ) AS PivotTable
    ORDER BY [Date];

然后我们可以测试它。

EXEC dbo.up_ReportMails @Reference=N'ABC';

enter image description here

答案 1 :(得分:0)

我已经测试了这段代码,但它确实有用。假设你有一个日历表(如果你没有日历表,你可以谷歌它并在大约10分钟内制作一个 - 它们非常简单并且可以节省你的时间):

DECLARE @StartDate date = '01/01/2016'
DECLARE @EndDate date = '05/06/2016'

SELECT  C.BaseDate,
        ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ETS AS DATE) THEN 1 END), 0) AS [ETS],
        ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ATS AS DATE) THEN 1 END), 0) AS [ATS],
        ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.ReadOn AS DATE) THEN 1 END), 0) AS [Read On],
        ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.Unsubscribed AS DATE) THEN 1 END), 0) AS [Unsubscribed],
        ISNULL(SUM(CASE WHEN C.BaseDate = CAST(M.Bounced AS DATE) THEN 1 END), 0) AS [Bounced]
FROM Calendar C
LEFT OUTER JOIN Mails M
    ON C.BaseDate = CAST(M.ETS AS DATE)
    OR C.BaseDate = CAST(M.ATS AS DATE)
    OR C.BaseDate = CAST(M.ReadOn AS DATE)
    OR C.BaseDate = CAST(M.Unsubscribed AS DATE)
    OR C.BaseDate = CAST(M.Bounced AS DATE)
WHERE C.BaseDate BETWEEN @StartDate AND @EndDate
GROUP BY C.BaseDate

基本上您正在做的是在日期范围内从日历表中选择每个日期,然后在任何日期时间与该日期匹配时将其加入到您的邮件表中。左连接的目的是使结果集中仍返回未发生任何事情的日期。它们都将为零,但它的一致性更好,如果有人想从您的报告中计算平均值。

一旦你拥有所有日期 - 以及所有具有匹配日期时间的记录,你只需要计算每个日期有多少匹配的ETS,有多少匹配的ATS,依此类推等等。最后,您按日历日期分组并完成所有操作。