2012-02-07 109 views
1

我有,我想加入,并在2008年SQL创建一个交叉表两张表:的SQL Server 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) 
+0

如果您发布的代码,XML或数据样本,**请**突出显示文本编辑器中的那些行并点击编辑器工具栏上的“代码示例”按钮(“{}”),以精确地格式化和语法突出显示它! (也绝对不需要大量' '或'
'元素,这样....) – 2012-02-07 06:09:04

回答

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执行一个支点:

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 ('[email protected]+') 
) AS Pvt' 
EXECUTE(@query) 

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

DROP TABLE tblA 
DROP TABLE tblB 

我希望这将有助于你

+0

谢谢,这工作很好!我喜欢CTE的使用:-) – user1130511 2012-02-07 18:52:54

+0

是的,它是非常简单而明确的专栏。乐意效劳 :-) – Arion 2012-02-07 19:08:07

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 - 这是feasable只在一个存储过程。

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;` 

将创建你所需要的输出。

+0

感谢您的答复,虐待尝试将此转换为sql2008。对不起,我没有在我的问题中指定。 – user1130511 2012-02-07 01:36:12

+0

应该很简单 - 请寄回你的结果!我还在你的问题上编辑了标签,使其更清晰。 – 2012-02-07 01:36:58