SQL Server-带条件的Update语句
我有一棵桌子树:SQL Server-带条件的Update语句,sql,sql-server,replace,sql-update,Sql,Sql Server,Replace,Sql Update,我有一棵桌子树: ID Name ParentID ------------------- 1 A NULL 2 A B 1 3 A B C 2 我想修剪名称列中的父前缀(在我上面的示例中,第二行是“A”,第三行是“A-B”),父前缀可能是多个单词,为简单起见,我只是在示例中添加了一个字母 Update Tree Set Name = REPLACE(Name, (Select Name Where ParetnID=
ID Name ParentID
-------------------
1 A NULL
2 A B 1
3 A B C 2
我想修剪名称列中的父前缀(在我上面的示例中,第二行是“A”,第三行是“A-B”),父前缀可能是多个单词,为简单起见,我只是在示例中添加了一个字母
Update
Tree
Set
Name = REPLACE(Name,
(Select Name
Where ParetnID=@ParentID), '')
Where ParentId IS NOT NULL
我不确定用户是如何获得
@ParentID
样本数据的
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 )
查询
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
SQL Server 2016及更高版本
在SQL Server 2016中,STRING_SPLIT()函数使这一点简单得多。在SQL Server 2016及更高版本中,您的查询如下所示:
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
现在可以将此select转换为update语句 从父引用更新名称(又名父名称)。OP令人困惑,因为没有解释名称字段
update t
set name = (select top 1 name from tree m where t.parentid = m.id)
from tree t
这里演示
尝试以下操作:
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
可以通过以下方式简单地选择值:
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
这是你的树桌。r是通过自身连接的子查询。
c前缀表示子项,p前缀表示父项。
必须工作尝试使用该功能,它可以访问当前行之前的行
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
结果
id name parentid
------ ---------- --------
1 A NULL
2 B 1
3 C 2
(3 row(s) affected)
由于您是SQL2016,因此可以通过使用其中的一些可用函数来简化这一过程。如果您更改了
IIF()
,这应该可以回溯到SQL2012或SQL2008
MS SQL Server 2017架构设置:
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)
;
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 |
查询:
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)
;
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 |
我所做的:
1) FROM(…)s1
>我使用子查询来避免计算反转字符串和分隔符的位置
1a)如果分隔符更改,只需更改CHARINDEX(“”,…)
2) 因为我有反向的字符串,所以我计算分隔符的位置,并使用LEFT(s1.revStr,(s1.delim-1))
提取该字符串
3) 由于字符串(父行)中可能只有一个元素,因此我IIF()
4) 由于我提取了反转字符串的第一项,现在我必须将该字符串反转回原始值。我在上面给出了一个示例数据,因此父字符串不是1个字符(A),父前缀更长,我想在变量中获取该行的父名称,并从该行名称中删除该变量。这有意义吗?对于未来的读者来说,row\u NUMBER()
仅在兼容级别为130+的情况下在SQL2016+中有效。什么版本的SQL?@Shawn SQL Server V17.1 oops。。。你能确认parentid是否就是ID本身吗?你从哪里得到的号码?那是SSMS的吗?尝试运行选择@@Version
。这会返回什么?@Shawn its SSMS 17,SQL Server 2016抱歉,我应该更清楚,在我的真实数据中我没有任何分隔符,我只是把它放在那里以保持清晰,我会解决我的问题。如果你想排除null,只需在底部放一个where子句,但我认为你需要null,因为这是你的父引用。更改replace(名称“-”,“.”)
至替换(名称“,”。)
。分隔符是空格字符。实际上@Shawn,字符串不是这里的问题……它实际上是在提取与父代有关的ID,但这不只是去掉了字符串中的第一个分隔符吗?ABC
将变成BC
?+1,尽管我曾想过使用cte,但这是一个整洁的应用程序roach.我喜欢cte,虽然我的答案使用了子查询。我不知道这将如何与许多行或长名称进行缩放。你必须检查。如果你想更新原始表而不是从中选择,你可以使用以下方法: