3

因为我讨厌要求具体的解决方案,所以这里是我的问题的背景,以防我以错误的方式接近它。如果您想跳过背景并直接回答问题,请跳至粗线。我正在创建一个 PDF 表单,该表单将预填充来自 SQL 数据库的数据。为此,我需要将数据库中的数据导出到 XFDF 文件中,然后我可以轻松地将其与空白 PDF 表单合并以填写值。

XFDF 文件具有以下格式:

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

其中“FirstName”和“LastName”对应于 PDF 表单上的字段名称,“John”和“Smith”是数据库中用于填充表单的对应值。

所以我的目标是创建 XFDF 文件,并使 PDF 上的字段名称与表中列的名称相对应。我目前的方法是使用 SELECT FOR XML EXPLICIT 语句。要使用它,我首先需要将数据选择为 for xml 显式语句所需的“通用表”格式,该格式对于原始数据表中的每一列都有单独的行。我可以手动浏览每个字段,为每个列编写单独的选择语句 - 例如,FirstName 列部分看起来像:

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

(我不确定 select for XML 语句的语法是否完全正确,但应该是这样的)

如果我对原始表中的每一列都做了一个这样的选择语句(加上一个用于根级“字段”元素,然后将它们联合在一起,它应该创建我需要的表,然后执行 SELECT FOR XML EXPLICIT 语句。

但是,此表单上有大量字段(政府机构!是的!),我更喜欢某种方式以编程方式执行此操作。

所以现在我已经给出了背景,这是我的实际问题。如果您阅读了背景并认为我的方法很糟糕,请告诉我。

我需要一种方法来获取包含这样一行的表:

+-----------+---------+------+
| 名字 | 姓氏 | 等 |
+-----------+---------+------+
| 约翰 | 史密斯 | 123 |
+-----------+---------+------+

并从中构造一个新表,如下所示:

+-----------+-------+
| 字段名 | 价值 |
+-----------+-------+
| 名字 | 约翰 |
| 姓氏 | 史密斯 |
| 等 | 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'   

显然这是不可能的,并且您不能使被选择的列成为变量。我查看了这个问题(在 SQL server 2008 上的 Select 语句中使用变量列名),最佳答案可能很有希望,但它以“但这一切都非常可怕,恕我直言”结束。在踏上这条路之前,我想研究一下不是“非常可怕”的解决方案。有什么建议么?

4

3 回答 3

1

您可以UNPIVOT在 MS SQL 2008 中使用,问题是您需要在所有列中具有相同的数据类型和排序规则,或者像下面的示例中那样进行转换。结果应该与您想要的完全一样

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
于 2013-02-01T17:41:06.797 回答
0

for xml使用XML 变量查询您的表并将结果存储在其中。然后查询 XML 变量以创建您需要使用的 XML 形状,local-name(.)以便从 XML 变量中获取列/节点名称。

SQL小提琴

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')

结果

<fields>
  <field name="FirstName">
    <value>John</value>
  </field>
  <field name="LastName">
    <value>Smith</value>
  </field>
  <field name="Etc">
    <value>123</value>
  </field>
</fields>
于 2013-02-01T22:30:08.600 回答
0

另一种选择是使用两个表和一个临时表:

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

您可以使用以下命令获取 tblEmployee 中的所有列名:

EXEC sp_help tblEmployee

然后您可以使用光标来填充您的 tblXTABEmployee。如果您想了解更多详细信息,请随时询问。

更新:您必须创建一个 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
于 2013-02-01T18:12:33.650 回答