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,虽然我的答案使用了子查询。我不知道这将如何与许多行或长名称进行缩放。你必须检查。如果你想
更新原始表而不是
从中选择
,你可以使用以下方法: