【问题标题】:SQL Server 2008 + Creating a cross-tab stored procedureSQL Server 2008 + 创建交叉表存储过程
【发布时间】:2012-02-28 11:15:41
【问题描述】:

我有两个表要加入并在 SQL 2008 中创建一个交叉表:

表A:

 Auto_ID | Fiscal_Period | Amount 
   1     | 01012012      | NULL 
   1     | 01022012      | 80 
   1     | 01032012      | NULL 
   2     | 01012012      | NULL 
   2     | 01022012      | 10 

表B:

Auto_ID | Row_ID | StaticData
   1    |    1   | sampledata
   2    |    2   | data1

我想使用交叉表来动态创建如下表结构:

Row_ID | StaticData  | FiscalPeriod(01012012) | FiscalPeriod(01022012) | FiscalPeriod(01032012)
   1   | sampledata  | NULL                   | 80                     | NULL
   2   | data1       | NULL                   | 10                     | NULL

我当前的查询正确地连接了表;但是,我在将会计期间转换到标题行时遇到了困难。

SELECT *
FROM (SELECT 
         B.Row_Id as RowID, B.StaticData as StaticData, A.Fiscal_Period AS FPPD 
      FROM TableA A 
      LEFT JOIN TableB B ON A.Auto_ID = B.Auto_ID)  

【问题讨论】:

  • 如果您发布代码、XML 或数据示例, 在文本编辑器中突出显示这些行,然后单击编辑器上的“代码示例”按钮 ({ })工具栏以很好地格式化和语法突出显示它! (也绝对不需要大量的  <br/> 元素,那样......)

标签: sql sql-server-2008 crosstab


【解决方案1】:

这就是我会做的:

首先创建一些测试数据:

CREATE TABLE tblA (Auto_ID INT,Fiscal_Period  VARCHAR(100),Amount FLOAT)
CREATE TABLE tblB (Auto_ID INT,Row_ID INT,StaticData VARCHAR(100))
INSERT INTO tblA
SELECT 1,'01012012',NULL UNION ALL
SELECT 1,'01022012',80 UNION ALL
SELECT 1,'01032012',NULL UNION ALL
SELECT 2,'01012012',NULL UNION ALL
SELECT 2,'01022012',10 

INSERT INTO tblB
SELECT 1,1,'sampledata' UNION ALL
SELECT 2,2,'data1'

然后找到唯一的列:

DECLARE @cols VARCHAR(MAX)
;WITH CTE
AS
(
SELECT
    ROW_Number() OVER(PARTITION BY tblA.Fiscal_Period ORDER BY tblA.Fiscal_Period) AS RowNbr,
    tblA.Fiscal_Period
FROM
    tblA AS tblA
)
SELECT
     @cols = COALESCE(@cols + ','+QUOTENAME('FiscalPeriod('+Fiscal_Period+')'),
                 QUOTENAME('FiscalPeriod('+Fiscal_Period+')'))
FROM
    CTE
WHERE
    CTE.RowNbr=1

然后用动态sql执行一个pivot:

DECLARE @query NVARCHAR(4000)=
N'SELECT
    *
FROM
(
SELECT
    tblB.Row_ID,
    tblb.StaticData,
    ''FiscalPeriod(''+tblA.Fiscal_Period+'')'' AS Name,
    tblA.Amount
FROM
    tblA AS tblA
    JOIN tblB AS tblB
        ON tblA.Auto_ID=tblB.Auto_ID
) AS p
PIVOT
(
    SUM(Amount)
    FOR Name IN ('+@cols+')
) AS Pvt'
EXECUTE(@query)

然后在我的情况下,我将删除临时表:

DROP TABLE tblA
DROP TABLE tblB

希望对你有帮助

【讨论】:

  • 是的,获得独特的列非常简洁。很高兴帮助:-)
【解决方案2】:

由于您没有指定数据库的风格,请注意,以下仅对 MySQL 有效!

交叉表查询只能通过非常肮脏的技巧才能实现,它仅在存储过程中实际上是可行的。

您首先想出一些方法,将会计期间列表转换为 SQL,类似于

SELECT
  TABLEB.Row_ID,
  TABLEB.staticdata
  ,fp01012012.Amount as fp01012012amount
  ,fp01022012.Amount as fp01022012amount
  ,fp01032012.Amount as fp01032012amount
FROM
  TABLEB
  LEFT JOIN TableA AS fp01012012 ON fp01012012.Auto_ID=TABLEB.Auto_ID AND fp01012012.Fiscal_Period='01012012'
  LEFT JOIN TableA AS fp01022012 ON fp01022012.Auto_ID=TABLEB.Auto_ID AND fp01022012.Fiscal_Period='01022012'
  LEFT JOIN TableA AS fp01032012 ON fp01032012.Auto_ID=TABLEB.Auto_ID AND fp01032012.Fiscal_Period='01032012'

您现在必须将其构建为动态 SQL - 这仅在存储过程中是可行的。

DELIMITER $$

DROP PROCEDURE IF EXISTS `create_fiscal_data`$$
CREATE PROCEDURE `create_fiscal_data` ()
BEGIN
      DECLARE dynfields VARCHAR(10000) DEFAULT 'SELECT TABLEB.Row_ID, TABLEB.staticdata';
      DECLARE dynfrom VARCHAR(10000) DEFAULT ' FROM TABLEB';
      DECLARE period VARCHAR(10) DEFAULT '';
      DECLARE done INT DEFAULT 0;
      DECLARE id INT DEFAULT 7;
      DECLARE periods CURSOR FOR SELECT DISTINCT Fiscal_Period FROM TableA;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
      OPEN periods;

      cycleperiods: LOOP
          FETCH periods INTO period;
          IF done=1 THEN LEAVE cycleperiods; END IF;

          SET dynfields=CONCAT(dynfields,',`fp',period,'`.Amount AS `fp',period,'amount`');
          SET dynfrom=CONCAT(dynfrom,' LEFT JOIN TableA AS `fp',period,'` ON `fp',period,'`.Auto_ID=TABLEB.Auto_ID AND `fp',period,'`.Fiscal_Period="',period,'"');

      END LOOP;

      CLOSE periods;

      SELECT @dynsql:=CONCAT(dynfields,dynfrom) INTO dynfields;
      -- Here comes the trick!
      PREPARE dynqry FROM @dynsql;
      EXECUTE dynqry;

END$$

DELIMITER ;

诀窍是,将 SQL 构建到变量 @dynsql 中(DECLAREd 变量不起作用),然后准备并执行它。

现在查询

CALL `create_fiscal_data;`

将创建您需要的输出。

【讨论】:

  • 感谢您的回复,我尝试将其转换为 sql2008。抱歉,我没有在我的问题中指定。
  • 应该很直接 - 请发回你的结果!我还编辑了您问题上的标签以使其更清晰。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-10
  • 2015-01-26
  • 1970-01-01
  • 2022-12-08
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
相关资源
最近更新 更多