【发布时间】:2015-11-26 01:26:23
【问题描述】:
我在我们的 SQL Server 2008 R2 服务器中遇到了一个奇怪的错误。 varchar 到 time 的转换失败,具体取决于顶级语句的 SELECT 子句中使用的其他列。重现问题的代码
CREATE FUNCTION [dbo].[explode]
(
@haystack varchar(max),
@separator varchar(8000)
)
RETURNS
@ret TABLE
(
orderCol int identity(1,1),
value varchar(max)
)
AS
BEGIN
declare @index bigint
set @index = charindex(@separator,@haystack)
while @index > 0
begin
insert into @ret (value) values (substring(@haystack,1,@index-1))
set @haystack = substring(@haystack,@index+len(@separator),len(@haystack)-@index-len(@separator)+1)
set @index = charindex(@separator,@haystack)
end
insert into @ret (value) select @haystack
RETURN
END
还有查询:
declare @s varchar(1000) = 'a,2015-10-08,1451,1,2,3,4,5,6,7,8,9,10,11;a,2015-10-08,1721,12,13,14,15,16,17,18,19,20,21,22'
declare @units varchar(1000) = 'l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11'
set @units = '@label,@date,@hour,'+@units
;with cte as (select b.value,c.value as unit, a.orderCol as ri from dbo.explode(@s,';') a
cross apply dbo.explode(value,',') b
inner join dbo.explode(@units,',') c
on b.orderCol = c.orderCol),
topCte as (
select c4.unit as unit
,convert(varchar,(case
when len(c3.value) <= 3 then '0' + substring(c3.value,1,1) + ':' + substring(c3.value,2,2)
else (substring(c3.value,1,2) + ':' + substring(c3.value,3,2))
end+':00'),108) as [time]
,c1.value as label
,c2.value as [Date]
,c4.value
from cte c1
inner join cte c2
on c1.ri = c2.ri and c1.unit = '@label' and c2.unit = '@date'
inner join cte c3
on c1.ri = c3.ri and c3.unit = '@hour'
inner join cte c4
on c1.ri = c4.ri and c4.unit not in ('@label','@date','@hour')
)
select unit, label, [date], value, cast([time] as time)
from topCte
这将失败:
消息 241,第 16 级,状态 1,第 5 行
从字符串转换日期和/或时间时转换失败。
但是,当我将最后两行更改为其中任何一行时,它都能正常工作:
select unit, label, [date], value, [time]
from topCte
select unit, label, [date], cast([time] as time)
from topCte
我想强调的是,我完全意识到这段代码是次优的,并且我知道如何重新编写它,以便通过重写仍然满足业务需求的代码来避免错误。但是这个错误不应该以这种方式发生,我很好奇是什么触发了它。
【问题讨论】:
-
time的值是多少? -
你说你知道它不是最理想的并且你知道如何解决它。该功能需要完全重写。它看起来像是一种基于循环的分离器。我会先解决这个问题。 sqlperformance.com/2012/07/t-sql-queries/split-strings
-
@roryap - 时间由@s 的两个子字符串生成,因此作为 [time] 输入的值是 '14:51:00' 和 '17:21:00'
-
@SeanLange 我说我知道这不是最有效的,我知道如何避免这个问题,但是根据我对 SQL Server 工作原理的理解,这个问题不应该发生所以我想知道是否这是一个错误,发生这种情况的根本原因是什么。我说我知道如何修改查询——而不是如何修复它。这是2个不同的东西。该函数不需要完全重写,因为对于我正在处理的数据量来说,它已经足够高效了。我添加了它,因此代码是完全可重现的。至于您的替代方案 - 感谢您提供链接,但所提供的改进可以忽略不计。
-
如果这是您唯一需要拆分器的时候,则过早优化。多年来,我一直在使用实际的 Moden 版本,而不是那里发布的版本。由于 sql server central 的社区,它随着时间的推移而发展和改进。正如我所说,我强烈推荐它,但这是你的电话。真正的问题是当其他人看到您的拆分器并将其用于大型表格上的非常长的字符串时。表演顿时如火龙一般,让人心惊肉跳。去过那里,做到了。
标签: sql sql-server tsql sql-server-2008-r2