使用t-SQL(分组项)按月/年排列数据

时间:2015-08-28 08:06:03

标签: sql sql-server tsql

我使用以下SQL语句按月销售的数量总结我的销售历史数据。

WITH StockSales AS
(
    SELECT
        CASE
            WHEN Month(PostST.TxDate) = 1 THEN 'Jan'
            WHEN Month(PostST.TxDate) = 2 THEN 'Feb'
            WHEN Month(PostST.TxDate) = 3 THEN 'Mar'
            WHEN Month(PostST.TxDate) = 4 THEN 'Apr'
            WHEN Month(PostST.TxDate) = 5 THEN 'May'
            WHEN Month(PostST.TxDate) = 6 THEN 'Jun'
            WHEN Month(PostST.TxDate) = 7 THEN 'Jul'
            WHEN Month(PostST.TxDate) = 8 THEN 'Aug'
            WHEN Month(PostST.TxDate) = 9 THEN 'Sept'
            WHEN Month(PostST.TxDate) = 10 THEN 'Oct'
            WHEN Month(PostST.TxDate) = 11 THEN 'Nov'
            WHEN Month(PostST.TxDate) = 12 THEN 'Dec'
        END AS MonthSold, 
        YEAR(PostST.TxDate) AS YearSold, 
        CONCAT(StkItem.Description_1, ' - ', StkItem.Code) AS Item, 
        CASE
            WHEN PostST.TrCodeID = 30  THEN PostST.Quantity * -1
            WHEN PostST.TrCodeID = 34 THEN PostST.Quantity * 1
            ELSE 0
        END AS QtySold
    FROM 
        StkItem
    INNER JOIN 
        PostST ON PostST.AccountLink = StkItem.StockLink
    WHERE 
        PostST.TrCodeID IN (34, 30)
)
SELECT
    StockSales.MonthSold, 
    StockSales.YearSold, 
    StockSales.Item, 
    SUM (StockSales.QtySold) AS QtySold
FROM 
    StockSales
GROUP BY 
    StockSales.QtySold, StockSales.MonthSold, StockSales.YearSold, StockSales.Item

我得到以下格式:

enter image description here

但是,我想要的是项目只出现一次(分组),然后每个月和每年作为一个单独的字段,每个月都有一个QtySold的SUM。

作为一个例子,我刚刚在Excel中设置了我想要的样子:

enter image description here

有没有办法以不同方式设置字段?

谢谢:)

3 个答案:

答案 0 :(得分:0)

您需要“旋转”数据以获得所需格式的结果。

<强> Excel中

一种方法是将数据导入Excel,您可以在其中根据数据创建数据透视表,以构建所需的结构。快速的方法是:

  • 粘贴SSMS数据(带标题)
  • 选择数据
  • 点击Excel中的“格式化为表格”,勾选“第1行标题”
  • 选择表格后,会出现一个新的功能区选项卡。在那里有一个名为“与数据透视表汇总”的按钮

创建数据透视表后,您可以选择行轴上的项目,列上的年份和月份以及#sold as values。

<强> SSRS

如果您有可用的SQL Server Reporting服务,还可以通过SSRS报告中的Tablix来旋转表。

  • 根据您的查询创建数据集(最好将SSRS查询粘贴到存储过程中,以便查询在SQL Server级别“可见”,并在进行架构更改时显示为依赖关系)。
  • 为方便起见,请按照首选格式添加一列年份和月份的组合以供显示。
  • 在报告中添加矩阵
  • 将“项目”设置为行值
  • 将“日期”字段设置为列分组。
  • 将#items设置为详细级别的值。

SQL Server 另一个选项是PIVOT SQL命令,请参见此处https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

这不是我经常做的事情,因为当您在编写查询时知道所需的精确列标题(旋转字段)时,它才真正有用,因为您仍需要指定所有列中的查询。

例如,如果你有一个像静态货币组这样的固定数据集,那么效果很好。

如果您有动态数据(例如您的情况下,可能会更改一组年/月),那么它不是那么有用,但如果您有固定的报告期,则可能没问题。

答案 1 :(得分:0)

