当前位置: 首页 > 面试题库 >

从字符串转换为SQL Server中的uniqueidentifier错误时转换失败

令狐俊风
2023-03-14
问题内容

我一直收到错误消息“从字符串转换为uniqueidentifier时转换失败”,终于到了尽头。我已将问题缩小到尽可能小的范围,同时使错误保持不变。如果要复制,请先从此处安装CSV拆分器:

http://www.sqlservercentral.com/articles/Tally+Table/72993/

这是测试代码。我使用的是SQL 2008R2,但位于与SQL 2005兼容的数据库中:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ZZZTESTTABLE]') AND type in (N'U'))
DROP TABLE [dbo].[ZZZTESTTABLE]
GO

CREATE TABLE [dbo].[ZZZTESTTABLE](
    [Col1] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_ZZZTESTTABLE] PRIMARY KEY CLUSTERED 
(
    [Col1] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

-- Test table that I would like to check my values against
insert dbo.ZZZTESTTABLE(Col1) values('85B049B7-CDD0-4995-B582-5A74523039C0')

-- Test string that will be split into table in the DelimitedSplit8k function
declare @temp varchar(max) = '918E809E-EA7A-44B5-B230-776C42594D91,6F8DBB54-5159-4C22-9B0A-7842464360A5'

-- I'm trying to delete all data in the ZZZTESTTABLE that is not in my string but I get the error 
delete dbo.ZZZTESTTABLE
where Col1 not in 
(
-- ERROR OCCURS HERE
    select cast(Item as uniqueidentifier) from dbo.DelimitedSplit8K(@temp, ',')
)

这里是DelimitedSplit8K函数的来源,因此您不必去查找它:

CREATE FUNCTION dbo.DelimitedSplit8K
--===== Define I/O parameters
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
     -- enough to cover VARCHAR(8000)
  WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "zero base" and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT 0 UNION ALL
                 SELECT TOP (DATALENGTH(ISNULL(@pString,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT t.N+1
                   FROM cteTally t
                  WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) 
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
        Item       = SUBSTRING(@pString,s.N1,ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000))
   FROM cteStart s
;

问题答案:

实际上,使用此UDF确实对执行顺序进行了程序假设。假定将在WHEREUDF 之前 对UDF中的子句进行求值cast(item as uniqueidentifier)。这种假设是错误的,因为优化器可以随意更改将WHERE子句移到演员表上方的计划,并且最终的结果是,要求演员表将部分标记转换为GUID(即类似的字符串18E809E-EA7A-44B5-B230-776C42594D91)。

有关更详细的答案,请阅读T-SQL函数并不表示一定的执行顺序。

解决方法是,对于不符合WHERE子句的行,可以将NULL强制放入UDF的投影值中:

CREATE FUNCTION dbo.DelimitedSplit8K
...
cteStart(N1, nullify) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT t.N+1, 
                    case when (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) then 1 else 0 end
                   FROM cteTally t
                  WHERE (SUBSTRING(@pString,t.N,1) = @pDelimiter OR t.N = 0) 
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1),
        Item       = case s.nullify
            when 1 then SUBSTRING(@pString,s.N1,ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000))
            else null
            end
   FROM cteStart s;
go

因为可以保证在CAST之前对CASE表达式进行求值(因为CAST的输入是CASE的输出),所以WHERE子句的重新排序是安全的。



 类似资料:
  • 问题内容: 在SQL 9(2005)中创建了一个存储过程,此后已升级到SQL 10(2008)。从那时起,以下存储过程停止工作并引发上述错误: 传入的参数@vPortalUID包含:2A66057D-F4E5-4E2B-B2F1-38C51A96D385。我执行这样的存储过程: 它跌倒了。我也尝试过转换。仍然没有喜悦。也具有将{}括起来的价值。我如上所述以编程方式和手动方式删除了这些内容。 如果您

  • 问题内容: 我有一个相当简单的分页查询,用于从表中获取行 该参数决定结果应按哪一列排序。 和都是日期时间字段。但是是varchar字段。 对于两个datetime字段,查询运行都很好,但是当出现以下错误时: “从字符串转换日期和/或时间时转换失败。” 我遇到的问题是我没有尝试转换任何东西吗? 问题答案: 您需要将您的语句划分为多个语句: 这是因为单个语句要求所有分支都具有兼容的数据类型。由于一个字

  • 嗨,伙计们,我有一个错误,当我试图发送数组字符串与猫鼬模式其工作正常的标签,而不是selectedFile... 猫鼬模式: controller.js 类型js 对于测试,我将dammy值设置为[“imgar”],并收到以下错误消息:“PostMessage验证失败:selectedFile:在路径“selectedFile”处为值“['imgar']”(键入数组)转换为字符串失败 我能做什么?

  • 我正在尝试加密和解密存储在SQL中的密码。解码时,我收到一个错误。输入不是有效的Base-64字符串,因为它包含一个非Base-64字符、两个以上的填充字符或填充字符中的非法字符。位于System.Convert.FromBase64_Decode。 解密代码: 加密代码: 列的数据类型为

  • 问题内容: 我试图创建一个表,如下所示, 首先,我尝试如下插入值, 它给出了错误的说法, 无法将varchar转换为日期时间 然后,我尝试使用以下格式作为我们stackoverflow建议的帖子之一, 但是我仍然收到错误消息, 从字符串转换日期和/或时间时转换失败 有什么建议? 问题答案: SQL Server支持多种格式-有关CAST和CONVERT的信息,请参见MSDN联机丛书。这些格式中的大

  • 我得到这个错误,你能找到我做错了什么。 无法转换“java”类型的值。lang.String“”转换为所需的java类型。时间LocalDate的嵌套异常为java。lang.IllegalStateException:无法转换“java”类型的值。lang.String“to required type”java。时间LocalDate“:未找到匹配的编辑器或转换策略。