在SQL Server中分隔单个列的值并更新它们

时间:2012-03-03 13:19:27

标签: sql sql-server

我有一个名为favorite_question的列,其更新如下:

if it is null
then insert a value
if not null then old value + , + new value

if((select Favorite_question from User_Details where User_Id = @userid) IS NULL)
begin
     update User_Details 
     set Favorite_question = (cast(@questionid as varchar(50))) 
     where User_Id = @userid
end
else
begin
     update User_Details 
     set Favorite_question = ((select Favorite_question 
                               from User_Details 
                               where User_Id = @userid ) + ',' +
                              (cast(@questionid as varchar(50)))) 
     where User_Id = @userid
end

其中@userid是用户值,@questionid是问题值

favorite_question被视为varchar(50)

我想随机删除此列中的值

例如。

如果列值为= 2,6,8,9,5并且我想从中删除8或从上面

中删除任何值

同样的SQL查询是什么。

4 个答案:

答案 0 :(得分:1)

UPDATE语句可以进行很多优化。整个“if((select ...”可以替换为:

UPDATE User_Details 
SET Favorite_question = COALESCE(Favorite_question + ',', '') + 
                        cast(@questionid as varchar(50))
where User_Id = @userid

现在开始您的真实问题:如何从Favorite_questions列中删除文本(数字)。 假设该列保存值“2,6,8,9,5”。如果要删除2,则得到',6,8,9,5',因此必须添加处理逻辑以在开头删除孤立的逗号。如果你想删除5,你会得到'2,6,8,9',所以必须添加处理逻辑来删除最后的孤立逗号。如果你想删除8,你得到'2,6,,9,5',所以必须添加处理逻辑来删除中间的双逗号之一。如果该列保存值'12,6,8,29,5,2'并且您想要删除'2',那么您不希望最终得到如下结果:'1,6,8,9,5 ”。

基本上我们应该花费大量精力从正确的文本中删除一个数字,并使文本处于干净状态(没有','6,8,9,5','2,6,9,5 '或者类似的东西)。 SQL在文本处理方面并不擅长。

基本问题是您的数据模型未规范化。您应该从User_Details表中删除列Favorite_question,并创建一个额外的表User_FavoriteQuestions(User_Id,Question_id)来为您的用户存储FavoriteQuestions。然后,您的第一个UPDATE语句将替换为

INSERT INTO User_FavoriteQuestions (User_Id, Question_id) 
VALUES(@userid, @questionid)

你真正的问题是:

DELETE FROM User_FavoriteQuestions 
WHERE User_Id = @userid AND Question_id = @questionid

一旦规范化数据模型,使用SQL操作就变得容易多了。

答案 1 :(得分:0)

好的,这种级别的字符串操作并不是SQL的强项。但是,它有可能......

首先,如果您要在多个字符串上执行此操作(或者即使是这种情况),您可能希望将其放入函数中。

为了简化,一种方法是使用一个只包含连续数字列表的数字表。这可以作为永久表,但对于这个例子,我将它显示为临时表。

declare @numberList table
(
  NumberID int
)

它可以以繁琐的方式填充,但来自http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/the-ten-most-asked-sql-server-questions--1#3

的巧妙技巧
insert into @numberList 
select number from master..spt_values
where type = 'P'

接下来,您要将原始文本分成单个部分:

declare @question varchar(20)
declare @questionTable table
(
  qNo int identity(1,1),
  qChar varchar(10)
)

set @question = '2,6,8,9,5'

set @question = ',' + @question + ','

insert into @questionTable(qChar)
select SUBSTRING(@question,NumberID + 1,CHARINDEX(',', @question, NumberID + 1) - NumberID - 1)
from @numberList
where NumberID <= LEN(@question)-1
  and SUBSTRING(@question, NumberID, 1) = ','

然后您需要确定要删除的随机部分

declare @numberCount int
declare @seed int
declare @posn int

select @numberCount = count(*) from @questionTable
set @seed = (DATEPART(mm, getdate())) * 100000 +( DATEPART(ss, getdate()) * 1000) + datepart(ms, getdate())
set @posn = (RAND(@seed) * @numberCount) + 1

然后从临时表中删除该部分:

delete from @questionTable where qNo = @posn

然后取回剩下的部分:

 declare @output varchar(20)

 select @output = coalesce(@output+',', '') + qChar
 from @questionTable

你可以不经过临时表这样做但是有很多CHARINDEX和REPLACEs ......

答案 2 :(得分:0)

拉动字符串操作需要几个步骤。

declare @S varchar(20)
declare @R varchar(20)

-- String of values
set @S = '2,6,8,9,5'
-- Value to remove
set @R = '8'

-- Add extra commas before and after
set @S = ','+@S+','
set @R = ','+@R+','

-- Remove the value
set @S = stuff(@S, charindex(@R, @S), len(@R)-1, '')

-- Remove extra commas
set @S = substring(@S, 2, len(@S)-2)

select @S

结果:

2,6,9,5

如果您需要使用并更新,可以使用交叉申请来处理以下步骤:

declare @T table
(
  S varchar(20)
)

insert into @T values('2,6,8,9,5')

declare @R varchar(20)
set @R = '8'

update T1
set S = substring(T3.S, 2, len(T3.S)-2)
from @T as T1
  cross apply (select ','+T1.S+',') as T2(S)
  cross apply (select stuff(T2.S, charindex(','+@R+',', T2.S), len(@R)+1, '')) as T3(S)

select *
from @T  

答案 3 :(得分:-1)

我最好的猜测是你可以使用Merge来更新/插入一个语句

- 合并声明

MERGE User_Details AS udp 使用(SELECT Favorite_question,User_Id FROM User_Details
  其中User_Id = @ userid)AS uds

ON udp.User_Id = uds.User_Id

匹配时 那么更新SET udp.Favorite_question = udp.Favorite_question +','+(cast(@questionid as varchar(50)))

当没有匹配时 INSERT(User_Id,Favorite_question) VALUES(uds.User_Id,(cast(@questionid as varchar(50))) );

GO

有关相同的详细信息,请参阅我的博客:

http://tryconcepts.blogspot.in/2012/03/merge-to-update-insert-using-single.html