使用SQL Server 2008 +。
我有一个rowversion列(也就是时间戳),我从数据库中检索并使用以下代码转换为数字(20,0):
CONVERT(NUMERIC(20,0), RowVersionColumn + 0) AS [RowVersion]
稍后,我需要将该数值(存储在ADO.NET DataSet中作为ulong / UInt64),并将其转换回rowversion数据类型。
但这会产生问题。看起来好像你可以转换为数字(20,0),反向操作无法产生正确的值。例如:
DECLARE @MyNumericValue NUMERIC(20,0)
DECLARE @MyRowVersionValue ROWVERSION
SET @MyNumericValue = 12345
SET @MyRowVersionValue = CONVERT(rowversion, @MyNumericValue)
PRINT CONVERT(NUMERIC(20,0), @MyRowVersionValue + 0)
运行此代码打印出值959447040,而不是12345.从CONVERT语句中删除“+ 0”会产生正确的结果,但我仍然无法可靠地获取曾经是rowversion的数值把它变回一个rowversion,其值应该是它应该是。
以下是此问题的更好演示:
DECLARE @MyNumericValue NUMERIC(20,0)
DECLARE @MyRowVersionValue ROWVERSION
DECLARE @MyRowVersionValue2 ROWVERSION
SET @MyRowVersionValue = @@DBTS
SET @MyNumericValue = CONVERT(NUMERIC(20,0), @MyRowVersionValue + 0)
SET @MyRowVersionValue2 = CONVERT(rowversion, @MyNumericValue)
SELECT @MyRowVersionValue
SELECT @MyNumericValue
SELECT @MyRowVersionValue2
您的结果将根据您的输入而有所不同,但作为示例,我的输出是:
0x0000000003ADBB2F
61717295
0x140000012FBBAD03
第一个和最后一个值应匹配,但它们不匹配。我猜这与二进制数据转换经常导致填充这一事实有关,而这个填充改变了值。参见:
http://msdn.microsoft.com/en-us/library/aa223991(v=SQL.80).aspx
思想?
编辑:澄清一下,我正在处理rowversion / timestamp的事实是偶然的。 BINARY(8)而不是ROWVERSION也会出现同样的问题,因为它们是等效的数据类型。
答案 0 :(得分:2)
虽然我不明白为什么你会将无意义的ROWVERSION值转换为数字然后再转回,你是否尝试使用BIGINT - 它匹配UInt64所需的8个字节而不是可变字节数(取决于强制NUMERIC(20,0)的实际值会将其更改为?
CREATE TABLE dbo.rv(a INT, rv ROWVERSION);
INSERT dbo.rv(a) SELECT 1 UNION SELECT 2;
WITH x AS
(
SELECT
rv,
rv_as_bigint = CONVERT(BIGINT, rv)
FROM dbo.rv
)
SELECT
rv,
rv_as_bigint,
rv_back_to_rv = CONVERT(ROWVERSION, rv_as_bigint)
FROM x;
DROP TABLE dbo.rv;
或者拿走原始样本并将BIGINT换成NUMERIC(20,0):
DECLARE @MyNumericValue BIGINT
DECLARE @MyRowVersionValue ROWVERSION
DECLARE @MyRowVersionValue2 ROWVERSION
SET @MyRowVersionValue = @@DBTS
SET @MyNumericValue = CONVERT(BIGINT, @MyRowVersionValue) -- removed the +0 hack
SET @MyRowVersionValue2 = CONVERT(rowversion, @MyNumericValue)
SELECT @MyRowVersionValue
SELECT @MyNumericValue
SELECT @MyRowVersionValue2
答案 1 :(得分:2)
当您将数据转换为binary
时(rowversion
基本上是binary(8)
),您将获得其内部表示而非逻辑值。您可以使用以下代码段验证行为:
DECLARE @MyNumericValue NUMERIC(20,0) = 0
SELECT @MyNumericValue, CONVERT(binary(8), @MyNumericValue)
或者你可以尝试
DECLARE @MyBinary binary(8) = 0x00
SELECT @MyBinary, CONVERT(numeric(20,0), @MyBinary)
根本不会转换。 那么,你的脚本真正发生的是:
SET @MyNumericValue = 12345
-- @MyRowVersionValue gets the internal representation of the numeric value 12345
SET @MyRowVersionValue = CONVERT(rowversion, @MyNumericValue)
-- +0 converts the binary value to int, then performs int-to-numeric conversion
PRINT CONVERT(NUMERIC(20,0), @MyRowVersionValue + 0)
-- Real binary-to-numeric conversion.
PRINT CONVERT(NUMERIC(20,0), @MyRowVersionValue)
真正的二进制到数字转换是安全的,但在您的情况下,您可能希望将rowversion转换为bigint
(或忘记数值并将其存储为二进制字符串)比numeric
,因为CONVERT(NUMERIC(20,0), @MyRowVersionValue)
并没有真正为您提供数值。