在sql server中,实现列数据转换成逗号隔开字符串

本文介绍了一种在SQL Server中将用户ID串转换为对应用户名串的方法,通过自定义函数SplitToTable和GetUserName实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    项目需要,要在查询中,加上后续处理人查询条件,因为后续处理人字段存的是用户ID串,所以想用函数实现功能:根据用户ID串,返回用户姓名串

根据功能,在数据库查询窗口运行测试,sql如下:没有问题,返回用户姓名串

ContractedBlock.gifExpandedBlockStart.gifCode
DECLARE @UserIdStr VARCHAR(1024
SET @UserIdStr='su20090812001,su20090912002'
DECLARE @sql VARCHAR(2048)
set @sql=N'SELECT  UserName 
FROM Users u WHERE 
u.UserID IN (
'''+ REPLACE(@UserIdStr,',',''',''')+''')'
--PRINT @sql
declare @output varchar(8000)
create table #temp(username varchar(20))
INSERT INTO #temp EXEC(@sql)
select  @output=coalesce(@output,'')+ username+','
from #temp
drop table #temp
PRINT substring(@output,1,LEN(@output)-1)

 

结果如下:

(2 行受影响)

kevin,zhangsan

 

现在将上面的sql写成函数,@ UserIdStr是用户ID串,将上面的代码改造成函数,但编译出误。

错误为

消息2772,级别16,状态1,过程GetUserName,第19

无法从函数内访问临时表。

消息2772,级别16,状态1,过程GetUserName,第20

无法从函数内访问临时表。

消息2772,级别16,状态1,过程GetUserName,第23

无法从函数内访问临时表。

消息2772,级别16,状态1,过程GetUserName,第24

无法从函数内访问临时表。

 

表明,在函数中,不支持临时表的,将临是表改成表变量,代码如下:

 

 

ContractedBlock.gifExpandedBlockStart.gifCode
CREATE FUNCTION GetUserName
(
        
@UserIdStr VARCHAR(1024)
)
RETURNS VARCHAR(1024)
AS
BEGIN
    
DECLARE @sql VARCHAR(2048)
set @sql=N'SELECT  UserName 
FROM Users u WHERE 
u.UserID IN (
'''+ REPLACE(@UserIdStr,',',''',''')+''')'
--PRINT @sql
declare @output varchar(8000)
declare @temp TABLE (username varchar(20))
INSERT INTO @temp EXEC(@sql)
select  @output=coalesce(@output,'')+ username+','
from @temp
--drop table #temp
return substring(@output,1,LEN(@output)-1)

END

 

编译后提示错误如下:

消息443,级别16,状态14,过程GetUserName,第20

在函数内的'INSERT EXEC' 中对带副作用的或依赖于时间的运算符的使用无效。

经过上面两次修改,在函数中是可以支持表变量的,不支持exec命令,那怎么能实现上述功能呢,上面的思路主要是想根据用户ID串找到用户姓名列表,然后,再根据coalesce对表列进行处理,将一列一数据转换成字体符串,coalesce的具体用法,请到google下吧。说明有很多,这里不在介绍。

现在整理一下思路:

1.将用户ID串,转换成数据表

2.用户表与步骤1里的表进行多表查询,得到用户姓名表

3.通过coalesce转成字符串

有了思路,就开始动手了,在sql server 中,函数可以返回表变量,正好用上。给这一步的函数起个名称,就叫SplitToTable,代码如下:

 

ContractedBlock.gifExpandedBlockStart.gifCode
Create FUNCTION dbo.[SplitToTable](@arr AS VARCHAR(7999))
  
RETURNS @t TABLE(pos INT NOT NULL, nvalue VARCHAR(50NOT NULL)
AS
BEGIN
  
DECLARE @end AS INT@start AS INT@pos AS INT
  
SELECT @arr = @arr + ','@pos = 1,
    
@start = 1@end = CHARINDEX(','@arr@start)
  
WHILE @end > 1
  
BEGIN
    
INSERT INTO @t VALUES(@posSUBSTRING(@arr@start@end - @start))

    
SELECT @pos = @pos + 1,
      
@start = @end + 1@end = CHARINDEX(','@arr@start)
  
END
  
RETURN
END

 

实现了第一步,紧接着,去实现第二步了,这就好实现了,可以两表join一下,或者直接多表查询。因为是要和视图接合,所以还是写成了函数,

代码如下:

 

ContractedBlock.gifExpandedBlockStart.gifCode
create FUNCTION dbo.[GetUserName]
(
    
@UserIDstr VARCHAR(1024)
)
RETURNS VARCHAR(1024)
AS
BEGIN
    
DECLARE @temp TABLE(username VARCHAR(50))
INSERT INTO @temp
SELECT  DISTINCT UserName
 
FROM  dbo.Users u,dbo.SplitToTable(@UserIDstr) f WHERE u.UserID=f.[nvalue] –-第二步
 
 
DECLARE @output VARCHAR(1024)
 
select  @output=coalesce(@output,'')+ username+','
from @temp  --第三步
return substring(@output,1,LEN(@output)-1)

END

 

下面测试下函数,是否返回想要的结果数据,

PRINT dbo.GetUserName('su20090812001,su20090912002')

结果如下:

kevin,zhangsan

完全正确,符合功能的要求。至此,本篇的内容结束,本人对sql 不是很精通,所以想的是实现功能,可能sql 2005/2008 有更好的函数或新功能可以实现,请大家积极留言,共同交流一下。
附上测试表的创建sql语句和数据

ContractedBlock.gifExpandedBlockStart.gifCode
ExpandedBlockStart.gifContractedBlock.gif/**//*创建表*/
CREATE TABLE [dbo].[Users](
    
[ID] [int] IDENTITY(1,1NOT NULL,
    
[UserID] [varchar](20) COLLATE Chinese_PRC_CI_AS NULL,
    
[UserName] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
    
[Address] [varchar](260) COLLATE Chinese_PRC_CI_AS NULL,
 
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
    
[ID] ASC
)
WITH (IGNORE_DUP_KEY = OFFON [PRIMARY]
ON [PRIMARY]

GO
-----------------插入测试数据
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ('su20090812001','kevin','beijing')
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ( 'su20090912002','zhangsan','tianjin')
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ( 'su20090701234','wangwu','shanghai')
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ( 'su20090912004','lisi','beijing')
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ( 'su20090912005','jialiu','hebei')
INSERT [Users] ( [UserID],[UserName],[Address]VALUES ( 'su20090912007','qianlong','zhejiang')

转载于:https://www.cnblogs.com/kevinlzf/archive/2009/09/15/1566828.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值