Sql server 获取SQL动态(日历)数据透视表的总计

Sql server 获取SQL动态(日历)数据透视表的总计,sql-server,pivot-table,dynamic-tables,Sql Server,Pivot Table,Dynamic Tables,我正在尝试使用SQL Server动态透视表,该表允许我计算列数,然后求和列数。透视表的目的是创建一个报告,其中包括个人在一个城市停留的所有天数以及总天数(一个月内)。因此,例如,人员A在6月份每天都会停留-总数将为30。人员B仅在6月3日开始停留-总数将为27等。数据表仅包含姓名、ArriveDate、DepartDate…通过SQL查询创建当月的天数 +------+------------+------------+-------+-------+-------+-----+------

我正在尝试使用SQL Server动态透视表,该表允许我计算列数,然后求和列数。透视表的目的是创建一个报告,其中包括个人在一个城市停留的所有天数以及总天数(一个月内)。因此,例如,人员A在6月份每天都会停留-总数将为30。人员B仅在6月3日开始停留-总数将为27等。数据表仅包含姓名、ArriveDate、DepartDate…通过SQL查询创建当月的天数

+------+------------+------------+-------+-------+-------+-----+-------+-------+-------+
|姓名|到达日期|出发日期| 06-01 | 06-02 | 06-03 |……|06-29 | 06-30 |总计|
+------+------------+------------+-------+-------+-------+-----+-------+-------+-------+
|A | 2014-06-01 | 2014-06-23 | 1 | 1 | 1 |……|1 |     1 |    30 |
|B | 2014-06-02 | 2014-06-23 | 0 | 1 | 1 |……|1 |     1 |    27 |
|C | 2014-06-02 | 2014-06-23 | 0 | 0 | 0 |……|1 |     1 |    16 |

+------+------------+------------+-------+-------+-------+-----+-------+-------+-------+
以下是我使用动态交叉表的尝试:

样本数据:

Name ArriveDate DepartDate
---- ---------- ----------
A    2015-07-01 2015-07-23
B    2015-07-02 2015-07-04
C    2015-07-03 2015-07-31
动态交叉表解决方案:

DECLARE @minDate AS DATE,
        @maxDate AS DATE

SELECT  @minDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1)),
        @maxDate = EOMONTH(GETDATE())

CREATE TABLE #dates(dt DATE)

DECLARE @sql1 VARCHAR(MAX) = '',
        @sql2 VARCHAR(MAX) = '',
        @sql3 VARCHAR(MAX) = '';

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),
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b),
Tally(N) AS(
    SELECT TOP(DATEDIFF(DAY, @minDate, @maxDate) + 1)
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM E8
)
INSERT INTO #dates
    SELECT DATEADD(DAY, N - 1, @minDate)
    FROM Tally

SELECT @sql1 =
'SELECT
    r.Name
    , r.ArriveDate
    , r.DepartDate' + CHAR(10)

SELECT @sql2 = @sql2 +
'   , SUM(CASE WHEN d.dt = CAST(''' + CONVERT(VARCHAR(8), dt, 112) + ''' AS DATE) THEN 1 ELSE 0 END) AS ' 
    + QUOTENAME(CONVERT(VARCHAR(10), dt, 120)) + CHAR(10)
FROM #dates
ORDER BY dt

SELECT @sql2 = @sql2 +
'   , COUNT(d.dt) AS [total]' + CHAR(10)

SELECT @sql3 =
'FROM Reservation r
LEFT JOIN #dates d
    ON d.dt BETWEEN r.ArriveDate AND r.DepartDate
GROUP BY
    r.Name, r.ArriveDate, r.DepartDate'

PRINT (@sql1 + @sql2 + @sql3)
EXEC (@sql1 + @sql2 + @sql3)

DROP TABLE #dates
结果:

Name ArriveDate DepartDate 2015-07-01  2015-07-02  2015-07-03  ..... 2015-07-29  2015-07-30  2015-07-31  total
---- ---------- ---------- ----------- ----------- ----------- ..... ----------- ----------- ----------- -----------
A    2015-07-01 2015-07-23 1           1           1           ..... 0           0           0           23
B    2015-07-02 2015-07-04 0           1           1           ..... 0           0           0           3
C    2015-07-03 2015-07-31 0           0           1           ..... 1           1           1           29

以下是我使用动态交叉表的尝试:

样本数据:

Name ArriveDate DepartDate
---- ---------- ----------
A    2015-07-01 2015-07-23
B    2015-07-02 2015-07-04
C    2015-07-03 2015-07-31
动态交叉表解决方案:

DECLARE @minDate AS DATE,
        @maxDate AS DATE

SELECT  @minDate = DATEADD(DAY, 1, EOMONTH(GETDATE(), -1)),
        @maxDate = EOMONTH(GETDATE())

CREATE TABLE #dates(dt DATE)

DECLARE @sql1 VARCHAR(MAX) = '',
        @sql2 VARCHAR(MAX) = '',
        @sql3 VARCHAR(MAX) = '';

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),
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b),
Tally(N) AS(
    SELECT TOP(DATEDIFF(DAY, @minDate, @maxDate) + 1)
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
    FROM E8
)
INSERT INTO #dates
    SELECT DATEADD(DAY, N - 1, @minDate)
    FROM Tally

SELECT @sql1 =
'SELECT
    r.Name
    , r.ArriveDate
    , r.DepartDate' + CHAR(10)

SELECT @sql2 = @sql2 +
'   , SUM(CASE WHEN d.dt = CAST(''' + CONVERT(VARCHAR(8), dt, 112) + ''' AS DATE) THEN 1 ELSE 0 END) AS ' 
    + QUOTENAME(CONVERT(VARCHAR(10), dt, 120)) + CHAR(10)
FROM #dates
ORDER BY dt

SELECT @sql2 = @sql2 +
'   , COUNT(d.dt) AS [total]' + CHAR(10)

SELECT @sql3 =
'FROM Reservation r
LEFT JOIN #dates d
    ON d.dt BETWEEN r.ArriveDate AND r.DepartDate
GROUP BY
    r.Name, r.ArriveDate, r.DepartDate'

PRINT (@sql1 + @sql2 + @sql3)
EXEC (@sql1 + @sql2 + @sql3)

DROP TABLE #dates
结果:

Name ArriveDate DepartDate 2015-07-01  2015-07-02  2015-07-03  ..... 2015-07-29  2015-07-30  2015-07-31  total
---- ---------- ---------- ----------- ----------- ----------- ..... ----------- ----------- ----------- -----------
A    2015-07-01 2015-07-23 1           1           1           ..... 0           0           0           23
B    2015-07-02 2015-07-04 0           1           1           ..... 0           0           0           3
C    2015-07-03 2015-07-31 0           0           1           ..... 1           1           1           29

尝试将代码放入代码格式块,这很有趣!尝试将代码放入代码格式块,这很有趣!没问题,很高兴我能帮忙。没问题,很高兴我能帮忙。