首先,您需要以所需格式转换月份,您可以通过在cte中使用belwo脚本来实现:

SELECT
    CASE
        WHEN Month(PostST.TxDate) = 1 THEN 'Jan'
        WHEN Month(PostST.TxDate) = 2 THEN 'Feb'
       .
       .
       .
        WHEN Month(PostST.TxDate) = 12 THEN 'Dec'
    END) + CAST ( YEAR(PostST.TxDate) AS VARCHAR) AS MonthSold, 
       .

然后使用SQL pivot来转动数据:

SELECT * FROM ( SELECT MonthSold, YearSold, Item, QtySold
FROM 
StockSales ) as data1
PIVOT ( SUM( QtySold ) FOR MonthSold IN ( 'Jan-13', 'Feb-13', 'Mar-13', 'Jan-14', 'Feb-14', 'Jan-15') ) AS PivotData

您必须手动将所有monthSold值放入FOR MonthSold IN()值。还有另一种方法,动态sql,可以让你自动处理它。您可以尝试此脚本,并查找该方法。希望它有所帮助

答案 2 :(得分:-1)

使用带有数据透视表的CTE

WITH Sales_CTE (Employee_No, [Employee Name], MonthSold,Amount)
AS
-- Define the CTE query.
(
   SELECT  EMP.Employee_No,Emp.First_Name+' '+Emp.Last_Name [Employee Name],   


       CASE
        WHEN Month(SLC.Post_Date) = 1 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Jan'
        WHEN Month(SLC.Post_Date) = 2 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Feb' 
        WHEN Month(SLC.Post_Date) = 3 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Mar' 
        WHEN Month(SLC.Post_Date) = 4 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Apr' 
        WHEN Month(SLC.Post_Date) = 5 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-May' 
        WHEN Month(SLC.Post_Date) = 6 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Jun' 
        WHEN Month(SLC.Post_Date) = 7 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Jul' 
        WHEN Month(SLC.Post_Date) = 8 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Aug' 
        WHEN Month(SLC.Post_Date) = 9 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Sep' 
        WHEN Month(SLC.Post_Date) = 10 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Oct' 
        WHEN Month(SLC.Post_Date) = 11 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Nov'        
        WHEN Month(SLC.Post_Date) = 12 THEN CAST (right(YEAR(SLC.Post_Date),2) AS VARCHAR)+'-Dec'
    END  AS [MonthSold], 
  CASE WHEN SLC.Transaction_Type IN ('B') 
                      THEN SLC.Commission_Received_Amount ELSE SLC.Commission_Amount + IsNULL(SLC.Pleasant_ChargeBack_Amount, 0) 
                      + IsNULL(SLC.Preferred_ChargeBack_Amount, 0) + IsNULL(SLC.Non_Preferred_ChargeBack_Amount, 0) + IsNULL(SLC.Other_ChargeBack_Amount, 0) 
                      END AS  [Amount] 
    FROM         tbl_Sales SLC JOIN
                      tbl_Employee EMP ON (EMP.Employee_ID = SLC.Employee_ID AND EMP.Load_Status = '0' AND SLC.Invoice_Status <> 'V') LEFT OUTER JOIN
                      tbl_Preferred PRV ON (PRV.Segment_Type = SLC.Segment_Type AND PRV.Club_Code = SLC.Club_Code AND PRV.Vendor_Code = SLC.Vendor_Code AND 
                      PRV.Effective_Date <= SLC.Post_Date AND PRV.Expiration_Date >= SLC.Post_Date) WHERE SLC.Post_Date>='2015-01-01'
)

SELECT *
FROM (
   SELECT * FROM Sales_CTE
) as s  
PIVOT
(
    SUM(Amount)
    FOR [MonthSold] IN ("15-Jan","15-Feb","15-Mar","15-Apr","15-May","15-Jun","15-Jul","15-Aug","15-Sep","15-Oct","15-Nov","15-Dec","16-Jan","16-Feb","16-Mar","16-Apr","16-May","16-Jun","16-Jul","16-Aug","16-Sep","16-Oct","16-Nov","16-Dec")
)AS pvt  order by Employee_No asc

GO