Cannot update itself in SQL Server 2008 R2 - sql-server

Please see my sample as below:
create table tbl1(cl1 int, cl2 varchar(10))
create table tbl2(cl1 int, cl2 varchar(10))
insert tbl1
select 1, 'a' union all
select 1, 'b' union all
select 1, 'c' union all
select 1, 'd' union all
select 1, 'e'
insert tbl2
select 1, '' union all
select 1, '' union all
select 1, 'c' union all
select 1, '' union all
select 1, 'a'
select * from tbl1
select * from tbl2
update b
set b.cl2 = a.cl2
from tbl1 a inner join tbl2 b on a.cl1=b.cl1
where b.cl2 = '' and a.cl2 not in (select cl2 from tbl2 where tbl2.cl1 = a.cl1)
What I want is to update all empty value at cl2 column in tbl2 table with not duplicate values.
I tried to run as the script above, but it didn't work correct.
Please help me to find out the solution.
Thanks.

Try this script.
create table #tbl1(cl1 int, cl2 varchar(10))
create table #tbl2(cl1 int, cl2 varchar(10))
insert #tbl1
select 1, 'a' union all
select 1, 'b' union all
select 1, 'c' union all
select 1, 'd' union all
select 1, 'e'
insert #tbl2
select 1, '' union all
select 1, '' union all
select 1, 'c' union all
select 1, '' union all
select 1, 'a'
update b
set b.cl2 = a.cl2
from #tbl1 a inner join #tbl2 b on a.cl1=b.cl1
where b.cl2 = '' and a.cl2 not in (select t.cl2 from #tbl2 t where a.cl1 = a.cl1)
Select * from #tbl1
Select * from #tbl2

Related

String Replace column data with data from another table

I have two tables:
TableA:
ID Values
---------------
1 Q
2 B
3 TA
4 BS
TableB:
RawValue Value
------------------
[1][4] QBS
[2][1][3] BQTA
I need to generate TableB values with its given RawValues. each [X] in rawvalue is the ID coulmn of TableA and shoud be replace with its value .
[1][4] means that Value of TableA with has ID of 1 (Q) and Value of TableA with has ID of 4 (BS) then should equal to QBS.
can anyone suggest a way to do it?
this is what I have already tried:
update tableb set value=replace(rawvalue,'[' + (select id from tablea where id = cast(replace(replace(rawdata,'[',''),']','') as int)) + ']',
(select values from tablea where id = cast(replace(replace(rawdata,'[',''),']','') as int)))
By the way: this is still in test process and I can totally change tables, rowvalue format and replacement methods if anyone has a better idea.
declare #tableA table (id int, value varchar(50))
insert into #tableA (id, value)
select 1, 'Q' union all
select 2, 'B' union all
select 3, 'TA' union all
select 4, 'BS'
declare #tableB table (rawdata varchar(255), value varchar(255))
insert into #tableB (rawdata)
select '[1][4]' union all -- QBS
select '[2][1][3]' -- BQTA
update b
set value = (
select a.value + ''
from #tableA a
cross apply (select charindex ('[' + cast (a.id as varchar(50)) + ']', b.rawdata) as pos) p
where pos > 0
order by pos
for xml path('')
)
from #tableB b
select * from #tableB
P.S. I would recommend not to name field similar to reserved keywords (I mean Values).
Turn RawValue into XML, shred the XML to get one row for each value in RawValue and join to TableA to get the value.
Use the for xml path() trick to concatenate the values from TableA.
update TableB
set Value = (
select T.Value as '*'
from (
select row_number() over(order by T2.X) as SortOrder,
TableA.Value
from (select cast(replace(replace(TableB.RawValue, '[', '<x>'), ']', '</x>') as xml)) as T1(X)
cross apply T1.X.nodes('x') as T2(X)
inner join TableA
on TableA.ID = T2.X.value('text()[1]', 'int')
) as T
order by T.SortOrder
for xml path('')
)
SQL Fiddle

Entering 40000 rows in sql server through loop

I have to make a database system that is purely on SQL Server. It's about a diagnostic lab. It should contain at least 40,000 distinct patient records. I have a table named "Patient" which contains an auto-generated ID, Name, DOB, Age and Phone number. Our teacher provided us with a dummy stored procedure which contained 2 temporary tables that has 200 names each and in the end he makes a Cartesian product which is supposed to give 40,000 distinct rows. I have used the same dummy stored procedure and modified it according to our table. But the rows inserted are only 1260 every time. Each time we run the query it does not give us more than 1260 records. I have added a part of temporary name tables and the stored procedure.
Declare #tFirstNames Table( FirstName Varchar(50) Not Null )
Declare #tLastNames Table ( LastName Varchar(50) Not Null )
Declare #tNames Table ( Id Int Identity Not Null, Name Varchar(50) Not Null)
Insert Into #tFirstNames (FirstName)
Select 'Julianne' Union All Select 'Sharyl' Union All Select 'Yoshie'
Union All Select 'Germaine' Union All Select 'Ja' Union All
Select 'Kandis' Select 'Hannelore' Union All Select 'Laquanda' Union All
Select 'Clayton' Union All Select 'Ollie' Union All
Select 'Rosa' Union All Select 'Deloras' Union All
Select 'April' Union All Select 'Garrett' Union All
Select 'Mariette' Union All Select 'Carline' Union All
Insert Into #tLastNames (LastName)
Select 'Brown' Union All Select 'Chrichton' Union All Select 'Bush'
Union All Select 'Clinton' Union All Select 'Blair'
Union All Select 'Wayne' Union All Select 'Hanks'
Union All Select 'Cruise' Union All Select 'Campbell'
Union All Select 'Turow' Union All Select 'Tracey'
Union All Select 'Arnold' Union All Select 'Derick'
Union All Select 'Nathanael' Union All Select 'Buddy'
Insert Into #tNames
Select FirstName + ' ' + LastName
From #tFirstNames, #tLastNames
Declare #iIndex Integer
Declare #iPatientTotalRecords Integer
Declare #vcName Varchar(50)
Declare #iAge Integer
--Set #iIndex = 1
Select #iPatientTotalRecords = Max(Id), #iIndex = Min(Id) From #tNames
While #iIndex <= #iPatientTotalRecords
Begin
Select #vcName = Name From #tNames Where Id = #iIndex
Set #iAge = Cast( Rand() * 70 As Integer ) + 10
Insert into Patient values
(#vcName, #iAge,
Case Cast( Rand() * 3 As Integer)
When 0 Then 'Male'
When 1 Then 'Female'
Else 'Female'
End,
Cast( Rand() * 8888889 As Integer ) + 1111111, DateAdd ( year, -#iAge, GetDate()))
Set #iIndex = #iIndex + 1
End
Possible you miss type UNION ALL -
Select 'Julianne' Union All
Select 'Sharyl' Union All
Select 'Yoshie' Union All
Select 'Germaine' Union All
Select 'Ja' Union All
Select 'Kandis' --<-- missing union all
Select 'Hannelore' Union All
Select 'Laquanda' Union All
Select 'Clayton' Union All
Select 'Ollie' Union All
Select 'Rosa' Union All
Select 'Deloras' Union All
Select 'April' Union All
Select 'Garrett' Union All
Select 'Mariette' Union All
Select 'Carline'
Try this one (without WHILE and additional variables):
DECLARE #tFirstNames TABLE (FirstName VARCHAR(50) NOT NULL)
INSERT INTO #tFirstNames (FirstName)
VALUES
('Julianne'), ('Sharyl'), ('Yoshie'), ('Germaine'),
('Ja'), ('Kandis'), ('Hannelore'), ('Laquanda'), ('Clayton'),
('Ollie'), ('Rosa'), ('Deloras'), ('April'), ('Garrett'),
('Mariette'), ('Carline')
DECLARE #tLastNames TABLE (LastName VARCHAR(50) NOT NULL)
INSERT INTO #tLastNames (LastName)
VALUES
('Brown'), ('Chrichton'), ('Bush'), ('Clinton'),
('Blair'), ('Wayne'), ('Hanks'), ('Cruise'), ('Campbell'),
('Turow'), ('Tracey'), ('Arnold'), ('Derick'),
('Nathanael'), ('Buddy')
INSERT INTO dbo.Patient (...)
SELECT
-- Possible problem: String or binary data would be truncated
d.FLName -- <-- FirstName + LastName i.e. 50 + 1 + 50 = 101 chars
, d.Age
, Gender = CASE ABS(CAST((BINARY_CHECKSUM(NEWID(), NEWID())) AS INT)) % 3
WHEN 0 THEN 'Male'
ELSE 'Female'
END
, (ABS(CAST((BINARY_CHECKSUM(NEWID(), NEWID())) AS INT)) % 8888889) + 1111111
, BirthDay = CONVERT(VARCHAR(10), DATEADD( year, -d.Age, GETDATE()), 112)
FROM (
SELECT
FLName = f.FirstName + ' ' + l.LastName
, Age = (ABS(CAST((BINARY_CHECKSUM(f.FirstName, NEWID())) AS INT)) % 70) + 10
FROM #tFirstNames f
CROSS JOIN #tLastNames l
) d

How to add two text row on same column in T-SQL

How can I add two text row on same column, or any alternative aggregate function which can apply sum() on text columns.
id Name
1 A
1 B
2 C
group by id
result like this.
id Names
1 A,B
2 C
Try this:
declare #t table(id int, name varchar(50))
insert #t values(1, 'A')
insert #t values(1, 'B')
insert #t values(2, 'C')
select t.id,
,STUFF((
select ',' + [name]
from #t t1
where t1.id = t.id
for xml path(''), type
).value('.', 'varchar(max)'), 1, 1, '') [Names]
from #t t
group by t.id
Result:
id Names
----------- --------------
1 A,B
2 C

SP Help (Invalid Column Name)

With a MS SQL Stored Procedure I am getting the following error "Invalid Column Name NavigationID".
Can anyone let me know what I am doing incorrectly?
DECLARE #NavigationID INT
SET #NavigationID = 5
CREATE TABLE #tmp (NavigationID int , ParentID int);
INSERT INTO #tmp SELECT NavigationID, ParentID FROM Nav;
WITH Parent AS
(
SELECT NavigationID, ParentID FROM #tmp WHERE NavigationID = #NavigationID
UNION ALL
SELECT t.NavigationID, t.ParentID FROM Parent
INNER JOIN #tmp t ON t.NavigationID = Parent.ParentID
)
SELECT NavigationID FROM ParentID
WHERE NavigationID <> #NavigationID;
With the code you posted you get.
Msg 208, Level 16, State 1, Line 10
Invalid object name 'ParentID'.
Change FROM ParentID to FROM Parent.
You also need a column NavigationID in table Nav.
Try this:
declare #Nav table(NavigationID int, ParentID int)
insert into #Nav
select 1, null union all
select 2, 1 union all
select 3, 1 union all
select 4, 3 union all
select 5, 3 union all
select 6, null union all
select 7, 6
declare #NavigationID int;
set #NavigationID = 5;
with Parent as
(
select NavigationID,
ParentID
from #Nav
where NavigationID = #NavigationID
union all
select t.NavigationID, t.ParentID
from Parent
inner join #Nav t
on t.NavigationID = Parent.ParentID
)
select NavigationID
from Parent
where NavigationID <> #NavigationID;
Result:
NavigationID
------------
3
1
Replace #Nav with whatever table you are using. #Nav is only here so that this code can be copied and tested.

Recursive CTE Problem

I am trying to use a recursive CTE in SQL Server to build up a predicate formula from a table containing the underlying tree structure.
For example, my table looks like:
Id | Operator/Val | ParentId
--------------------------
1 | 'OR' | NULL
2 | 'AND' | 1
3 | 'AND' | 1
4 | '>' | 2
5 | 'a' | 4
6 | 'alpha' | 4
...
...which represents ((a > alpha) AND (b > beta)) OR ((c > gamma) AND (a < delta)).
ParentId is a reference to the Id in the same table of the parent node.
I want to write a query which will build up this string from the table. Is it possible?
Thanks
For a production environment, you may want to go with a recursive function for simplicity if performance and recursion depth limits (32 levels) is not a problem.
However, here's a quite clean and pretty efficient solution with CTEs (note that it will accept any number of "trees" and return one result for each item which has no parent):
DECLARE #tbl TABLE
(
id int PRIMARY KEY
NOT NULL,
op nvarchar(max) NOT NULL,
parent int
) ;
INSERT INTO #tbl
SELECT 1, 'OR', NULL UNION ALL
SELECT 2, 'AND', 1 UNION ALL
SELECT 3, 'AND', 1 UNION ALL
SELECT 4, '>', 2 UNION ALL
SELECT 5, 'a', 4 UNION ALL
SELECT 6, 'alpha', 4 UNION ALL
SELECT 7, '>', 2 UNION ALL
SELECT 8, 'b', 7 UNION ALL
SELECT 9, 'beta', 7 UNION ALL
SELECT 10, '>', 3 UNION ALL
SELECT 11, 'c', 10 UNION ALL
SELECT 12, 'gamma', 10 UNION ALL
SELECT 13, '>', 3 UNION ALL
SELECT 14, 'd', 13 UNION ALL
SELECT 15, 'delta', 13 ;
WITH nodes -- A CTE which sets a flag to 1 for non-leaf nodes
AS (
SELECT t.*, CASE WHEN p.parent IS NULL THEN 0
ELSE 1
END node
FROM #tbl t
LEFT JOIN (
SELECT DISTINCT parent
FROM #tbl
) p ON p.parent = T.id
),
rec -- the main recursive run to determine the sort order and add meta information
AS (
SELECT id rootId, node lvl, CAST(0 AS float) sort, CAST(0.5 AS float) offset, *
FROM nodes
WHERE parent IS NULL
UNION ALL
SELECT r.rootId, r.lvl+t.node, r.sort+r.offset*CAST((ROW_NUMBER() OVER (ORDER BY t.id)-1)*2-1 AS float),
r.offset/2, t.*
FROM rec r
JOIN
nodes t ON r.id = t.parent
),
ranked -- ranking of the result to sort and find the last item
AS (
SELECT rootId, ROW_NUMBER() OVER (PARTITION BY rootId ORDER BY sort) ix,
COUNT(1) OVER (PARTITION BY rootId) cnt, lvl, op
FROM rec
),
concatenated -- concatenate the string, adding ( and ) as needed
AS (
SELECT rootId, ix, cnt, lvl, CAST(REPLICATE('(', lvl)+op AS nvarchar(max)) txt
FROM ranked
WHERE ix = 1
UNION ALL
SELECT r.rootId, r.ix, r.cnt, r.lvl,
c.txt+COALESCE(REPLICATE(')', c.lvl-r.lvl), '')+' '+COALESCE(REPLICATE('(', r.lvl-c.lvl), '')+r.op
+CASE WHEN r.ix = r.cnt THEN REPLICATE(')', r.lvl)
ELSE ''
END
FROM ranked r
JOIN
concatenated c ON (r.rootId = c.rootId)
AND (r.ix = c.ix+1)
)
SELECT rootId id, txt
FROM concatenated
WHERE ix = cnt
OPTION (MAXRECURSION 0);
I found something, but it looks pretty nasty. You would be able to do this a lot easier using a recursive fundtion...
DECLARE #Table TABLE(
ID INT,
Op VARCHAR(20),
ParentID INT
)
INSERT INTO #Table SELECT 1,'OR',NULL
INSERT INTO #Table SELECT 2,'AND',1
INSERT INTO #Table SELECT 3,'AND',1
INSERT INTO #Table SELECT 4,'>',2
INSERT INTO #Table SELECT 5,'a',4
INSERT INTO #Table SELECT 6,'alpha',4
INSERT INTO #Table SELECT 7,'>',2
INSERT INTO #Table SELECT 8,'b',7
INSERT INTO #Table SELECT 9,'beta',7
INSERT INTO #Table SELECT 10,'>',3
INSERT INTO #Table SELECT 11,'c',10
INSERT INTO #Table SELECT 12,'gamma',10
INSERT INTO #Table SELECT 13,'<',3
INSERT INTO #Table SELECT 14,'a',13
INSERT INTO #Table SELECT 15,'delta',13
;WITH Vals AS (
SELECT t.*,
1 Depth
FROM #Table t LEFT JOIN
#Table parent ON t.ID = parent.ParentID
WHERE parent.ParentID IS NULL
UNION ALL
SELECT t.*,
v.Depth + 1
FROM #Table t INNER JOIN
Vals v ON v.ParentID = t.ID
),
ValLR AS(
SELECT DISTINCT
vLeft.ID LeftID,
vLeft.Op LeftOp,
vRight.ID RightID,
vRight.Op RightOp,
vLeft.ParentID OperationID,
vLeft.Depth
FROM Vals vLeft INNER JOIN
Vals vRight ON vLeft.ParentID = vRight.ParentID
AND vLeft.ID < vRight.ID
WHERE (vRight.ID IS NOT NULL)
),
ConcatVals AS(
SELECT CAST('(' + LeftOp + ' ' + Op + ' ' + RightOp + ')' AS VARCHAR(500)) ConcatOp,
t.ID OpID,
v.Depth,
1 CurrentDepth
FROM ValLR v INNER JOIN
#Table t ON v.OperationID = t.ID
WHERE v.Depth = 1
UNION ALL
SELECT CAST('(' + cL.ConcatOp + ' ' + t.Op + ' {' + CAST(v.RightID AS VARCHAR(10)) + '})' AS VARCHAR(500)) ConcatOp,
t.ID OpID,
v.Depth,
cL.CurrentDepth + 1
FROM ValLR v INNER JOIN
#Table t ON v.OperationID = t.ID INNER JOIN
ConcatVals cL ON v.LeftID = cL.OpID
WHERE v.Depth = cL.CurrentDepth + 1
),
Replaces AS(
SELECT REPLACE(
c.ConcatOp,
SUBSTRING(c.ConcatOp,PATINDEX('%{%', c.ConcatOp), PATINDEX('%}%', c.ConcatOp) - PATINDEX('%{%', c.ConcatOp) + 1),
(SELECT ConcatOp FROM ConcatVals WHERE OpID = CAST(SUBSTRING(c.ConcatOp,PATINDEX('%{%', c.ConcatOp) + 1, PATINDEX('%}%', c.ConcatOp) - PATINDEX('%{%', c.ConcatOp) - 1) AS INT))
) ConcatOp,
1 Num
FROM ConcatVals c
WHERE Depth = (SELECT MAX(Depth) FROM ConcatVals)
UNION ALL
SELECT REPLACE(
r.ConcatOp,
SUBSTRING(r.ConcatOp,PATINDEX('%{%', r.ConcatOp), PATINDEX('%}%', r.ConcatOp) - PATINDEX('%{%', r.ConcatOp) + 1),
(SELECT ConcatOp FROM ConcatVals WHERE OpID = CAST(SUBSTRING(r.ConcatOp,PATINDEX('%{%', r.ConcatOp) + 1, PATINDEX('%}%', r.ConcatOp) - PATINDEX('%{%', r.ConcatOp) - 1) AS INT))
) ConcatOp,
Num + 1
FROM Replaces r
WHERE PATINDEX('%{%', r.ConcatOp) > 0
)
SELECT TOP 1
*
FROM Replaces
ORDER BY Num DESC
OUTPUT
ConcatOp
----------------------------------------------------------------
(((a > alpha) AND (b > beta)) OR ((c > gamma) AND (a < delta)))
If you would rather want to look at a recursive function, give me a shout and we can have a look.
EDIT: Recursive Function
Have a look at how much easier this is
CREATE TABLE TableValues (
ID INT,
Op VARCHAR(20),
ParentID INT
)
INSERT INTO TableValues SELECT 1,'OR',NULL
INSERT INTO TableValues SELECT 2,'AND',1
INSERT INTO TableValues SELECT 3,'AND',1
INSERT INTO TableValues SELECT 4,'>',2
INSERT INTO TableValues SELECT 5,'a',4
INSERT INTO TableValues SELECT 6,'alpha',4
INSERT INTO TableValues SELECT 7,'>',2
INSERT INTO TableValues SELECT 8,'b',7
INSERT INTO TableValues SELECT 9,'beta',7
INSERT INTO TableValues SELECT 10,'>',3
INSERT INTO TableValues SELECT 11,'c',10
INSERT INTO TableValues SELECT 12,'gamma',10
INSERT INTO TableValues SELECT 13,'<',3
INSERT INTO TableValues SELECT 14,'a',13
INSERT INTO TableValues SELECT 15,'delta',13
GO
CREATE FUNCTION ReturnMathVals (#ParentID INT, #Side VARCHAR(1))
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE #RetVal VARCHAR(500)
IF (#ParentID IS NULL)
BEGIN
SELECT #RetVal = ' (' + dbo.ReturnMathVals(ID,'L') + Op + dbo.ReturnMathVals(ID,'R') + ') '
FROM TableValues
WHERE ParentID IS NULL
END
ELSE
BEGIN
SELECT TOP 1 #RetVal = ' (' + dbo.ReturnMathVals(ID,'L') + Op + dbo.ReturnMathVals(ID,'R') + ') '
FROM TableValues
WHERE ParentID = #ParentID
ORDER BY CASE WHEN #Side = 'L' THEN ID ELSE -ID END
SET #RetVal = ISNULL(#RetVal, (SELECT TOP 1 Op FROM TableValues WHERE ParentID = #ParentID ORDER BY CASE WHEN #Side = 'L' THEN ID ELSE -ID END))
END
RETURN #RetVal
END
GO
SELECT dbo.ReturnMathVals(NULL, NULL)
GO
DROP FUNCTION ReturnMathVals
DROP TABLE TableValues
Yes it is possible to do it but the problem is not the CTE, check it with PIVOT
read more about it from this link
http://msdn.microsoft.com/en-us/library/ms177410.aspx
some examples in this documentation is similar with your problem
I couldn't figure out how to do the double-recursion, but hopefully one of the intermediate CTEs in this will set you on the right track:
SET NOCOUNT ON
DECLARE #tree AS TABLE
(
Id int NOT NULL
,Operator varchar(10) NOT NULL
,ParentId int
)
INSERT INTO #tree
VALUES (1, 'OR', NULL)
INSERT INTO #tree
VALUES (2, 'AND', 1)
INSERT INTO #tree
VALUES (3, 'AND', 1)
INSERT INTO #tree
VALUES (4, '>', 2)
INSERT INTO #tree
VALUES (5, 'a', 4)
INSERT INTO #tree
VALUES (6, 'alpha', 4)
INSERT INTO #tree
VALUES (7, '>', 2)
INSERT INTO #tree
VALUES (8, 'b', 7)
INSERT INTO #tree
VALUES (9, 'beta', 7)
INSERT INTO #tree
VALUES (10, '>', 3)
INSERT INTO #tree
VALUES (11, 'c', 10)
INSERT INTO #tree
VALUES (12, 'gamma', 10)
INSERT INTO #tree
VALUES (13, '>', 3)
INSERT INTO #tree
VALUES (14, 'd', 13)
INSERT INTO #tree
VALUES (15, 'delta', 13) ;
WITH lhs_selector
AS (
SELECT ParentId
,MIN(Id) AS Id
FROM #tree
GROUP BY ParentId
),
rhs_selector
AS (
SELECT ParentId
,MAX(Id) AS Id
FROM #tree
GROUP BY ParentId
),
leaf_selector
AS (
SELECT Id
FROM #tree AS leaf
WHERE NOT EXISTS ( SELECT *
FROM #tree
WHERE ParentId = leaf.Id )
),
recurse
AS (
SELECT operator.Id
,CASE WHEN lhs_is_leaf.Id IS NOT NULL THEN NULL
ELSE lhs.Id
END AS LhsId
,CASE WHEN rhs_is_leaf.Id IS NOT NULL THEN NULL
ELSE rhs.Id
END AS RhsId
,CASE WHEN COALESCE(lhs_is_leaf.Id, rhs_is_leaf.Id) IS NULL
THEN '({' + CAST(lhs.Id AS varchar) + '} ' + operator.Operator + ' {'
+ CAST(rhs.Id AS varchar) + '})'
ELSE '(' + lhs.Operator + ' ' + operator.Operator + ' ' + rhs.Operator + ')'
END AS expression
FROM #tree AS operator
INNER JOIN lhs_selector
ON lhs_selector.ParentID = operator.Id
INNER JOIN rhs_selector
ON rhs_selector.ParentID = operator.Id
INNER JOIN #tree AS lhs
ON lhs.Id = lhs_selector.Id
INNER JOIN #tree AS rhs
ON rhs.Id = rhs_selector.Id
LEFT JOIN leaf_selector AS lhs_is_leaf
ON lhs_is_leaf.Id = lhs.Id
LEFT JOIN leaf_selector AS rhs_is_leaf
ON rhs_is_leaf.Id = rhs.Id
)
SELECT *
,REPLACE(REPLACE(op.expression, '{' + CAST(op.LhsId AS varchar) + '}', lhs.expression),
'{' + CAST(op.RhsId AS varchar) + '}', rhs.expression) AS final_expression
FROM recurse AS op
LEFT JOIN recurse AS lhs
ON lhs.Id = op.LhsId
LEFT JOIN recurse AS rhs
ON rhs.Id = op.RhsId

Resources