Reputation: 11
I want to update the part of the string between the hyphens in SQL Server. So I have a column named Supplier
with a value like this:
Supplier |
---|
test-abcd123-value |
I want to update it to:
Supplier |
---|
test-testing321-value |
How do you update query that?
Upvotes: 1
Views: 100
Reputation: 22177
Please try the following solution.
It will work starting from SQL Server 2017 onwards due to the use of the CONCAT_WS()
function. If needed, it is very easy to switch to the older CONCAT()
function.
It is using tokenization via XML/XQuery, and checking for exact count of tokens in the column.
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, supplier VARCHAR(50));
INSERT INTO @tbl (supplier) VALUES
('FirstToken-abcd123-ThirdToken'),
('FirstToken-yaddyyaddy-ThirdToken'),
('FirstToken-bla bla bla-ThirdToken'),
('FirstToken-DoNothing');
-- DDL and sample data population, end
-- before
SELECT * FROM @tbl;
DECLARE @separator CHAR(1) = '-'
, @replaceWith varchar(20) = 'NewMiddleToken';
;WITH rs AS
(
SELECT *
, new_supplier = CONCAT_WS(@separator
, c.value('(/root/r[1]/text())[1]', 'VARCHAR(30)')
, @replaceWith
, c.value('(/root/r[3]/text())[1]', 'VARCHAR(30)'))
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(supplier, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
CROSS APPLY (SELECT c.value('count(/root/r)', 'INT')) AS t3(cnt)
WHERE cnt = 3
)
UPDATE t
SET t.supplier = rs.new_supplier
FROM @tbl AS t INNER JOIN
rs ON t.ID = rs.ID;
--after
SELECT * FROM @tbl;
Output
ID | supplier |
---|---|
1 | FirstToken-NewMiddleToken-ThirdToken |
2 | FirstToken-NewMiddleToken-ThirdToken |
3 | FirstToken-NewMiddleToken-ThirdToken |
4 | FirstToken-DoNothing |
Upvotes: 0
Reputation: 29943
You may try to get the positions of the hyphens using CHARINDEX()
and update the text using STUFF()
and appropriate calculations:
; WITH cte AS (
SELECT
Supplier,
CHARINDEX('-', Supplier) AS p1,
CHARINDEX('-', Supplier, CHARINDEX('-', Supplier) + 1) AS p2
FROM Data
)
UPDATE cte
SET Supplier = STUFF(Supplier, p1 + 1, p2 - p1 - 1, 'newvalue')
WHERE p1 > 0 AND p2 > 0
Upvotes: 1
Reputation: 12014
You could find the positions of the hyphens,
with that get the part you want to replace,
and then use the replace function
The query below shows all the necessary stages that you need
declare @test table (supplier varchar(50))
insert into @test (supplier) values ('test-abcd123-value'), ('test-yaddyyaddy-value2'), ('test-bla bla bla-value'), ('test-nothing')
select t.supplier,
t.startpos,
t.length,
substring(t.supplier, t.startpos, t.length) as to_replace,
replace(t.supplier, substring(t.supplier, t.startpos, t.length), 'testing321') end_result
-- it would be so nice if you could write it like this, but you have te repeat the statement above here or make yet another subquery
--replace(t.supplier, to_replace, 'testing321') end_result
from ( select t.supplier,
charindex('-', supplier) + 1 startpos,
(charindex('-', supplier, charindex('-', supplier) + 1)) - (charindex('-', supplier)) - 1 length
from @test t
) t
where t.startpos > 0
and t.length > 0
this results in
supplier | startpos | length | to_replace | end_result |
---|---|---|---|---|
test-abcd123-value | 6 | 7 | abcd123 | test-testing321-value |
test-yaddyyaddy-value2 | 6 | 10 | yaddyyaddy | test-testing321-value2 |
test-bla bla bla-value | 6 | 11 | bla bla bla | test-testing321-value |
in case you want to show all rows, also the ones you can not replace, you can use this
declare @test table (supplier varchar(50))
insert into @test (supplier) values ('test-abcd123-value'), ('test-yaddyyaddy-value2'), ('test-bla bla bla-value'), ('test-nothing')
select t.supplier,
t.startpos,
t.length,
case when t.startpos > 0 and t.length > 0 then
substring(t.supplier, t.startpos, t.length)
else null
end as to_replace,
case when t.startpos > 0 and t.length > 0 then
replace(t.supplier, substring(t.supplier, t.startpos, t.length), 'testing321')
else t.supplier
end as end_result
from ( select t.supplier,
charindex('-', supplier) + 1 startpos,
(charindex('-', supplier, charindex('-', supplier) + 1)) - (charindex('-', supplier)) - 1 length
from @test t
) t
and the result is
supplier | startpos | length | to_replace | end_result |
---|---|---|---|---|
test-abcd123-value | 6 | 7 | abcd123 | test-testing321-value |
test-yaddyyaddy-value2 | 6 | 10 | yaddyyaddy | test-testing321-value2 |
test-bla bla bla-value | 6 | 11 | bla bla bla | test-testing321-value |
test-nothing | 6 | -6 | test-nothing |
Upvotes: 0