【问题标题】:Getting Data In to a pivot table将数据输入数据透视表
【发布时间】:2013-09-05 19:15:12
【问题描述】:

嗯,我真的尝试使用我昨天在@AaronBertrand 的问答中学到的东西来解决类似类型的问题。 我在 Microsoft SQL Server 2008 R2 中使用

我的数据如下所示:

SalesPersonID TransDate   Order     DateTotal
1108          8/2/2013    231.95    7713.8
1108          8/2/2013    5805.15   7713.8
1108          8/2/2013    1676.70   7713.8
1108          8/3/2013    159.95    3635.35
1108          8/3/2013    468.90    3635.35
1108          8/3/2013    1160.85   3635.35
1108          8/3/2013    209.95    3635.35
1108          8/3/2013    1161.85   3635.35
1108          8/3/2013    473.85    3635.35
1108          8/4/2013    149.98    3151.68
1108          8/4/2013    793.95    3151.68
1108          8/4/2013    55.00     3151.68
1108          8/4/2013    198.95    3151.68
1108          8/4/2013    398.00    3151.68
1108          8/4/2013    1255.85   3151.68
1108          8/4/2013    299.95    3151.68
1108          8/9/2013    223.95    1413.8
1108          8/9/2013    59.95     1413.8
1108          8/9/2013    1129.90   1413.8
1108          8/30/2013   1396.43   1396.43
1108          8/31/2013   89.95     1735.65
1108          8/31/2013   495.95    1735.65
1108          8/31/2013   495.95    1735.65
1108          8/31/2013   633.85    1735.65
1108          8/31/2013   19.95     1735.65
1205          8/3/2013    2389.09   2389.09

使用我从之前的问题[Here] 得到的答案,我想我并不完全理解 SQL....

所以.....

我需要这样的数据:

SalesPersonID   1       2       3       4       5     6     7     8     9      ….  29    30      31
1108            0.00    7713.80 3635.35 3151.68 0.00  0.00  0.00  0.00  1413.80    0.00  1396.43 1735.65
1205            0.00    0.00    2389.09 0.00    0.00  0.00  0.00  0.00  0.00       0.00  0.00    0.00

顶部的数字是所选月份的天数,我使用的是 8 月,如果选择 6 月,则只有 30 天。

我使用此代码获取我的第一天和最后一天以及日期。

DECLARE @BeginDate AS VARCHAR(10), @EndDate AS VARCHAR(10), @SelectedMonthDays AS int
SET @BeginDate='08/15/13'

-- Last Day of Current Month
Set @SelectedMonthDays = DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@BeginDate)+1,0)))

-- Last day Date of Current Month
SET @EndDate=cast(convert(date,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@BeginDate)+1,0))) as varchar(10))

-- Convert input date to the first day Date of current month
Set @BeginDate = cast(convert(date,DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0,@BeginDate),0))) as varchar(10))

要获取当前选定月份的天数,我有以下代码:

SELECT xhours = number FROM Master..spt_values WHERE type = N'P' and number between 1 and @SelectedMonthDays ORDER BY number

感谢大家提供的任何帮助。

【问题讨论】:

    标签: sql sql-server sql-server-2008-r2 group-by pivot


    【解决方案1】:

    这种类型的数据转换称为PIVOT

    如果您提前知道所需的值,则可以对查询进行硬编码,基本语法如下:

    SELECT salespersonid, 
           COALESCE([1], 0.00)  AS [1], 
           COALESCE([2], 0.00)  AS [2], 
           COALESCE([3], 0.00)  AS [3], 
           COALESCE([4], 0.00)  AS [4]
    FROM   
    (
        SELECT salespersonid, 
            [order], 
            Datepart(day, transdate) day 
        FROM   yourtable 
        WHERE  transdate >= '2013-08-01' 
            AND transdate <= '2013-08-31'
    ) x 
    PIVOT 
    (
        Sum([order]) 
        FOR day IN ([1], [2], [3], [4]) 
    ) p 
    

    但是您希望根据每个月的天数调整结果的情况,您将希望使用动态 SQL 来查看。您可以使用Master..spt_values 使用现有查询来获取日期列表,您只需将该列表放在字符串中即可。动态 SQL 代码将类似于:

    DECLARE @BeginDate AS VARCHAR(10), @EndDate AS VARCHAR(10), @SelectedMonthDays AS int
    SET @BeginDate='08/15/13'
    
    -- Last Day of Current Month
    Set @SelectedMonthDays = DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@BeginDate)+1,0)))
    
    -- Last day Date of Current Month
    SET @EndDate=cast(convert(date,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@BeginDate)+1,0))) as varchar(10))
    
    -- Convert input date to the first day Date of current month
    Set @BeginDate = cast(convert(date,DATEADD(s,0,DATEADD(mm, DATEDIFF(m,0,@BeginDate),0))) as varchar(10))
    
    
    DECLARE @cols AS NVARCHAR(MAX),
        @colsNull AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @cols = STUFF((SELECT ',' + QUOTENAME(number) 
                        from Master..spt_values 
                        WHERE type = N'P' 
                          and number between 1 and @SelectedMonthDays 
                        group by number
                        ORDER BY number
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    select @colsNull = STUFF((SELECT ', coalesce(' + QUOTENAME(number)+', 0.00) as '+QUOTENAME(number)
                        from Master..spt_values 
                        WHERE type = N'P' 
                          and number between 1 and @SelectedMonthDays 
                        group by number
                        ORDER BY number
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    
    set @query = 'SELECT SalesPersonID, ' + @colsNull + ' 
                from 
                (
                    select SalesPersonID, [Order], 
                      datepart(day, TransDate) day
                    from yourtable
                    where TransDate>= '''+convert(varchar(10), @BeginDate, 120)+'''
                      and TransDate<= '''+convert(varchar(10), @EndDate, 120)+'''
                ) x
                pivot 
                (
                    sum([Order])
                    for day in (' + @cols + ')
                ) p '
    
    
    execute sp_executesql @query;
    

    SQL Fiddle with Demo。这给出了一个结果:

    | SALESPERSONID | 1 |      2 |       3 |       4 | 5 | 6 | 7 | 8 |      9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |      30 |      31 |
    |          1108 | 0 | 7713.8 | 3635.35 | 3151.68 | 0 | 0 | 0 | 0 | 1413.8 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 | 1396.43 | 1735.65 |
    |          1205 | 0 |      0 | 2389.09 |       0 | 0 | 0 | 0 | 0 |      0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |       0 |       0 |
    

    【讨论】:

    • 工作得很好!!谢谢你。但我有一个小问题。输出的美元在小数点右边有 4 位小数。我试图解决这个问题,但我似乎破坏了代码。这是我尝试的最后一个地方:'select SalesPersonID, Cast([Order] as decimal(6,2)) as [Order], datepart(day, TransDate) AS day' 错误:将钱转换为数据类型的算术溢出错误数字。
    • @Jeff 那段代码应该可以工作——看这个演示——sqlfiddle.com/#!3/c03167/16那列的数据类型是什么?你能用正确的表结构编辑 sql fiddle 吗?
    • 我确实检查了演示,你的东西是正确的。数据类型为 Decimal(6,2)。
    • @Jeff 我猜你的值可能大于(6,2) 尝试将其更改为cast([order] as decimal(10,2)) 甚至(20,2) 以查看是否可以解决问题。
    • Duh....当然我得到“算术溢出”它的钱并且大于(6,2)我现在将它设置为16,2并且一切正常......对不起打扰你是我的经验不足。
    猜你喜欢
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多