Как я могу извлечь значения из универсальной таблицы аудита, воссозданной как набор строк со значимыми именами столбцов в SQL? - PullRequest
0 голосов
/ 21 мая 2009

Итак, у меня есть таблица аудита, выглядит так:

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. Я буду знать имя таблицы и дату обновления.

Ответы [ 3 ]

2 голосов
/ 21 мая 2009

Это можно сделать с помощью функции PIVOT. Я попробую разработать пример:

SELECT *
FROM ERAUser.Audit
PIVOT (max(NewValue) FOR FieldName in (Field1, Field2, Field3)) as PivotTable

Функция max () необходима для указания Sql Server, что делать, если он находит несколько строк с одним и тем же FieldName. Вы можете использовать оператор 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
0 голосов
/ 21 мая 2009

Если вы знаете, что вам нужно только вернуть строки из одной таблицы (например, «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.

0 голосов
/ 21 мая 2009

Это будет чрезвычайно сложно, не в последнюю очередь потому, что тип значений для одной комбинации имени таблицы и имени столбца будет отличаться от других типов. Чтобы создать целую запись, соответствующую одной строке таблицы, вам нужно будет объединить несколько записей аудита. Таким образом, ваш набор строк должен быть привязан к одной таблице за раз. Непонятно, записываете ли вы неизмененные столбцы - вероятно, нет - поэтому работа с набором строк, содержащим всю запись, будет в лучшем случае трудной.

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