SQL Server - 带条件的Update语句

时间:2018-02-08 22:33:54

标签: 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=@ParentID), '')
Where ParentId IS NOT NULL

我不确定如何获得@ParentID

6 个答案:

答案 0 :(得分:1)

尝试使用LAG函数,它可以访问当前行之前的行。

.card-img-overlay {
position: absolute;
top: 0px;
right: 0px;
bottom: 0;
left: 150px;
padding: 1.25rem;
}

结果

    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

答案 1 :(得分:0)

示例数据

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

结果集

+----+-------+----------+-------------+-----------+
| ID | Name  | ParentID | NameElement | NodeLevel |
+----+-------+----------+-------------+-----------+
|  2 | A B   |        1 | B           |         1 |
|  3 | A B C |        2 | C           |         2 |
+----+-------+----------+-------------+-----------+

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转换为更新语句。

答案 2 :(得分:0)

从父参考更新NAME(又名父母姓名)。由于没有解释NAME字段,因此OP令人困惑。

update t
set name = (select top 1 name from tree m where t.parentid = m.id)
from tree t

这里的演示 http://rextester.com/live/SXLC53543

答案 3 :(得分:0)

尝试以下方法:

    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

答案 4 :(得分:0)

可以通过这种方式简单地选择值:

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的前缀为child,p为parent。 必须工作

答案 5 :(得分:0)

由于您是SQL2016,因此可以使用其中的一些功能来简化这一过程。如果更改IIF(),这应该可以返回SQL2012或SQL2008。

SQL Fiddle

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

<强> Results

|     Name | finalStr |
|----------|----------|
|       A1 |       A1 |
|    A1 B2 |       B2 |
| A1 B2 C3 |       C3 |
|       D1 |       D1 |
|    D1 E2 |       E2 |
| D1 E2 F3 |       F3 |

我做了什么:

1)FROM (...) s1&gt;&gt;我使用子查询来防止必须计算反向字符串和分隔符的位置。

1a)如果分隔符发生变化,只需更改CHARINDEX(' ',.....)

2)由于我有反向字符串,我计算分隔符的位置并用LEFT(s1.revStr,(s1.delim-1))提取该字符串。

3)由于字符串中只有一个元素(父行),我IIF()以查看我的分隔符是否超出范围。

4)由于我已经提取了反向字符串的第一项,我现在必须将该字符串反转以恢复为原始值。