2013-02-01 45 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> 
相关问题