如何在SQL Server存储过程中将varchar转换为整数?

时间:2012-01-21 21:05:47

标签: sql sql-server stored-procedures

我需要编写获取字符串的存储过程。字符串中的每个字符都必须转换为int类型,并且必须将转换后的类型插入到表中。

5 个答案:

答案 0 :(得分:4)

如何编写UDF(http://vadivel.blogspot.com/2011/10/how-to-split-delimited-string-values-in.html)来拆分分隔的字符串然后在你的内部调用它存储过程。

CREATE FUNCTION [dbo].[SplitUsingXML] 
( 
    @String VARCHAR(MAX),
    --If your delimiter is multi character
    --then change it as VARCHAR with appropriate length 
    @Delimiter CHAR(1) 
)
RETURNS @Results TABLE
(
    parsedValue VARCHAR(MAX)
)   
AS
BEGIN
    DECLARE @xml XML
    SET @XML = N'<Content><row>' + REPLACE(@String, @Delimiter, '</row><row>') + '</row></Content>'

    --If your individual value length within the CSV can be more than 25 characters
    --then you might want to increase it in the below statement
    --pls note it won't throw an error if its more than 25 characters 
    --just that it would truncate and show only the first 25 character :)
    INSERT INTO @Results(parsedValue)
    SELECT row.value('.','VARCHAR(25)') as parsedValue 
    FROM @xml.nodes('//Content/row') AS RECORDS(row)

    RETURN
END
GO

--Usage
SELECT Cast(parsedValue as INT) 
FROM [dbo].[SplitUsingXML] ('1,2,3,4',  ',')
GO

答案 1 :(得分:3)

我在这个问题上发布的数字表解决方案将是您最有效的解决方案。 Print bullet before each sentence + new line after each sentence SQL将在我回家后修补代码

修改

基本工作单元是内联表值函数。您可能听说过TVF以及它们如何在SQL Server中吮吸但与多语句类型有关。内联很好,因为优化器可以理解它们而不会制定糟糕的计划。

dbo.StringSplit返回单列(varchar)表,其值根据提供的分隔符进行拆分。如果您的数据中已有数字表或快速数字生成器,则可以减少所需的代码行(派生表L0到L5)。我假设你没有。使用numbers table to split data的技术不是我的,但我相信已完成分析的SQL杰出人物。

你要求一个proc,所以我提供dbo.StringSplitToInts来遵守,但它所做的只是用适当的参数调用TVF。您可以提取select语句并转换为内联代码或任何您需要的代码。

-- This function splits a delimited string with good performance
-- characteristics
CREATE FUNCTION dbo.StringSplit
(
    @input varchar(8000)
,   @delimiter char(1) = ','
)
RETURNS
    table
RETURN
-- L0 to L5 simulate a numbers table
-- http://billfellows.blogspot.com/2009/11/fast-number-generator.html
WITH L0 AS
(
    SELECT
        0 AS C
    UNION ALL
    SELECT
        0
)
, L1 AS
(
    SELECT
        0 AS c
    FROM
        L0 AS A
        CROSS JOIN L0 AS B
)
, L2 AS
(
    SELECT
        0 AS c
    FROM
        L1 AS A
        CROSS JOIN L1 AS B
)
, L3 AS
(
    SELECT
        0 AS c
    FROM
        L2 AS A
        CROSS JOIN L2 AS B
)
, L4 AS
(
    SELECT
        0 AS c
    FROM
        L3 AS A
        CROSS JOIN L3 AS B
)
, L5 AS
(
    SELECT
        0 AS c
    FROM
        L4 AS A
        CROSS JOIN L4 AS B
)
, NUMS AS
(
    SELECT
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS number
    FROM
        L5
)
, SOURCE_DATA (ID, content) AS
(
    -- This query simulates your input data
    -- This implementation could be simplified as our function
    -- only accepts 1 row of data but this could be applied to 
    -- any category of problem, not just a single line of input
    SELECT 1, @input 
)
, MAX_LENGTH AS
(
    -- this query is rather important. The current NUMS query generates a 
    -- very large set of numbers but we only need 1 to maximum lenth of our
    -- source data. We can take advantage of a 2008 feature of letting
    -- TOP take a dynamic value
    SELECT TOP (SELECT MAX(LEN(SD.content)) AS max_length FROM SOURCE_DATA SD)
        N.number
    FROM
        NUMS N
)
, MULTI_LINES AS
(
    -- This query will make many lines out a single line based on the supplied delimiter
    -- Need to retain the ID (or some unique value from original data to regroup it
    -- http://www.sommarskog.se/arrays-in-sql-2005.html#tblnum
    SELECT 
        SD.ID
    ,   LTRIM(substring(SD.content, Number, charindex(@delimiter, SD.content + @delimiter, Number) - Number)) AS lines
    FROM
        MAX_LENGTH
        CROSS APPLY
            SOURCE_DATA SD
    WHERE
        Number <= len(SD.content)
        AND substring(@delimiter + SD.content, Number, 1) = @delimiter
)
SELECT
    ML.lines
FROM
    MULTI_LINES ML
GO

-- This is overkill as the function is more versatile but
-- in the spirit of delivering what was asked for, this proc
-- calls the function and casts the data to the appropriate type
CREATE PROCEDURE dbo.StringSplitToInts
(
    @input varchar(8000)
,   @delimiter char(1) = ','
)
AS
BEGIN
    SET NOCOUNT ON
    SELECT
        CAST(SS.lines AS int) AS int_tokens
    FROM
        dbo.StringSplit(@input, @delimiter) SS

END
GO

-- Over 9000!
EXECUTE dbo.StringSplitToInts '100,200,300,500,9000'

答案 2 :(得分:1)

从我的想法:(未经测试)

转换:

select cast ( @myString as int)

将字符拆分为整数表:

create procedure aaa
@d nvarchar(max)

as
declare @i int
set @i=0
 declare @t table(val int)

while @i<=len(@d)



begin
insert into @t (val) select cast (SUBSTRING(@d, i, 1) as int)
set @i=@i+1
end

答案 3 :(得分:1)

您可以使用递归CTE生成字符串中的字符位置列表:

create procedure dbo.AddInts(
    @numbers varchar(max))
as
; with  list as
        (
        select  1 as pos
        where   len(@numbers) > 0
        union all
        select  pos + 1
        from    list
        where   len(@numbers) > pos
        )
insert  YourTable
        (col1)
select  cast(substring(@numbers, list.pos, 1) as int)
from    list
go

答案 4 :(得分:1)

使用XML

试试这个:

DECLARE @S varchar(max), @Split char(1), @X xml   

SELECT @S = '1,2,3,4,5', @Split = ',' 
SELECT @X = CONVERT(xml,' <root> <s>' + REPLACE(@S,@Split,'</s> <s>') + '</s>   </root> ') 
SELECT [Value] = T.c.value('.','varchar(20)') FROM @X.nodes('/root/s') T(c)