SQL Server 2008 +创建交叉表存储过程

时间:2012-02-07 00:13:53

标签: sql sql-server-2008 crosstab

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

表A:

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

TABLEB:

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)  

2 个答案:

答案 0 :(得分:2)

这就是我要做的事情:

首先创建一些测试数据:

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

我希望这会对你有所帮助

答案 1 :(得分:0)

由于您没有指定数据库的味道,请注意,以下内容仅适用于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(DECLARE d变量不起作用),然后准备并执行它。

现在查询

CALL `create_fiscal_data;`

将创建您需要的输出。