【问题标题】:sql: values of rows as columnssql:行的值作为列
【发布时间】:2012-09-05 10:31:05
【问题描述】:

我有一张表,用于存储合同的交易,如下所示:

Id_Contract[int] | Month[DateTime] | Amount[int]
------------------------------------------------
        1          2012-01-01 00:00:00.000      500     
        1          2012-03-01 00:00:00.000      450 
        2          2012-09-01 00:00:00.000      300     
        3          2012-08-01 00:00:00.000      750 

用户应该能够选择查询的时间跨度 我要存档的是,如果用户选择从 01/2012 到 03-2012 的时间跨度,他会得到结果:

Id_Contract[int] | Jan 2012 | Feb 2012 | Mar 2012
--------------------------------------------------
    1                   500                       450

你有什么建议我可以解决这个问题吗?

最好的问候, r3try

编辑:感谢到目前为止的回答! 当我用谷歌搜索我的问题时,我也偶然发现了旋转,但到目前为止我还没有找到一个真正解决我的问题的例子(因为基本上每个例子都给出了列条目的具体可能性,但在我的例子中,它可能像“2012 年 3 月” ', '2012 年 4 月', ..., '2013 年 1 月', ...)

只是为了给你们一些关于我打算如何处理我从 sql 查询中得到的日期的更多背景信息: 我有一个带有gridview 的asp.net webforms 站点,其中包含一些合同数据......现在这个表应该通过该特定合同的付款信息进行扩展(基本上是Id_Contract 上的一个连接,但'pivoted')。 如果用户选择 2012 年 3 月 - 2012 年 5 月,则 Gridview 应包含合同的正常数据 + 3 列付款信息(3 月、4 月、5 月)。 在数据库中,只存储了已经插入值的条目。 -> 我希望解释能让事情更清楚一点。

【问题讨论】:

  • 请添加标识您使用的特定 rdbms 的标签
  • 您需要显示时间间隔内的所有月份,还是只显示表中有数据的月份?
  • 你会被引向动态sql...当心!! *不祥的合唱*

标签: sql sql-server-2008 pivot


【解决方案1】:

您的问题可以使用动态透视来解决。请查看此article

试试这个

DECLARE @t TABLE(Id_Contract INT, Dt DATETIME,Amount INT)
INSERT INTO @t SELECT 1,'2012-01-01 00:00:00.000',500
INSERT INTO @t SELECT 1,'2012-03-01 00:00:00.000',450
INSERT INTO @t SELECT 2,'2012-09-01 00:00:00.000',300
INSERT INTO @t SELECT 3,'2012-08-01 00:00:00.000',750

DECLARE @cols AS VARCHAR(MAX), @query  AS VARCHAR(MAX);

SELECT 
    Id_Contract
    , LEFT(DATENAME(month,Dt),3) + ' ' + DATENAME(Year,Dt) AS Month_Year_Name
    ,Amount
INTO #Temp
FROM @t 
WHERE Dt BETWEEN  '01/01/2012' AND '03/31/2012'

SELECT  @cols = STUFF(( SELECT DISTINCT 
                               '],[' +   t2.Month_Year_Name
                        FROM    #Temp AS t2
                        ORDER BY '],[' + t2.Month_Year_Name
                        FOR XML PATH('')
                      ), 1, 2, '') + ']'

SET @query = 'SELECT Id_Contract, ' + @cols + ' FROM 
            (
                SELECT
                     Id_Contract
                    , Amount
                    , Month_Year_Name
                FROM #Temp
           ) x
            PIVOT 
            (
                 MAX(amount)
                 FOR Month_Year_Name in (' + @cols + ')
            ) p '
EXECUTE(@query)
DROP TABLE #Temp

// 结果

Id_Contract Jan 2012    Mar 2012
1           500         450

编辑

对于您的测试数据,

DECLARE @t TABLE(Id_Contract INT, Dt DATETIME,Amount INT) 
INSERT INTO @t SELECT 1,'2012-01-01 00:00:00.000',500 
INSERT INTO @t SELECT 1,'2012-03-01 00:00:00.000',450 
INSERT INTO @t SELECT 2,'2012-03-01 00:00:00.000',450 
INSERT INTO @t SELECT 3,'2012-08-01 00:00:00.000',750 

输出是

Id_Contract Jan 2012    Mar 2012
1              500          450
2              NULL         450

如果满足要求,请告诉我。

【讨论】:

  • hmm,刚刚意识到如果多个合同在同一月份,这将不起作用......
  • 示例:DECLARE @t TABLE(Id_Contract INT, Dt DATETIME,Amount INT) INSERT INTO @t SELECT 1,'2012-01-01 00:00:00.000',500 INSERT INTO @t SELECT 1,'2012-03-01 00:00:00.000',450 插入@t SELECT 2,'2012-03-01 00:00:00.000',450 插入@t SELECT 3,'2012-08-01 00:00:00.000',750
  • @user1226742:将DISTINCT 添加到构建列列表的子查询(... STUFF(( SELECT DISTINCT ...) 并替换@987654327 @ 在PIVOT 子句中与SUM(amount)
  • user1226742.. 检查编辑。我按照 Andriy M 的建议在子查询中添加了 Distinct 子句。如果它对您有帮助,请告诉我。
【解决方案2】:

你想要做的就是pivoting,内置的PIVOT and UNPIVOT relational operators.支持它。

我会用一个解决方案来扩展答案,但现在看一下链接,你就会得到大致的想法。

【讨论】:

    猜你喜欢
    • 2021-09-22
    • 1970-01-01
    • 2021-12-22
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多