SQL - "递增" char值导致排序错误

时间:2014-11-26 16:38:45

标签: sql sql-server sql-server-2008 collation

我正在处理一个表,其中一堆任意设置存储为VARCHAR(255)值。我负责处理的特定代码是需要递增并返回给调用者的序列号。 (再次注意,序列“number”存储为VARCHAR,这是我无法控制的。)

因为它是一个序列号,我真的不想在单独的步骤中选择和更新。当我过去用实际的数字字段处理过这种事情时,我的方法就像是

UPDATE TABLE SET @SEQ_NUM = VALUE = VALUE + 1

增加值并在一个swell 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,Level 16,State 1,Line 4 The collat​​ion   接收变量的'SQL_Latin1_General_CP1_CI_AS'不等于   列'VALUE'的排序规则'Latin1_General_BIN'。

我理解这意味着什么,但我不明白为什么会发生这种情况,或者通过扩展,如何解决这个问题。

除了修复特定错误之外,我欢迎提出增加char序列“数字”的替代方法的建议。

3 个答案:

答案 0 :(得分:1)

从其中一条评论中,您可能已经听过这样的声音,但这是我的建议:

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

答案 1 :(得分:0)

手动维护序列号绝不是我想要使用的解决方案,但我可以理解可能存在约束。

如果将其细分为2个步骤,那么您可以解决此问题。注意我已将此示例代码的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

答案 2 :(得分:0)

您可以继续在OP中使用古怪的更新,但必须将@Variable = Column = Expression语句中的三重分配UPDATE拆分为@Variable = ExpressionColumn = @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

这种简单的重写可以防止db-engine抱怨@VariableColumn之间的数据类型差异(例如VARCHARNVARCHAR),并且看起来更像是“便携式”的方式进行古怪的更新(如果有的话)