问题:
我有一个表记录foo
中的数据行。每次更新行时,都会插入一个新行以及修订号。该表看起来像:
id rev field
1 1 test1
2 1 fsdfs
3 1 jfds
1 2 test2
请注意,在表格中,最后一条记录是第一行的较新版本。
有没有人知道查询最新版本行的有效方法,以及特定版本的记录?例如,rev=2
的查询将返回第2,3和第4行(不是替换的第1行),而rev=1
的查询产生rev< = 1的行,如果是重复的ID,选择具有较高版本号的ID(记录:1,2,3)。
我真的不确定这在SQL Server中是否可行......
我不想以迭代的方式返回结果。
答案 0 :(得分:36)
仅获取最新修订:
SELECT * from t t1
WHERE t1.rev =
(SELECT max(rev) FROM t t2 WHERE t2.id = t1.id)
要获得特定修订,在这种情况下为1(如果某个项目没有修订版本,则为下一个最小修订版本):
SELECT * from foo t1
WHERE t1.rev =
(SELECT max(rev)
FROM foo t2
WHERE t2.id = t1.id
AND t2.rev <= 1)
这可能不是最有效的方法,但现在我无法想出更好的方法来做到这一点。
答案 1 :(得分:6)
我就是这样做的。 ROW_NUMBER()
需要SQL Server 2005或更高版本
示例数据:
DECLARE @foo TABLE (
id int,
rev int,
field nvarchar(10)
)
INSERT @foo VALUES
( 1, 1, 'test1' ),
( 2, 1, 'fdsfs' ),
( 3, 1, 'jfds' ),
( 1, 2, 'test2' )
查询:
DECLARE @desiredRev int
SET @desiredRev = 2
SELECT * FROM (
SELECT
id,
rev,
field,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rn
FROM @foo WHERE rev <= @desiredRev
) numbered
WHERE rn = 1
内部SELECT
返回所有相关记录,并在每个id
组内(即PARTITION BY
),按降序rev
计算行号。
外部SELECT
只会从每个rev
组中选择第一个成员(因此,id
}成员最多。
@desiredRev = 2
时的输出:
id rev field rn
----------- ----------- ---------- --------------------
1 2 test2 1
2 1 fdsfs 1
3 1 jfds 1
@desiredRev = 1
时的输出:
id rev field rn
----------- ----------- ---------- --------------------
1 1 test1 1
2 1 fdsfs 1
3 1 jfds 1
答案 2 :(得分:4)
如果您想要每个字段的所有最新版本,可以使用
SELECT C.rev, C.fields FROM (
SELECT MAX(A.rev) AS rev, A.id
FROM yourtable A
GROUP BY A.id)
AS B
INNER JOIN yourtable C
ON B.id = C.id AND B.rev = C.rev
对于您的示例,将返回
rev field
1 fsdfs
1 jfds
2 test2
答案 3 :(得分:3)
此处的替代解决方案会产生更新成本,但读取最新数据行的效率更高,因为它可以避免计算MAX(rev)
。当您对表的子集进行批量更新时,它也可以工作。我需要这种模式以确保我能够有效地切换到通过长时间运行的批量更新更新的新数据集,而没有任何时间窗口,我们可以看到部分更新的数据。
rev
列替换为age
列age = 0
age = -1
的新行 - 这是我长时间运行的批处理过程。UPDATE table-name SET age = age + 1
表示子集中的所有行。这会将视图切换为新的最新数据(行= 0),并在单个事务中对旧数据进行老化。age > N
的行 - 可选择清除旧数据age
然后id
创建一个复合索引,这样视图就会很好,也很快,也可以用来查找id。尽管此键实际上是唯一的,但是当您使行老化时(UPDATE SET age=age+1
期间)它暂时不是唯一的,因此您需要使其非唯一且理想情况下是聚簇索引。如果您需要查找给定id
的所有版本,则可能需要id
上的其他索引。 最后......让我们说你有糟糕的一天,批处理中断了。您可以通过运行以下命令快速恢复到以前的数据集版本:
UPDATE table-name SET age = age - 1
- 回滚版本DELETE table-name WHERE age < 0
- 清理不好的东西注意:我建议命名列名RowAge
而不是age
来表示正在使用此模式,因为它更清楚地表明它与数据库相关的值并且它补充了SQL Server的RowVersion
命名惯例。它也不会与需要返回一个人年龄的专栏或视图发生冲突。
与其他解决方案不同,此模式适用于非SQL Server数据库。
答案 4 :(得分:2)
SELECT
MaxRevs.id,
revision.field
FROM
(SELECT
id,
MAX(rev) AS MaxRev
FROM revision
GROUP BY id
) MaxRevs
INNER JOIN revision
ON MaxRevs.id = revision.id AND MaxRevs.MaxRev = revision.rev
答案 5 :(得分:1)
SELECT foo.* from foo
left join foo as later
on foo.id=later.id and later.rev>foo.rev
where later.id is null;
答案 6 :(得分:0)
这个怎么样?
select id, max(rev), field from foo group by id
查询特定版本,例如修订版1,
select id, max(rev), field from foo where rev <= 1 group by id