Sql 动态选择更改的列名
我有一张如下所示的表格 ID名称地址城市角色日期\u已修改 1汤姆·奥斯汀经理X 2汤姆·奥斯汀校长 3汤姆:达拉斯副总裁 如何编写查询以选择在条目1、2和3之间更改的列名?目前,我正在编写一份需要识别变化的报告。这就是我到目前为止所拥有的,并且需要与之合作 我需要能够通过存储过程进行检测,并查看下面的输出 Id列名称已更改 2地址Y 2角色Y 3地址ZSql 动态选择更改的列名,sql,tsql,sql-server-2008-r2,Sql,Tsql,Sql Server 2008 R2,我有一张如下所示的表格 ID名称地址城市角色日期\u已修改 1汤姆·奥斯汀经理X 2汤姆·奥斯汀校长 3汤姆:达拉斯副总裁 如何编写查询以选择在条目1、2和3之间更改的列名?目前,我正在编写一份需要识别变化的报告。这就是我到目前为止所拥有的,并且需要与之合作 我需要能够通过存储过程进行检测,并查看下面的输出 Id列名称已更改 2地址Y 2角色Y 3地址Z 3角色Z如果我正确理解了您的问题,您需要的是检测从一行到另一行的更改并取消激活数据。SQL Server 2012或更高版本需要使用LAG ;
3角色Z如果我正确理解了您的问题,您需要的是检测从一行到另一行的更改并取消激活数据。SQL Server 2012或更高版本需要使用LAG
;with cte as (
-- LAG for id is used to skip first row from selection
select id, LAG(id, 1) OVER (ORDER BY id) AS OldId,
address, LAG(address, 1) OVER (ORDER BY id) AS OldAddress,
role, LAG(role, 1) OVER (ORDER BY id) AS OldRole,
Date_Modified
from audit_data
)
SELECT id, ColName, data_col, Date_Modified
FROM
(
select id, address, role, Date_Modified
from cte
-- detect any change in monitored data
where ((OldAddress IS NULL OR address <> OldAddress)
OR (OldRole IS NULL OR role <> OldRole))
AND OldId IS NOT NULL
) AS cp
-- unpivot address and role into data_col column
UNPIVOT
(
data_col FOR ColName IN (address, role)
) AS up;
[编辑]SQL 2008R2版本:
这与阿列克谢的回答非常相似:
CREATE TABLE #temp( ID INT IDENTITY(1, 1),
NAME VARCHAR(30),
ADDRESS VARCHAR(30),
CITY VARCHAR(30),
ROLE VARCHAR(30),
Date_Modified DATETIME );
INSERT INTO #temp
SELECT 'Tom',
'something',
'austin',
'manager',
DATEADD(day, -3, GETDATE())
UNION
SELECT 'Tom',
'nothing',
'austin',
'principal',
DATEADD(day, -2, GETDATE())
UNION
SELECT 'Tom',
'anything',
'dallas',
'VP',
DATEADD(day, -1, GETDATE());
SELECT 'Jon',
'something',
'san antonio',
'assistant manager',
DATEADD(day, -3, GETDATE())
UNION
SELECT 'Jon',
'something',
'austin',
'assistant manager',
DATEADD(day, -2, GETDATE())
UNION
SELECT 'Jon',
'anything',
'dallas',
'manager',
DATEADD(day, -1, GETDATE());
SELECT id,
ColName,
Date_Modified
FROM(
SELECT DISTINCT B.ID,
B.Name,
CASE
WHEN A.ADDRESS <> B.ADDRESS
THEN B.ADDRESS
END AS ADDRESS,
CASE
WHEN A.CITY <> B.CITY
THEN B.CITY
END AS CITY,
CASE
WHEN A.ROLE <> B.ROLE
THEN B.ROLE
END AS ROLE,
B.Date_Modified
FROM(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY Date_Modified DESC) AS ROWNUM
FROM #temp ) AS A
INNER JOIN(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY Date_Modified DESC) AS ROWNUM
FROM #temp ) AS B ON A.NAME = B.NAME
AND CHECKSUM(A.NAME, A.ADDRESS, A.CITY, A.ROLE) <> CHECKSUM(B.NAME, B.ADDRESS, B.CITY, B.ROLE)
AND A.ROWNUM = B.ROWNUM - 1 ) AS cp
UNPIVOT( data FOR ColName IN( address,
role )) AS up;
看起来您需要使用触发器。我将继续这样做…现在需要的是报告遗留数据。那么,您的表是否保存历史数据,或者只是通过覆盖字段中的数据来更新字段?在上面,我已经查询了一个审计表设计不佳!!它只维护状态的快照。它只是更新字段。它没有关于更改内容的任何信息。但是它有时间戳和更新它的用户。我添加了一些条目以确保它适用于整个集合。感谢您的解决方案。但是,我使用的是问题前面标记的sql server 2008 r2。如何检索列名已更改的新旧值?。在SQL2008 R2上,可以使用自联接替换LAG:audit_数据根据ad.id=ad_old.id-1与自身联接,前提是您知道id没有间隙。一旦有时间,我将尝试用遗留查询编辑答案。我添加了一个遗留查询,无论您的ID中是否存在漏洞,它都应该可以工作。
;with ad_cte as (
select id, address, role, Date_Modified, ROW_NUMBER() OVER (ORDER BY id) RowNo
from audit_data
),
cte as (
select ad.id,
ad.address, ad_old.address AS OldAddress,
ad.role, ad_old.role AS OldRole,
ad.Date_Modified
from ad_cte ad
join ad_cte ad_old on ad_old.RowNo + 1 = ad.RowNo
)
SELECT id, ColName, data_col, Date_Modified
FROM
(
select id, address, role, Date_Modified
from cte
-- detect any change in monitored data
where ((OldAddress IS NULL OR address <> OldAddress)
OR (OldRole IS NULL OR role <> OldRole))
-- this should be changed for generality
AND cte.id > 1
) AS cp
-- unpivot address and role into data_col column
UNPIVOT
(
data_col FOR ColName IN (address, role)
) AS up;
CREATE TABLE #temp( ID INT IDENTITY(1, 1),
NAME VARCHAR(30),
ADDRESS VARCHAR(30),
CITY VARCHAR(30),
ROLE VARCHAR(30),
Date_Modified DATETIME );
INSERT INTO #temp
SELECT 'Tom',
'something',
'austin',
'manager',
DATEADD(day, -3, GETDATE())
UNION
SELECT 'Tom',
'nothing',
'austin',
'principal',
DATEADD(day, -2, GETDATE())
UNION
SELECT 'Tom',
'anything',
'dallas',
'VP',
DATEADD(day, -1, GETDATE());
SELECT 'Jon',
'something',
'san antonio',
'assistant manager',
DATEADD(day, -3, GETDATE())
UNION
SELECT 'Jon',
'something',
'austin',
'assistant manager',
DATEADD(day, -2, GETDATE())
UNION
SELECT 'Jon',
'anything',
'dallas',
'manager',
DATEADD(day, -1, GETDATE());
SELECT id,
ColName,
Date_Modified
FROM(
SELECT DISTINCT B.ID,
B.Name,
CASE
WHEN A.ADDRESS <> B.ADDRESS
THEN B.ADDRESS
END AS ADDRESS,
CASE
WHEN A.CITY <> B.CITY
THEN B.CITY
END AS CITY,
CASE
WHEN A.ROLE <> B.ROLE
THEN B.ROLE
END AS ROLE,
B.Date_Modified
FROM(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY Date_Modified DESC) AS ROWNUM
FROM #temp ) AS A
INNER JOIN(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY Date_Modified DESC) AS ROWNUM
FROM #temp ) AS B ON A.NAME = B.NAME
AND CHECKSUM(A.NAME, A.ADDRESS, A.CITY, A.ROLE) <> CHECKSUM(B.NAME, B.ADDRESS, B.CITY, B.ROLE)
AND A.ROWNUM = B.ROWNUM - 1 ) AS cp
UNPIVOT( data FOR ColName IN( address,
role )) AS up;