【问题标题】:Convert varchar list to int in Sql Server在 Sql Server 中将 varchar 列表转换为 int
【发布时间】:2015-04-16 16:35:40
【问题描述】:

我需要一种方法来将@listOfPageIds 识别为数字列表而不是字符串。我已经尝试过强制转换,删除单引号......我真的不想在 sql 中做一个循环。

Declare @listOfPageIds varchar(50) ;

Set @listofPageIds = '2, 3, 4, 5, 6, 7, 14, 15';

select * from mytable p where p.PageId in( @listOfPageIds);

【问题讨论】:

  • 你不能使用这样的变量。您必须使用拆分器解析列表或使用动态 sql。是否可以使用用户定义的表类型而不是 csv 值列表?
  • 不管怎样,一个列表就是一个字符串。如果您需要将它们作为数字,那么您必须将它们分成单独的行。
  • 您是否搜索过任何与在 TSQL 中分隔 CSV(逗号分隔值)相关的内容?
  • 我做了...我不想在分隔符上拆分,但显然我必须这样做。

标签: sql sql-server sql-server-2008 tsql ssms


【解决方案1】:

在生产服务器上,我会编写一些用于拆分列表的表值函数,但是如果您需要快速的临时查询,这个 xml 技巧可以工作

declare @listOfPageIds varchar(50), @data xml
declare @temp table(id int)

select @listofPageIds = '2, 3, 4, 5, 6, 7, 14, 15';
select @data = '<t>' + replace(@listofPageIds, ', ', '</t><t>') + '</t>'

insert into @temp
select
    t.c.value('.', 'int') as id
from @data.nodes('t') as t(c)

select * from @temp

sql fiddle demo

【讨论】:

  • 只是想补充一点,如果您的值列表在每个逗号后不包含空格,例如select @listofPageIds = '2,3,4,5, 6, 7,14,15';,您将收到一个 sql 转换错误。以下将修复 SET @listofPageIds = replace(@listofPageIds, ' ', '') SELECT @data = '&lt;t&gt;' + replace(@listofPageIds, ',', '&lt;/t&gt;&lt;t&gt;') + '&lt;/t&gt;'
【解决方案2】:

声明@YourTable

DECLARE @yourTable TABLE (col1 INT);
INSERT INTO @yourTable VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15);

动态 SQL 解决方案

DECLARE @listOfPageIds nvarchar(255);
SET @listOfPageIds = '2, 3, 4, 5, 6, 7, 14, 15'
EXEC
(
'
DECLARE @yourTable TABLE (col1 INT);
INSERT INTO @yourTable VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
SELECT *
FROM @yourTable
WHERE col1 IN (' + @listOfPageIds+ ')'
)

递归 CTE 解决方案

DECLARE @listOfPageIds nvarchar(255);
SET @listOfPageIds = '2, 3, 4, 5, 6, 7, 14, 15'
SET @listOfPageIds = REPLACE(@listOfPageIds,' ','') + ',';  -- Put the end comma there instead of having to use a case statement in my query
                                                            -- As well as getting rid of useless white space with REPLACE()

WITH CTE
AS
(
    SELECT 1 row_count, CAST(SUBSTRING(@listOfPageIds,0,CHARINDEX(N',',@listOfPageIds,0)) AS NVARCHAR(255)) AS search_val, CHARINDEX(',',@listOfPageIds,0) + 1 AS starting_position
    UNION ALL
    SELECT row_count + 1,CAST(SUBSTRING(@listOfPageIds,starting_position,CHARINDEX(',',@listOfPageIds,starting_position) - starting_position) AS NVARCHAR(255)) AS search_val, CHARINDEX(',',@listOfPageIds,starting_position) + 1 AS starting_position
    FROM CTE
    WHERE row_count < (LEN(@listOfPageIds) - LEN(REPLACE(@listOfPageIds,',','')))
)

SELECT *
FROM @yourTable
WHERE col1 IN (SELECT CAST(search_val AS INT) FROM CTE)

结果(@yourTable 的值为 1-15):

col1
-----------
2
3
4
5
6
7
14
15

【讨论】:

  • 如果选民评论这个答案如此缺乏以至于它应该投反对票,这可能会有所帮助。
  • 我不知道。 OP 说他不想循环,但递归解决方案不是循环。所以我不知道。
  • 其实递归的 cte 用于像这样计数,和幕后的循环是一回事。 sqlservercentral.com/articles/T-SQL/74118 再加上您发布的解决方案没有返回 OP 正在寻找的数据可能也无济于事。
  • 好吧,我最终不得不对两个答案都使用类似的解决方案,并且必须循环并以表格形式返回的格式是正确的答案。我不知道如果没有这种递归就无法完成。 :) 两个答案都很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-27
  • 2013-07-21
  • 1970-01-01
相关资源
最近更新 更多