-3

Suppose there are two tables

TableA

Id XML

1 <A x="$Y" B="$Z" />

TableB

Id Key Value

1  $Y   100

1  $Z   200

Id columns in TableA and TableB can be joined.

The expected output is

TableA

Id XML

1 <A x="100" B="200" />
6
  • 1
    What have you tried so far? What's wrong with REPLACE? Commented Sep 4, 2019 at 15:40
  • @Larnu - Replace is not letting me make use of ID columns efficiently. I have to first get the String dynamically (understand where does $ start and when the quotes end) and then go to another table and then match the string. Considerably slow. Commented Sep 4, 2019 at 15:43
  • stackoverflow.com/questions/1956978/… and stackoverflow.com/questions/51835718/… Commented Sep 4, 2019 at 15:44
  • @TabAlleman - Let me go through them. Commented Sep 4, 2019 at 15:46
  • @Larnu - Can we join these tables on a TableA.ID = TableB.ID in REPLACE function ? Commented Sep 4, 2019 at 15:50

1 Answer 1

1

The link supplied by Tab Alleman does show you the basic idea here. You need to use REPLACE and a Recursive Common Table Expression (rCTE):

CREATE TABLE TableA (Id int,
                     [XML] xml);
CREATE TABLE TableB (Id int,
                     [Key] varchar(5),
                     [Value] varchar(20));
INSERT INTO dbo.TableA (Id,
                        [XML])
VALUES(1,'<A x="$Y" B="$Z" />');

INSERT INTO dbo.TableB (Id,
                        [Key],
                        [Value])
VALUES (1,'$Y','100'),
       (1,'$Z','200');
GO


WITH RNs AS(
    SELECT B.Id,
           B.[Key],
           B.[Value],
           ROW_NUMBER() OVER (PARTITION BY B.Id ORDER BY [Key]) AS RN
    FROM dbo.TableB B),
rCTE AS(
    SELECT A.Id,
           REPLACE(CONVERT(varchar(MAX),A.[XML]),RN.[Key], RN.[Value]) AS [XML],
           RN.RN
    FROM dbo.TableA A
         JOIN RNs RN ON A.Id = RN.Id
    WHERE RN.RN = 1
    UNION ALL
    SELECT r.Id,
           REPLACE(r.[XML],RN.[Key], RN.[Value]) AS [XML],
           RN.RN
    FROM rCTE r
         JOIN RNs RN ON r.Id = RN.Id
                    AND RN.RN = r.RN + 1)
SELECT Id,
       CONVERT(xml,[xml]) AS [XML]
FROM rCTE r
WHERE RN = (SELECT MAX(RN) FROM rCTE E);

GO

DROP TABLE dbo.TableA;
DROP TABLE dbo.TableB;

As an UPDATE statement, this would like this:

WITH RNs AS(
    SELECT B.Id,
           B.[Key],
           B.[Value],
           ROW_NUMBER() OVER (PARTITION BY B.Id ORDER BY [Key]) AS RN
    FROM dbo.TableB B),
rCTE AS(
    SELECT A.Id,
           REPLACE(CONVERT(varchar(MAX),A.[XML]),RN.[Key], RN.[Value]) AS [XML],
           RN.RN
    FROM dbo.TableA A
         JOIN RNs RN ON A.Id = RN.Id
    WHERE RN.RN = 1
    UNION ALL
    SELECT r.Id,
           REPLACE(r.[XML],RN.[Key], RN.[Value]) AS [XML],
           RN.RN
    FROM rCTE r
         JOIN RNs RN ON r.Id = RN.Id
                    AND RN.RN = r.RN + 1)
UPDATE A
SET [XML] = r.[XML]
FROM TableA A
     JOIN rCTE r oN A.Id = r.Id
WHERE RN = (SELECT MAX(RN) FROM rCTE E);
Sign up to request clarification or add additional context in comments.

8 Comments

I am just trying to run update dbo.TableA set a.[XML] = REPLACE(convert (varchar(max),a.[XML]), b.[key], b.[value]) as [xml] from dbo.tablea a inner join dbo.tableb b on a.id = b.id but it says invalid syntax near 'as', isn't it intending to do the same operation ?
You don't alias a column in an UPDATE statement, @Gsab
I've added an UPDATE version for you, @Gsab
@Larnu- fixed the statement like update dbo.TableA set [XML] = REPLACE(convert (varchar(max),a.[XML]), b.[key], b.[value]) from dbo.tablea a inner join dbo.tableb b on a.id = b.id , but what i have observed is that only the first key got replaced with its value and not the second
It works fine for me, @Gsab: db<>fiddle
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.