SQL-“;递增“;字符值导致排序错误
我正在处理一个表,其中一组任意设置存储为SQL-“;递增“;字符值导致排序错误,sql,sql-server,sql-server-2008,collation,Sql,Sql Server,Sql Server 2008,Collation,我正在处理一个表,其中一组任意设置存储为VARCHAR(255)值。我的任务是处理一个需要递增并返回给调用方的序列号。(再次注意,序列“number”存储为VARCHAR,这是我无法控制的) 因为它是一个序列号,我真的不想在单独的步骤中进行选择和更新。当我过去用实际的数字字段处理这类事情时,我的方法是 UPDATE TABLE SET @SEQ_NUM = VALUE = VALUE + 1 这会增加值,并在一个foop中提供更新的值。我想在这种情况下,我会尝试同样的基本方法: DECLARE
VARCHAR(255)
值。我的任务是处理一个需要递增并返回给调用方的序列号。(再次注意,序列“number”存储为VARCHAR
,这是我无法控制的)
因为它是一个序列号,我真的不想在单独的步骤中进行选择和更新。当我过去用实际的数字字段处理这类事情时,我的方法是
UPDATE TABLE SET @SEQ_NUM = VALUE = VALUE + 1
这会增加值,并在一个foop中提供更新的值。我想在这种情况下,我会尝试同样的基本方法:
DECLARE @SEQ_NUM VARCHAR(255)
UPDATE SOME_TABLE
SET @SEQ_NUM = VALUE = CAST((CAST(VALUE AS INT) + 1) AS VARCHAR)
WHERE NAME = 'SOME_NAME'
只要我不尝试将结果分配给变量,实际的更新就可以正常工作;一旦我这样做,我就会收到以下错误:
Msg 549,16级,状态1,第4行排序规则
接收变量的“SQL\u Latin1\u General\u CP1\u CI\u AS”不等于
“VALUE”列的排序规则“Latin1\u General\u BIN”
我明白这意味着什么,但我不明白为什么会发生这种情况,或者说,如何解决这个问题
除了修复特定错误之外,我还欢迎提供增加字符序列“编号”的替代方法的建议。手动维护序列号决不是我想使用的解决方案,但我可以理解这可能存在一些限制 如果你把它分解成两个步骤,那么你就可以解决这个问题。注意,我已将此示例代码的
WHERE
子句替换为:
CREATE TABLE #SOME_TABLE ( [VALUE] VARCHAR(255) )
INSERT INTO #SOME_TABLE
( VALUE )
VALUES ( '12345' )
DECLARE @SEQ_NUM VARCHAR(255)
UPDATE #SOME_TABLE
SET [VALUE] = CAST(( CAST([VALUE] AS INT) + 1 ) AS VARCHAR(255))
WHERE 1 = 1
SELECT *
FROM #SOME_TABLE
SELECT @SEQ_NUM = [VALUE]
FROM #SOME_TABLE
WHERE 1 = 1
SELECT @SEQ_NUM
DROP TABLE #SOME_TABLE
从其中一条评论中,听起来你可能已经意识到了这一点,但我建议如下:
UPDATE TABLE
SET VALUE = CAST((CAST(VALUE AS INT) + 1) AS VARCHAR)
OUTPUT inserted.VALUE
WHERE NAME = 'SOME_NAME'
这将像SELECT
语句一样输出新值。如果希望在SQL中执行此操作,还可以将inserted.VALUE
强制转换为int
如果要将值放入@SEQ_NUM
而不是从语句/存储过程输出值,则不能使用标量变量,但可以将其泵入表变量,如下所示:
DECLARE @SEQ_NUM AS TABLE ( VALUE VARCHAR(255) );
UPDATE TABLE
SET VALUE = CAST((CAST(VALUE AS INT) + 1) AS VARCHAR)
OUTPUT inserted.VALUE INTO @SEQ_NUM ( VALUE )
WHERE NAME = 'SOME_NAME'
SELECT VALUE FROM @SEQ_NUM
您可以继续在OP中使用古怪的update,但必须将
update
语句中的三重赋值@Variable=Column=Expression
拆分为两个简单赋值@Variable=Expression
和Column=@Variable
,如下所示
CREATE TABLE #SOME_TABLE (
NAME VARCHAR(255)
, VALUE VARCHAR(255) COLLATE Latin1_General_BIN
)
INSERT #SOME_TABLE SELECT 'SOME_NAME', '42'
DECLARE @SEQ_NUM VARCHAR(255)
/*
-- this quirky update fails on COLLATION mismatch or data-type mismatch
UPDATE #SOME_TABLE
SET @SEQ_NUM = VALUE = CAST((CAST(VALUE AS INT) + 1) AS VARCHAR)
WHERE NAME = 'SOME_NAME'
*/
-- this quirky update works in all cases
UPDATE #SOME_TABLE
SET @SEQ_NUM = CAST((CAST(VALUE AS INT) + 1) AS VARCHAR)
, VALUE = @SEQ_NUM
WHERE NAME = 'SOME_NAME'
SELECT *, @SEQ_NUM FROM #SOME_TABLE
这种简单的重写可以防止数据库引擎抱怨
@Variable
和Column
之间的数据类型差异(例如VARCHAR
vsNVARCHAR
),这似乎是一种更为“便携”的方式来进行奇怪的更新(如果有这种情况的话)为什么还要维护自己的序列号?它充满了并发性等问题。因为设计这个的人没有想到你会在这里打一场败仗。你可以使用COLLATE
关键字来解决这个问题。@SeanLange,相信我,我知道。幸运的是,这个特定的用例不会经常使用,但它仍然是一个巨大的PITA。@GordonLinoff——具体是如何使用的?我尝试对计算出的值强制进行排序,如:“SET SEQ_NUM=value=CAST((CAST(value AS INT)+1)AS VARCHAR)COLLATE SQL\u Latin1\u General\u CP1\u CI\u AS”,但收到了相同的错误。我不知道如何在变量本身上设置COLLATE值(并不是说我不知道某件事意味着什么)。我还没有试过这个替代方法,但我在考虑一种类似于您所概述的方法,除了在查询中使用表var和OUTPUT子句之外。这正是我现在正在做的。我在一个存储过程中执行此更新,需要返回值;除了将输出插入到表var中并选择返回的值之外,是否有一种简化的替代方法?如果输出没有插入到表变量中,我就不太熟悉它的操作。因此,这两个代码块将做完全相同的事情——从存储过程中输出新值。如果不需要在存储过程中操作值,则使用第一个块,当读取代码中返回的数据时(例如,通过ExecuteScalar
),它将具有新值。