【问题标题】:How to convert TIMESTAMP values to VARCHAR in T-SQL as SSMS does?如何像 SSMS 一样在 T-SQL 中将 TIMESTAMP 值转换为 VARCHAR?
【发布时间】:2016-12-07 10:05:30
【问题描述】:

我正在尝试将表中的 TIMESTAMP 字段转换为字符串,以便可以将其作为动态 SQL 的一部分打印或执行。 SSMS 是能够做到的,所以必须有一个内置的方法来做到这一点。但是,我无法使用 T-SQL 让它工作。

以下正确显示表格结果:

SELECT TOP 1 RowVersion FROM MyTable

它显示0x00000000288D17AE。但是,我需要将结果作为更大字符串的一部分。

DECLARE @res VARCHAR(MAX) = (SELECT TOP 1 'test' + CONVERT(BINARY(8), RowVersion) FROM MyTable)
PRINT(@res)

这会产生一个错误:The data types varchar and binary are incompatible in the add operator

DECLARE @res VARCHAR(MAX) = (SELECT TOP 1 'test' + CONVERT(VARCHAR(MAX), RowVersion) FROM MyTable)
PRINT(@res)

这会产生乱码:test (®

实际上,空格只是空字符并终止字符串,以便使用EXEC()运行动态SQL。

DECLARE @sql VARCHAR(MAX) = 'SELECT TOP 1 ''test'' + CONVERT(VARCHAR(MAX), RowVersion) FROM MyTable'
EXEC (@sql)

这只是显示带有单词“test”的表格结果。因为CONVERT函数首先返回终止空字符,所以动态SQL中“test”之后的所有内容都被截断了。

显然,我希望得到的字符串是“test0x00000000288D17AE”,甚至是十进制等值,在这种情况下是“test680335278”。

任何想法将不胜感激。

【问题讨论】:

  • SSMS 不进行任何此类转换。它像 任何 其他 .NET 应用程序一样在网格中显示数据。二进制值通常显示为十六进制或 Base64。为什么要将二进制值转换为字符串?为什么不按原样传递,或者将其用作参数? BTW rowversion 也不能用作标识符,如果您认为可以将其用作人类可读的键
  • rowversion 是一个binary(8) 值,就像bigint 一样。您可以将其转换为 bigint,然后使用FORMAT 来获取其十六进制表示,例如FORMAT(cast(RowVersion)as bigint),"x")FORMAT(cast(cast(RowVersion as binary(8))as bigint),"x")。格式不会用零填充字符串
  • 虽然没有记录,但我相信master.sys.fn_varbintohexstr 会将任何VARBINARY 类型值转换为NVARCHAR 值。请参阅here 了解有关此功能如何工作的一些信息以及源代码。

标签: sql-server tsql ssms nvarchar sql-timestamp


【解决方案1】:

SELECT 'test' + CONVERT(NVARCHAR(MAX), CONVERT(BINARY(8), RowVersion), 1)。诀窍是1CONVERT 作为样式,根据documentation。 (通过2 省略0x。)

【讨论】:

  • 你试过了吗?它返回Explicit conversion from data type timestamp to nvarchar(max) is not allowed。如果我将其更改为VARCHAR,则没有错误,但仍然显示问题中所述的垃圾。
  • @Neo:我的错,我错误地认为 SQL Server 会将ROWVERSION 视为二进制类型。它没有,因此需要一个中间转换步骤才能使其工作。
  • @Neo:依赖未记录的函数显然比依赖CONVERT 的内置功能更糟糕。当然,您接受什么取决于您,但我知道在生产环境中我更喜欢什么。
  • @Neo 你试过编辑版的Jeroen Mostert 解决方案吗?它适用于我的附加步骤 CONVERTing 到 BINARY(8) 首先,然后是 CONVERTing 到 NVARCHAR... 因此,由于 Jeroen 上面给出的原因,我将这个答案赞成为我相信它比我自己的要好。
  • 好吧,这次我错了。是的,编辑后的版本有效。事实上,我现在更喜欢这个答案,因为十六进制字母保持大写(看起来更好)。它不是生产代码(它只是一个在开发中帮助我的脚本),但我更喜欢以最正确的方式做事,我认为就是这样。我会将已接受的答案更改为这个答案,但仍然支持你的答案,@3N1GM4。谢谢你的诚实!
【解决方案2】:

如 cmets 中所述,未记录的函数 master.sys.fn_varbintohexstr 会将二进制转换为字符串,以便您可以与其他字符串值连接:

DECLARE @binary BINARY(8)
SELECT @binary = CAST(1234567890 AS BINARY(8))

SELECT @binary AS BinaryValue, 
       LEFT(master.sys.fn_varbintohexstr(@binary),2) + UPPER(RIGHT(master.sys.fn_varbintohexstr(@binary),LEN(master.sys.fn_varbintohexstr(@binary))-2)) AS VarcharValue,
       'test' + LEFT(master.sys.fn_varbintohexstr(@binary),2) + UPPER(RIGHT(master.sys.fn_varbintohexstr(@binary),LEN(master.sys.fn_varbintohexstr(@binary))-2)) AS ConcatenatedVarcharValue

我继续拆分前两个字符,并没有对它们应用UPPER 函数,以准确再现二进制值时显示的格式。

结果:

/--------------------------------------------------------------------\
|     BinaryValue    |    VarcharValue    | ConcatenatedVarcharValue |
|--------------------+--------------------+--------------------------|
| 0x00000000499602D2 | 0x00000000499602D2 |  test0x00000000499602D2  |
\--------------------------------------------------------------------/

【讨论】:

  • 谢谢。 SELECT TOP 1 'test' + master.sys.fn_varbintohexstr(RowVersion) FROM MyTable 得到了我所需要的。
【解决方案3】:

看看这个:

SELECT 
substring(replace(replace(replace(replace(cast(CAST(GETDATE() AS datetime2) as 
varchar(50)),'-',''),' ',''),':',''),'.',''),1,18)

【讨论】:

  • 在答案中添加解释,说明其工作原理。
猜你喜欢
  • 2018-02-24
  • 1970-01-01
  • 2010-09-16
  • 2018-02-10
  • 2013-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多