我想要检索最近添加的客户。我没有任何列存储添加行的日期/时间,而我的主键是Cust_ID
,它不是IDENTITY
列,不一定按升序输入。
这是我的表Customer
,并且想象已按此顺序添加了三行:
Cust_ID Cust_Name Cust_Age
-------------------------------------
2 C 23
6 A 25
3 B 22
在上面的示例中,我想获得最后一条记录(B
)。 SQL Server中是否有任何预定义函数将返回表的最后一行(不依赖于升序)?
答案 0 :(得分:14)
不,SQL Server中没有预定义函数可以返回表的“最后一行”。
根据定义,表是一组无序行。想象一下,你把一堆弹珠放在一个袋子里。现在打开包,然后问别人哪个大理石先进或最后进去。现在把它们扔到地板上,当其他人进入房间时,请问他们是先到底还是最后一个。你不能这样做,因为没有额外的信息表明他们倒下的顺序。
对于SQL Server中的表也是如此。除非您添加IDENTITY列,日期时间列或触发器,或使用外部功能(如更改跟踪,CDC,审核等),否则SQL Server无法告诉您最后插入了哪一行。您可以认为只是从没有order by子句的表中选择看起来就像它以正确的顺序返回数据一样,这是纯粹的巧合。这是一个例子:
CREATE TABLE dbo.floobat
(
ID INT PRIMARY KEY,
n VARCHAR(16),
x CHAR(4000) NOT NULL DEFAULT ''
);
INSERT dbo.floobat(ID,n) VALUES(1,'Sparky');
INSERT dbo.floobat(ID,n) VALUES(2,'Aaron');
INSERT dbo.floobat(ID,n) VALUES(3,'Norbert'); -- <-- inserted last
SELECT ID, n FROM dbo.floobat;
好的,所以默认情况下,这似乎没问题。结果:
ID n
-- -------
1 Sparky
2 Aaron
3 Norbert -- < yes, this is right
但是,让我们对表格进行更改,您的应用程序或其他依赖于上述顺序的其他内容将不知道:
CREATE NONCLUSTERED INDEX x ON dbo.floobat(n);
SELECT ID, n FROM dbo.floobat;
哦,哦!结果:
ID n
-- -------
2 Aaron
3 Norbert
1 Sparky -- < oops, this is no longer right
您必须记住这一点:如果您不包含ORDER BY子句,那么告诉 SQL Server您不关心订单。因此,它将找到返回数据的最有效方法,这可能会导致不同的观察顺序。添加上面的索引为SQL Server提供了更好的检索数据的访问路径。它仍然使用扫描,但该索引比聚集索引(它只能在页面上容纳两行)更瘦。
即使没有索引,您也可能无法获得预期的结果,因为您的Cust_ID
列未按升序插入,这是错误的。因此,如果您插入5
而不是2
,则选择不使用ORDER BY实际上会导致2
然后5
(假设不存在更好的索引)。
除了创建(或删除,更改或重建)索引之外的其他事情可能会导致排序行为发生同样的变化。应用Service Pack,CU或修补程序;刷新程序缓存;使用各种RECOMPILE选项;更新统计;重启服务器;添加或禁用跟踪标志;更改服务器选项选项;将数据库移动到其他服务器;等等。
因此,如果您想要跟踪这些信息,您需要以某种方式自己添加它,因为其他几个答案已经解决了。
答案 1 :(得分:3)
除非您的表格中有IDENTITY
或DateTime
列,否则您无法获得最后一行插入。
答案 2 :(得分:3)
如果表中没有可用的元数据,并且您无法编辑架构以提供时间戳或标识列,那么您应该依赖SQL Server的元数据生成机制。一个是CDC。
CDC代表change data capture,正如名称所示,它可以帮助您了解已应用于数据的任何更改。我认为您可以使用此元数据来了解插入表中的最新记录。
答案 3 :(得分:2)
或者
或
答案 4 :(得分:2)
如果您无法更改表架构,则可以考虑添加一个具有相同架构的新表,该架构仅存储最后插入的记录,