所以我有这个审计表,看起来像这样:
USE [DatabaseName]
GO
/****** Object: Table [ERAUser].[Audit] Script Date: 05/20/2009 17:07:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [ERAUser].[Audit](
[AuditID] [int] IDENTITY(1,1) NOT NULL,
[Type] [char](1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[TableName] [varchar](128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[PrimaryKeyField] [varchar](1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[PrimaryKeyValue] [varchar](1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[FieldName] [varchar](128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[OldValue] [varchar](1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[NewValue] [varchar](1000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[UpdateDate] [datetime] NULL DEFAULT (getdate()),
[UserName] [varchar](128) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
问题是,由于我无法控制的原因,我需要将数据作为复制源表的行集返回给用户(作为此系统用户的其他开发人员)。如何将此架构转换为侧面并将FieldName中的值作为行集的列标题?我正在使用SQL 2005.我将知道tablename和UpdateDate。
答案 0 :(得分:2)
这可以使用PIVOT功能完成。我会试着找出一个例子:
SELECT *
FROM ERAUser.Audit
PIVOT (max(NewValue) FOR FieldName in (Field1, Field2, Field3)) as PivotTable
如果找到多个具有相同FieldName的行,则需要max()告诉Sql Server该怎么做。您可以使用WHERE语句将其限制为正确的行;如果确保它只找到一个,则max(NewValue)等于NewValue。
如果您有很长的列列表,则可以为此生成SQL:
declare @columnlist nvarchar(4000)
select @columnlist = IsNull(@columnlist + ', ', '') + FieldName
from (
select distinct FieldName from ERAUser.Audit
) sub
declare @query nvarchar(4000)
select @query = 'select *
from ERAUser.Audit
PIVOT (max(newValue) FOR FieldName in (' + @columnlist + ')) as PivotTable'
exec sp_executesql @query
以下是PIVOT的基本示例,以获得一般概念:
create table #normalized (
colname varchar(12),
value varchar(12)
)
insert into #normalized values ('value1','A')
insert into #normalized values ('value2','B')
insert into #normalized values ('value3','C')
select *
from #normalized
PIVOT (max(value) FOR ColName in (value1,value2,value3)) as Y
这将导致:
value1 value2 value3
A B C
答案 1 :(得分:0)
这将非常困难,尤其是因为表名和列名的一个组合的值的类型将与其他类型不同。要创建对应于表的一行的整个记录,您将必须组合多个审核记录。因此,您的行集必须一次定制到一个表。目前尚不清楚您是否记录未更改的列 - 您可能没有 - 因此处理包含整个记录的行集将是最难的。
答案 2 :(得分:0)
如果您知道只需要从一个表中返回行(例如“Foo”)并假设要创建的所有字段都是varchar(50):
1)创建一个具有所需结构的临时表
DECLARE @Sql VARCHAR(8000)
DECLARE @ColName VARCHAR(128)
DECLARE @Comma VARCHAR(2)
SET @CreateSql = "CREATE TABLE #Temp ("
SET @Comma = ''
DECLARE columnCur CURSOR FOR
SELECT DISTINCT FieldName
FROM Audit
WHERE TableName = 'Foo'
OPEN columnCur
FETCH NEXT FROM columnCur INTO @ColName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @CreateSql = @CreateSql+@Comma+@ColName+' VARCHAR(128) NULL'
SET @Comma = ', '
FETCH NEXT FROM columnCur INTO @ColName
END
CLOSE columnCur
DEALLOCATE columnCur
SET @CreateSql = @CreateSql + ")"
EXECUTE sp_executesql @CreateSql
2)填写表主键:
--Assuming a single PK column, otherwise you need another cursor
DECLARE @pk VARCHAR(1000)
SELECT @pk=PrimaryKeyField
FROM Audit
WHERE TableName = 'Foo'
DECLARE @PkSql VARCHAR(2000)
SET @PkSql = 'INSERT INTO #Temp ('+@pk+') VALUES SELECT DISTINCT PrimaryKeyValue FROM Audit WHERE TableName = ''Foo'''
EXECUTE sp_executesql @PkSql
3)创建一个游标,创建动态sql,用正确的值更新临时表中的行(与上面类似的风格)
4)从#Temp
中选择5)DROP #Temp
注意:这应该可行,但由于我现在没有可用的SQL Server,所以它完全未经测试。