2013-02-01 86 views
2

由於我討厭要求具體的解決方案,這裏是我的問題的背景,以防萬一我以錯誤的方式接近它。如果您想跳過背景並正確回答問題,請跳至粗體行。我正在創建一個PDF格式的表單,該格式將預填充來自SQL數據庫的數據。爲了做到這一點,我需要將數據庫中的數據導出到XFDF文件中,然後我可以輕鬆地將其與空白PDF表單合併以填充值。如何將具有多列的行轉換爲具有兩列(字段名和值)和多行的表?

的XFDF文件的格式如下:

<fields> 
    <field name="FirstName"> 
     <value>John</value> 
    </field> 
    <field name="LastName"> 
     <value>Smith</value> 
    </field> 
</fields> 

其中「名字」和「姓氏」對應PDF表單上的字段的名稱,而「約翰」和「史密斯」是從相應的值數據庫來填充表單。

所以我的目標是創建XFDF文件,並使PDF上的字段名稱與表格中列的名稱相對應。我目前的做法是使用SELECT FOR XML EXPLICIT語句。爲了使用它,我首先需要將數據選擇爲xml顯式語句所需的「通用表格」格式,其中原始數據表格中的每列都有單獨的行。我可以手動完成對每個字段,寫一個單獨的SELECT語句爲每列 - 因此,例如,名字列部分看起來是這樣的:

SELECT 2    AS Tag, 
     1    AS Parent, 
     null   AS [fields!1], 
     FirstName  AS [fields!2!name], 
     D.FirstName  AS [value!3!] 
From Data AS D 

(我不知道這正是對選擇正確的語法對於XML語句,但它應該是這樣的)

如果我爲我的原始表中的每個列做了select語句(加上一個用於根級別「fields」元素,然後將它們聯合在一起,它應該創建我需要的表然後執行SELECT FOR XML EXPLICIT語句。

但是,有一個這種形式的領域(政府機構! Yeesh!),我更喜歡某種方式來編程。

所以,現在我已經給出了背景,這是我的實際問題。如果您閱讀背景並認爲我的方法很糟糕,請告訴我。

我需要一種方法來服用含有一排像這樣的表:

 
+-----------+----------+-----+ 
| FirstName | LastName | Etc | 
+-----------+----------+-----+ 
| John  | Smith | 123 | 
+-----------+----------+-----+ 

,並從它建立一個新的表看起來像這樣:

 
+-----------+-------+ 
| FieldName | Value | 
+-----------+-------+ 
| FirstName | John | 
| LastName | Smith | 
| Etc  | 123 | 
+-----------+-------+ 

如果這是有效的,我會這樣做:

SELECT 2    AS Tag, 
     1    AS Parent, 
     null   AS [fields!1], 
     C.column_name  AS [fields!2!name], 
     D.{C.column_name}  AS [value!3!] 
From  Data AS D, information_schema.columns AS C 
WHERE C.table_name = 'Data' 

顯然這是不可能的,你不能讓col被選中的變量。我看了這個問題(Use variable Column name in Select statement on SQL server 2008),最好的答案可能是有希望的,但它以「但它非常可怕,恕我直言。」結束。在踏上這條道路之前,我想研究一些不太「可怕」的解決方案。有什麼建議麼?

+0

SQL服務器,MySQL或其他? –

+1

MS SQL Server 2008. –

回答

1

您可以在MS SQL 2008中使用UNPIVOT 問題是您需要在所有列中使用相同的數據類型和排序規則,或者在下面的示例中進行轉換。結果應該是完全像你想

SELECT seq,ts 
FROM 
    (select 

    convert(nvarchar(200),FirstName) COLLATE Latin1_General_CI_AS as FirstName, 
    convert(nvarchar(200),LastName) COLLATE Latin1_General_CI_AS as LastName, 
    convert(nvarchar(200),Etc) COLLATE Latin1_General_CI_AS as Etc, 

    from youPersonTable P 
     where id = 1 
) p 
UNPIVOT 
    (ts FOR Seq IN 
     (FirstName,LastName,Etc) 
) AS unpvt 
+0

我沒有測試過這個,但它是我數據庫中的實時代碼的剝離版本。所以它'應該':) –

+0

我想我的問題與這一個將是它看起來像我需要手動寫出一行(轉換(nvarchar(200),_______)COLLATE Latin1_General_CI_AS爲______)爲每個字段。我希望有一個更清潔的解決方案 - 就像我可以循環遍歷所有列一樣。 –

+1

我知道,它有點麻煩。我的原始SP有50多行'轉換'。但它很好地解決了這個問題。你猜你可以使用sysobjects等產生的代碼 –

0

另一種辦法是用兩個表加一個臨時表的工作之一:

tblEmployee 
tblXTABEmployee --This table basically swaps the rows for columns. 
tmpXTABEmployee 

您可以使用此獲得tblEmployee的所有列名命令:

EXEC sp_help tblEmployee 

然後你可以使用遊標來填充你的tblXTABEmployee。感覺費用問你是否想要更多的細節。

UPDATE: 你將不得不創建一個tmpXTABEmployee,你會選擇所有的列名到使用的sp_help,然後用光標這樣的(請注意,我沒有測試過這一點):

declare @ColumnName nvarchar(255) 
declare @SQLString nvarchar(4000) 
declare columnNameCursor cursor for 

SELECT  ColumnName 
FROM  tmpXTABEmployee 
GROUP BY ColumnName 
ORDER BY ColumnName 

OPEN columnNameCursor 

FETCH NEXT FROM columnNameCursor INTO @ColumnName 

BEGIN TRY 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @SQLString = 'INSERT INTO dbo.tblXTABEmployee (FieldName, DataValue) VALUES (' + @ColumnName + ', ' + dbo.tmpXTABEmployee.DataValue + ')' 
    EXEC (@SQLString) 
    FETCH NEXT FROM columnNameCursor INTO @ColumnName 
END 
END TRY 
BEGIN CATCH 
DECLARE @msg VARCHAR(4096) 
SET @msg = 'Failure occurred attempting to insert into tblXTABEmployee.'; 
RAISERROR(@msg, 0, 1); 
END CATCH 

CLOSE columnNameCursor 
DEALLOCATE columnNameCursor 
GO 
+0

我不知道任何關於遊標,所以是的,請告訴我更多。 –

0

使用for xml查詢您的表格,並將結果存儲在XML變量中。然後您查詢XML變量來創建需要使用local-name(.)來從XML變量的列/節點名XML的形狀..

SQL Fiddle

MS SQL Server 2008的架構設置

create table YourTable 
(
    FirstName varchar(25), 
    LastName varchar(25), 
    Etc int 
) 

insert into YourTable values ('John', 'Smith', 123) 

查詢1

declare @XML xml 

set @XML = (
      select * 
      from YourTable 
      for xml path('row'), type 
      ) 

select T.N.value('local-name(.)', 'sysname') as "@name", 
     T.N.value('text()[1]', 'varchar(max)') as "value" 
from @XML.nodes('/row/*') as T(N) 
for xml path('field'), root('fields') 

Results

<fields> 
    <field name="FirstName"> 
    <value>John</value> 
    </field> 
    <field name="LastName"> 
    <value>Smith</value> 
    </field> 
    <field name="Etc"> 
    <value>123</value> 
    </field> 
</fields> 
相關問題