使用 Rollup 从 SQL 服务器中的 mm/dd/yyyy 获取每月和每年的计数值

Get monthy and yearly count value from mm/dd/yyyy in SQL Server using Rollup

我有一个数据库 table,如下所示,有超过 100000 条记录:

我正在尝试对此实施汇总查询,以便我可以检索特定项目的记录并按月显示数量。

我有 15 列的超过 100000 条记录。目前它是基于 select 查询迭代检索按年然后按月计算总和。我想用rollup来加快检索速度。

你只需要做条件聚合:

DECLARE @fromYear   INT = 2010,
        @toYear     INT = 2014

DECLARE @fromDate   DATE,
        @toDate     DATE

-- Generate date range based on @fromYear and @toYear
SELECT
    @fromDate = DATEADD(YEAR, @fromYear - 1900, 0),
    @toDate   = DATEADD(YEAR, @toYear - 1900 + 1, 0)

SELECT
    YEAR(soldDate), 
    [Jan] = SUM(CASE WHEN MONTH(soldDate) = 1  THEN quantity ELSE 0 END),
    [Feb] = SUM(CASE WHEN MONTH(soldDate) = 2  THEN quantity ELSE 0 END),
    [Mar] = SUM(CASE WHEN MONTH(soldDate) = 3  THEN quantity ELSE 0 END),
    [Apr] = SUM(CASE WHEN MONTH(soldDate) = 4  THEN quantity ELSE 0 END),
    [May] = SUM(CASE WHEN MONTH(soldDate) = 5  THEN quantity ELSE 0 END),
    [Jun] = SUM(CASE WHEN MONTH(soldDate) = 6  THEN quantity ELSE 0 END),
    [Jul] = SUM(CASE WHEN MONTH(soldDate) = 7  THEN quantity ELSE 0 END),
    [Aug] = SUM(CASE WHEN MONTH(soldDate) = 8  THEN quantity ELSE 0 END),
    [Sep] = SUM(CASE WHEN MONTH(soldDate) = 9  THEN quantity ELSE 0 END),
    [Oct] = SUM(CASE WHEN MONTH(soldDate) = 10 THEN quantity ELSE 0 END),
    [Nov] = SUM(CASE WHEN MONTH(soldDate) = 11 THEN quantity ELSE 0 END),
    [Dec] = SUM(CASE WHEN MONTH(soldDate) = 12 THEN quantity ELSE 0 END)
FROM tbl
WHERE
    item = 'basketball'
    AND soldDate >= @fromDate
    AND soldDate < @toDate
GROUP BY YEAR(soldDate)

如果你想显示所有年份,包括那些有 0 件商品的年份,你需要先生成所有这些年份。您可以使用计数 table 来做到这一点。然后结果将 LEFT JOINed 到上面的原始查询:

DECLARE @fromYear   INT = 2010,
        @toYear     INT = 2014

DECLARE @fromDate   DATE,
        @toDate     DATE

-- Generate date range based on @fromYear and @toYear
SELECT
    @fromDate = DATEADD(YEAR, @fromYear - 1900, 0),
    @toDate   = DATEADD(YEAR, @toYear - 1900 + 1, 0)

;WITH E1(N) AS(
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
CteTally(N) AS(
    SELECT TOP(@toYear - @fromYear) 
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
    FROM E4
),
CteAgg AS(
    SELECT
        [Yr]  = YEAR(soldDate),
        [Jan] = SUM(CASE WHEN MONTH(soldDate) = 1  THEN quantity ELSE 0 END),
        [Feb] = SUM(CASE WHEN MONTH(soldDate) = 2  THEN quantity ELSE 0 END),
        [Mar] = SUM(CASE WHEN MONTH(soldDate) = 3  THEN quantity ELSE 0 END),
        [Apr] = SUM(CASE WHEN MONTH(soldDate) = 4  THEN quantity ELSE 0 END),
        [May] = SUM(CASE WHEN MONTH(soldDate) = 5  THEN quantity ELSE 0 END),
        [Jun] = SUM(CASE WHEN MONTH(soldDate) = 6  THEN quantity ELSE 0 END),
        [Jul] = SUM(CASE WHEN MONTH(soldDate) = 7  THEN quantity ELSE 0 END),
        [Aug] = SUM(CASE WHEN MONTH(soldDate) = 8  THEN quantity ELSE 0 END),
        [Sep] = SUM(CASE WHEN MONTH(soldDate) = 9  THEN quantity ELSE 0 END),
        [Oct] = SUM(CASE WHEN MONTH(soldDate) = 10 THEN quantity ELSE 0 END),
        [Nov] = SUM(CASE WHEN MONTH(soldDate) = 11 THEN quantity ELSE 0 END),
        [Dec] = SUM(CASE WHEN MONTH(soldDate) = 12 THEN quantity ELSE 0 END)
    FROM tbl t
    WHERE
        item = 'basketball'
        AND soldDate >= @fromDate
        AND soldDate < @toDate
    GROUP BY YEAR(soldDate)
)
SELECT
    [Yr] = (@fromYear + t.N - 1),
    [Jan] = ISNULL([Jan], 0),
    [Feb] = ISNULL([Feb], 0),
    [Mar] = ISNULL([Mar], 0),
    [Apr] = ISNULL([Apr], 0),
    [May] = ISNULL([May], 0),
    [Jun] = ISNULL([Jun], 0),
    [Jul] = ISNULL([Jul], 0),
    [Aug] = ISNULL([Aug], 0),
    [Sep] = ISNULL([Sep], 0),
    [Oct] = ISNULL([Oct], 0),
    [Nov] = ISNULL([Nov], 0),
    [Dec] = ISNULL([Dec], 0)
FROM CteTally t
LEFT JOIN CteAgg a
    ON (@fromYear + t.N - 1) = a.Yr
ORDER BY (@fromYear + t.N - 1)
DROP TABLE tbl

ONLINE DEMO