SQL Server 2008 + Создание хранимой процедуры кросс-таблицы - PullRequest
1 голос
/ 07 февраля 2012

У меня есть две таблицы, к которым я хочу присоединиться и создать таблицу кросс-таблиц в SQL 2008:

Таблица A:

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

ТАБЛИЦА:

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 ]

2 голосов
/ 07 февраля 2012

Я бы сделал следующее:

Сначала создайте несколько тестовых данных:

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 ('+@cols+')
) AS Pvt'
EXECUTE(@query)

Тогда в моем случае я опущу временные таблицы:

DROP TABLE tblA
DROP TABLE tblB

Надеюсь, это поможет вам

0 голосов
/ 07 февраля 2012

Поскольку вы не указали разновидность базы данных, имейте в виду, что следующее применимо только для 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;`

создаст нужный вывод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...