简体   繁体   中英

Separating values of a single column in SQL Server and updating the same

I have a column called favorite_question which is updated as following:

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

where @userid is users value and @questionid is question value

favorite_question is taken as varchar(50)

I want to remove a value from this column randomly

for eg.

if column values are = 2,6,8,9,5 and I want to remove 8 from it or any from the above

what would be the sql query for the same.

The UPDATE statement can be optimised a lot. The whole "if((select ..." can be replaced by:

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

Now on for your real question: how to remove text (a number) from the Favorite_questions column. Suppose the column holds the value '2,6,8,9,5'. If you want to remove the 2, you get ',6,8,9,5', so one has to add processing logic to remove the orphaned comma at the beginning. If you want to remove the 5, you get '2,6,8,9,', so one has to add processing logic to remove the orphaned comma at the end. If you want to remove the 8, you get '2,6,,9,5', so one has to add processing logic to remove one of the double comma's in the middle. What if the column holds the value '12,6,8,29,5,2' and you want to remove '2', you would not want to end up with something like: '1,6,8,9,5'.

Basically we should spend A LOT of effort to get removing a number from that text correct and leave the text in a clean state (no ',6,8,9,5', '2,6,,9,5' or the like). SQL is not that good at text processing.

The basic problem is that your data model is not normalised. You should remove the column Favorite_question from the User_Details table and create an extra table User_FavoriteQuestions (User_Id, Question_id) to store the FavoriteQuestions for your users. Your first UPDATE statement would then be replaced by

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

Your real question becomes:

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

Once you normalise your data model, manipulating it with SQL becomes a lot easier.

Ok, this level of string manipulation isn't really SQL's forte. However, it is possible...

Firstly, if you're going to do this on more than a single string (or even if that is the case) you may want to put this into a function.

To make it easier, one approach is to have a number table that contains just a list of consecutive numbers. This can be made as a permanent table but for this example I'm showing it as temporary.

declare @numberList table
(
  NumberID int
)

It can be populated in a tedious fashion but a neat trick from 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'

Next you want to separate out the original text into the individual parts:

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) = ','

Then you need to determine a random part to remove

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

Then remove the part from the temporary table:

delete from @questionTable where qNo = @posn

Then get back the remaining parts:

 declare @output varchar(20)

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

You can do this without going via temporary tables but there are a lot of CHARINDEXs and REPLACEs...

There are a couple of steps needed to pull the string manipulation of.

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

Result:

2,6,9,5

If you need to do this with and update you can use cross apply to handle the steps:

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  

My best guess is that you can use Merge to Update / Insert using a single statement

-- Merge Statement

MERGE User_Details AS udp USING (SELECT Favorite_question, User_Id FROM User_Details
where User_Id = @userid ) AS uds

ON udp.User_Id = uds.User_Id

WHEN MATCHED THEN UPDATE SET udp.Favorite_question = udp.Favorite_question +',' + (cast(@questionid as varchar(50)))

WHEN NOT MATCHED THEN INSERT(User_Id ,Favorite_question ) VALUES(uds.User_Id ,(cast(@questionid as varchar(50))) );

GO

For same details see my blog:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM