Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 动态选择更改的列名_Sql_Tsql_Sql Server 2008 R2 - Fatal编程技术网

Sql 动态选择更改的列名

Sql 动态选择更改的列名,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 ;

我有一张如下所示的表格

ID名称地址城市角色日期\u已修改 1汤姆·奥斯汀经理X

2汤姆·奥斯汀校长

3汤姆:达拉斯副总裁

如何编写查询以选择在条目1、2和3之间更改的列名?目前,我正在编写一份需要识别变化的报告。这就是我到目前为止所拥有的,并且需要与之合作

我需要能够通过存储过程进行检测,并查看下面的输出

Id列名称已更改 2地址Y

2角色Y

3地址Z


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;