使用相关记录中的值更新表

时间:2014-07-26 06:03:30

标签: sql sql-server tsql sql-update common-table-expression

我有一张桌子,必须有下一个结构:

╔════╦═══════╦════╦═════╗
║ id ║   a   ║ c  ║  b  ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║    ║ P25 ║
║ 56 ║       ║ 56 ║ 25  ║
║ 57 ║       ║ 57 ║ 25  ║
╚════╩═══════╩════╩═════╝

其中:
1)id = 55的记录是 父记录
2)id = 56,id = 57的记录(列在 a 列中并用分号分隔)
子记录 < / p>

第一个表是下一个

╔════╦═══════╦════╦═════╗
║ id ║   a   ║ c  ║  b  ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║    ║     ║
║ 56 ║       ║ 56 ║     ║
║ 57 ║       ║ 57 ║     ║
╚════╩═══════╩════╩═════╝

所以我必须更新第一张表

等表格

为此我创建了下一个CTE

with My_CTE(PId, a, c, b, newC, inde) as
(
    select
        ST.PID, ST.a, ST.c, ST.b, res.C,
        ind = case 
        when ST.a != '' 
                then (dense_rank() over(order by ST.a))
        end
    from STable as ST
    outer APPLY 
        fnSplit(ST.a) as res
    where (not(ST.a = '') or not(ST.c = ''))
)
UPDATE STable
Set b = 
cte.inde
From STable as st 
Join My_CTE as cte on st.PID = cte.PId;
GO

结果我有下一个值的表

╔════╦═══════╦════╦═════╗
║ id ║   a   ║ c  ║  b  ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║    ║ 25  ║
║ 56 ║       ║ 56 ║     ║
║ 57 ║       ║ 57 ║     ║
╚════╩═══════╩════╩═════╝

所以我需要在子列 b 中为子记录设置值。
也许它可以在MyCTE的精选声明中建立?

请帮忙

2 个答案:

答案 0 :(得分:0)

我不完全确定我是否理解你的要求,如果我误解了,请道歉。

所以你已经设法将结果集设置到这里

╔════╦═══════╦════╦═════╗
║ id ║   a   ║ c  ║  b  ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║    ║ 25  ║
║ 56 ║       ║ 56 ║     ║
║ 57 ║       ║ 57 ║     ║
╚════╩═══════╩════╩═════╝

现在你希望它看起来像这样

╔════╦═══════╦════╦═════╗
║ id ║   a   ║ c  ║  b  ║
╠════╬═══════╬════╬═════╣
║ 55 ║ 56;57 ║    ║ P25 ║
║ 56 ║       ║ 56 ║ 25  ║
║ 57 ║       ║ 57 ║ 25  ║
╚════╩═══════╩════╩═════╝

请查看此脚本是否适合您。

IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp

IF OBJECT_ID(N'tempdb..#temp1')>0
DROP TABLE #temp1

CREATE TABLE #temp (id int, a varchar(100),c varchar(100),b varchar(100))
INSERT INTO #temp VALUES ('55','56;57',' ','25')
INSERT INTO #temp VALUES ('56',' ','56',' ')
INSERT INTO #temp VALUES ('57',' ','57',' ')
SELECT * FROM #temp t

SELECT y.id, fn.string AS a,y.b
INTO #temp1
FROM #temp AS y 
CROSS APPLY dbo.fnParseStringTSQL(y.a, ';') AS fn

--SELECT * FROM #temp1

UPDATE t
SET t.b=CASE WHEN CHARINDEX(';',t.a)>0 THEN 'P'+t.b ELSE t1.b END
FROM #temp t
LEFT JOIN #temp1 t1
ON t.id = t1.a
--DROP TABLE #temp

SELECT * FROM #temp t

IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp

IF OBJECT_ID(N'tempdb..#temp1')>0
DROP TABLE #temp1

借用此link

的函数
CREATE FUNCTION [dbo].[fnParseStringTSQL]
(
    @string        NVARCHAR(MAX),
    @separator     NCHAR(1)
)
RETURNS @parsedString TABLE (string NVARCHAR(MAX))
AS
BEGIN
    DECLARE @position INT
    SET @position = 1
    SET @string = @string + @separator
    WHILE CHARINDEX(@separator, @string, @position) <> 0
    BEGIN
        INSERT INTO @parsedString
        SELECT   SUBSTRING(
                     @string,
                     @position,
                     CHARINDEX(@separator, @string, @position) - @position
                 )

        SET @position = CHARINDEX(@separator, @string, @position) + 1
    END
    RETURN
END

答案 1 :(得分:0)

这实际上不是一个理想的数据结构,但以下内容将会这样做......

CREATE TABLE #STable
(
    id int primary key clustered
    , a varchar(500)
    , c varchar(500)
    , b varchar(500)
)

INSERT INTO #STable
(id, a, c, b)
VALUES (55, '56;57', '', '25')
, (56, '', '56', '')
, (57, '', '57', '')

/* >>>>> Get all parents <<<<< */
CREATE TABLE #folks
(
    sno int identity(1,1)
    , id int
    , a varchar(500)
)

CREATE TABLE #family
(
    parent int
    , child int
)

INSERT INTO #folks
(id, a)
SELECT id, a
FROM #STable
WHERE a <> ''

DECLARE @NID int
        , @XID int
        , @parent int
        , @Children varchar(500)
        , @Child int

SELECT @NID = MIN(sno), @XID = MAX(sno)
FROM #folks

/* >>>>> Loop to figure out the children <<<<< */
WHILE @NID <= @XID
BEGIN

    SELECT @parent = id, @Children = a
    FROM #folks
    WHERE sno = @NID

    WHILE LEN(@Children) > 0
    BEGIN

        IF CHARINDEX(';', @Children) > 0
        BEGIN
            SET @Child = CAST(LEFT(@Children, CHARINDEX(';', @Children) -1) as int)
            SET @Children = RIGHT(@Children, LEN(@Children) - CHARINDEX(';', @Children))

            INSERT INTO #family
            (parent, child)
            VALUES (@parent, @Child)

        END
        ELSE 
        BEGIN

            SET @Child = CAST(@Children AS INT)
            SET @Children = ''

            INSERT INTO #family
            (parent, child)
            VALUES (@parent, @Child)

        END

    END

    SET @NID = @NID + 1

END

/* >>>>> Update <<<<< */
UPDATE c
SET b = p.b
FROM #family f
INNER JOIN #STable p
    on f.parent = p.id
INNER JOIN #STable c
    on f.child = c.id

SELECT *
FROM #STable

DROP TABLE #STable
DROP TABLE #folks
DROP TABLE #family