逐步更新SQL行

时间:2013-06-03 05:03:03

标签: sql sql-server tsql

我目前正在处理两张桌子。

一个表包含一组列,如ID,NAME,AGE,TEAM,SCHOOL等,在一个名为PRIMARY_TABLE的表中

我还有一个名为SECONDARY_TABLE的审计表,它记录上述值随时间的更新。

我在此表中有ATTRIBUTE,PREV_VALUES和RECORD_ID列。它具有以下属性:

  • RECORD_ID列对应于PRIMARY_TABLE
  • 的ID列
  • ATTRIBUTE列将存储正在更改的PRIMARY_TABLE列。

例如,如果我有

132 NIKO 18 LANCERS JESUIT
143 KEENAN 25 RAIDERS ROCKLAND 

在我的第一张表中

132 'AGE' 22
132 'NAME' STEVAN 

在我的第二个,

然后我想要一个具有

的组合表
132 NIKO 18 LANCERS JESUIT
132 NIKO 22 LANCERS JESUIT
132 STEVAN 22 LANCERS JESUIT
143 KEENAN 25 RAIDERS ROCKLAND .

我很难解决的问题是保留未受影响的行中的值。似乎我有任何想法将两个表连接在一起不会因此而起作用。

有什么想法?我认为唯一的解决方案是为此创建一个存储过程。如果您需要澄清,也请告诉我。

修改

还有一件事......

这是另一回事。审计表还有一个“time_of_change”列。如果多个行的ID具有相同的更改时间,那么在结果表中不应该有多行,而应该只有一行。

例如,如果我们的审计表有

132 'AGE' 22 1:00
132 'NAME' STEVAN 1:00

然后而不是

132 STEVAN 18 LANCERS JESUIT
132 NIKO   22 LANCERS JESUIT

补充说,应该只添加一行 132 STEVAN 22 LANCERS JESUIT

我想不出任何可能的方法来做到这一点。

3 个答案:

答案 0 :(得分:3)

UPDATE2 如果您在secondary_table中有一个更新日期时间的列(让我们称之为updated_at),那么您可以适当地订购结果集。

SELECT id, name, age, team, school, GETDATE() updated_at 
  FROM primary_table
UNION ALL
SELECT p.id, 
       CASE WHEN s.attribute = 'NAME'   
            THEN s.prev_values ELSE p.name END name,
       CASE WHEN s.attribute = 'AGE'    
            THEN s.prev_values ELSE p.age END age, 
       CASE WHEN s.attribute = 'TEAM'   
            THEN s.prev_values ELSE p.team END team, 
       CASE WHEN s.attribute = 'SCHOOL' 
            THEN s.prev_values ELSE p.school END school,
       updated_at
  FROM primary_table p JOIN secondary_table s
    ON p.ID = s.record_id
ORDER BY id, updated_at DESC

这是 SQLFiddle 演示

UPDATE1 一个版本UNION,条件输出为CASE

SELECT * 
  FROM primary_table
UNION ALL
SELECT p.id, 
       CASE WHEN s.attribute = 'NAME'   
            THEN s.prev_values ELSE p.name END name,
       CASE WHEN s.attribute = 'AGE'    
            THEN s.prev_values ELSE p.age END age, 
       CASE WHEN s.attribute = 'TEAM'   
            THEN s.prev_values ELSE p.team END team, 
       CASE WHEN s.attribute = 'SCHOOL' 
            THEN s.prev_values ELSE p.school END school
  FROM primary_table p JOIN secondary_table s
    ON p.ID = s.record_id
ORDER BY id

这是 SQLFiddle 演示

带有UNION s

原始版本

SELECT * 
  FROM primary_table
UNION ALL
SELECT p.id, s.prev_values, p.age, p.team, p.school
  FROM primary_table p JOIN secondary_table s
    ON p.ID = s.record_id
   AND s.attribute = 'NAME'
