Reputation: 609
I have this table Tree:
ID Name ParentID
-------------------
1 A NULL
2 A B 1
3 A B C 2
I want to trim the parent prefix in the name column (in my example above 'A' in the second row and 'A-B' in the third), the parent might be multiple words for simplicity I just put a letter in my example.
Update
Tree
Set
Name = REPLACE(Name,
(Select Name
Where ParetnID=@ParentID), '')
Where ParentId IS NOT NULL
Im not sure how the get that @ParentID
Upvotes: 1
Views: 336
Reputation: 4824
Update NAME (aka Parent's Name) from the parent reference. The OP is confusing since NAME field was not explained.
update t
set name = (select top 1 name from tree m where t.parentid = m.id)
from tree t
demo here http://rextester.com/live/SXLC53543
Upvotes: 0
Reputation: 4786
Since you're SQL2016, you can make this easier by using some of the functions available there. This should work back to SQL2012, or SQL2008 if you change the IIF()
.
MS SQL Server 2017 Schema Setup:
CREATE TABLE t ( ID int, Name varchar(10), ParentID int ) ;
INSERT INTO t
VALUES
(1,'A1',NULL)
, (2,'A1 B2',1)
, (3,'A1 B2 C3',2)
, (4,'D1',NULL)
, (5,'D1 E2',4)
, (6,'D1 E2 F3',5)
;
The Query:
SELECT s1.Name
, REVERSE( IIF( s1.delim-1<0 , s1.revStr, LEFT(s1.revStr,(s1.delim-1)) ) ) AS finalStr
FROM (
SELECT Name
, REVERSE(t.Name) as revStr
, CHARINDEX(' ',REVERSE( t.Name )) as delim
FROM t
) s1
| Name | finalStr |
|----------|----------|
| A1 | A1 |
| A1 B2 | B2 |
| A1 B2 C3 | C3 |
| D1 | D1 |
| D1 E2 | E2 |
| D1 E2 F3 | F3 |
What I Did:
1) FROM (...) s1
>> I used a subquery to keep from having to calculate the reversed string and the position of the delimiter.
1a) If the delimiter changes, just change CHARINDEX(' ',.....)
.
2) Since I have the reversed string, I calculate the position of the delimiter and extract that string with LEFT(s1.revStr,(s1.delim-1))
.
3) Since there may be only one element in the string (parent rows), I IIF()
to see if my delimiter starts out of bounds.
4) Since I've extracted the first item of the reversed string, I now have to reverse that string back to revert to the original value.
Upvotes: 0
Reputation: 716
try use the LAG Function, it enables to access a row that comes before the current row.
DECLARE @ttable TABLE
(
id SMALLINT ,
name VARCHAR(10) ,
parentid SMALLINT
)
INSERT INTO @ttable
VALUES ( 1, 'A', NULL ),
( 2, 'A B', 1 ),
( 3, 'A B C', 2 )
--
;
WITH CTE
AS ( SELECT Id ,
name ,
RTRIM(LTRIM(REPLACE(name, LAG(name, 1, 0) OVER ( ORDER BY id ), ''))) rr ,
parentid
FROM @ttable
)
UPDATE CTE
SET name = rr
SELECT * FROM @ttable
Result
id name parentid
------ ---------- --------
1 A NULL
2 B 1
3 C 2
(3 row(s) affected)
Upvotes: 1
Reputation: 555
Values can be simply selected by this way:
select substring(cv,CHARINDEX(pv,cv)+LEN(pv),LEN(cv))
from (select ct.name cv,pt.name pv from tree ct,tree pt where pt.id=ct.parentid) r
here t is your tree table. r is the subquery by joining with itself. c prefix for child and p for parent. must work
Upvotes: 0
Reputation: 69574
Sample Data
Declare @t TABLE (ID INT , Name VARCHAR(100), ParentID INT)
INSERT INTO @t VALUES
(1 ,'A' ,NULL),
(2 ,'A B' ,1 ),
(3 ,'A B C' ,2 )
Query
SELECT *
FROM @t t
CROSS APPLY
(
SELECT Replace(
RTRIM(LTRIM(Split.a.value('.', 'VARCHAR(100)')))
,'|' , '&') NameElement
, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 NodeLevel
FROM
(
SELECT Cast ('<X>'
+ Replace(Replace(t.Name, ' ', '</X><X>'), '&' , '|')
+ '</X>' AS XML) AS Data
) AS t CROSS APPLY Data.nodes ('/X') AS Split(a)
) c(NameElement, NodeLevel)
WHERE t.ParentID = c.NodeLevel
Result Set
+----+-------+----------+-------------+-----------+
| ID | Name | ParentID | NameElement | NodeLevel |
+----+-------+----------+-------------+-----------+
| 2 | A B | 1 | B | 1 |
| 3 | A B C | 2 | C | 2 |
+----+-------+----------+-------------+-----------+
SQL Server 2016 and Later versions
In SQL Server 2016 STRING_SPLIT() function has made this a lot simpler. In SQL Server 2016 and later versions your query would look like:
SELECT *
FROM @t t
CROSS APPLY (SELECT value
, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 NodeLevel
FROM string_split(t.name , ' ')
) c(NameElement, NodeLevel)
WHERE t.ParentID = c.NodeLevel
Now you can convert this select into an update statement.
Upvotes: 0
Reputation: 79
Try the following:
Update Tree
Set Name = REPLACE(Name,B.Name, '')
FROM Tree A
INNER JOIN Tree B
ON A.ParentID = B.ID
Where ParentId IS NOT NULL
Upvotes: 0