1

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

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

而且我还有一个名为 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.

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

4

3 回答 3

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演示

于 2013-06-03T05:53:24.577 回答
0

This is not perfect but try this one:

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
于 2013-06-03T06:08:55.980 回答
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
;

在 SQL Fiddle 上查看现场演示

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

我注意到我的脚本不太正确——它显示 2 行而不是 3 行进行编辑。另外,没有审计行的行没有有效时间。但这部分是有道理的。无论如何,你有一份大工作摆在你面前……

于 2013-06-04T00:34:03.853 回答