UNION ALL
SELECT p.id, p.name, s.prev_values, p.team, p.school
  FROM primary_table p JOIN secondary_table s
    ON p.ID = s.record_id
   AND s.attribute = 'AGE'
ORDER BY id

输出:

|  ID |   NAME | AGE |    TEAM |   SCHOOL |
-------------------------------------------
| 132 |   NIKO |  18 | LANCERS |   JESUIT |
| 132 | STEVAN |  18 | LANCERS |   JESUIT |
| 132 |   NIKO |  22 | LANCERS |   JESUIT |
| 143 | KEENAN |  25 | RAIDERS | ROCKLAND |

这是 SQLFiddle 演示

答案 1 :(得分:0)

这不完美,但试试这个:

SELECT * FROM Primary_Table
UNION ALL
SELECT * FROM
(SELECT A.ID, A.Name, B.GetAge as Age, A.School
 FROM Primary_Table A INNER JOIN (SELECT Record_id, CONVERT(int,Value) as GetAge FROM    Secondary_Table
 WHERE Attrib='AGE'  ) B
 ON A.ID = B.Record_id) UAge
 UNION ALL
SELECT * FROM
(SELECT A.ID, B.GetName as Name, A.Age, A.School
FROM Primary_Table A INNER JOIN (SELECT Record_id, Value as GetName FROM    Secondary_Table
WHERE Attrib='NAME'  ) B
ON A.ID = B.Record_id) UName
ORDER BY ID

答案 2 :(得分:0)

这是一些让你入门的脚本。你有一个很大的工作要领先于你。如果您在审计表中没有当前值(事情看起来很复杂,那么事情会变得非常困难,所以我用这个假设构建了我的脚本。)

WITH Curr AS (
   SELECT
      Record_ID = T.ID,
      V.*,
      Time_Of_Change = Convert(datetime, 0)
   FROM
      dbo.Team T
      CROSS APPLY (VALUES
         ('Name', Convert(varchar(20), T.Name)),
         ('Age', Convert(varchar(20), T.Age)),
         ('Team', Convert(varchar(20), T.Team)),
         ('School', Convert(varchar(20), T.School))
      ) V (Attribute, Prev_Values)
),
Data AS (
   SELECT
      H.Record_ID,
      H.Time_Of_Change,
      C.Attribute,
      A.Prev_Values
   FROM
      (
         SELECT DISTINCT Record_ID, Time_Of_Change
         FROM dbo.Audit
         WHERE TableName = 'Team'
         UNION ALL
         SELECT DISTINCT ID, GetDate()
         FROM dbo.Team
      ) H
      CROSS JOIN (VALUES
         ('Name'), ('Age'), ('Team'), ('School')
      ) C (Attribute)
      CROSS APPLY (
         SELECT TOP 1 *
            FROM (
              SELECT Record_ID, Attribute, Prev_Values, Time_Of_Change
              FROM dbo.Audit
              WHERE TableName = 'Team'
              UNION ALL
              SELECT *
              FROM Curr
           ) A
         WHERE
            H.Record_ID = A.Record_ID
            AND H.Time_Of_Change >= A.Time_Of_Change
            AND C.Attribute = A.Attribute
         ORDER BY
            A.Time_Of_Change DESC
      ) A
)
SELECT *
FROM
   Data
   PIVOT (Max(Prev_Values) FOR Attribute IN (Name, Age, Team, School)) P
;

See a Live Demo at SQL Fiddle

您可以非常轻松地为要重建历史记录的每个表创建一个视图。构建一个查询INFORMATION_SCHEMA.COLUMNS视图的存储过程,并构建类似于我给你的东西。在任何表更改后运行SP一次,它将更新视图。

我注意到我的脚本不太正确 - 它为编辑显示了2行而不是3行。另外,对于没有审计行的行,没有有效时间。但那部分是有道理的。在任何情况下,你都有一个很大的工作......