存储过程复制行

时间:2018-03-27 15:59:34

标签: sql sql-server parent-child

我有一个表格,用于存储有关文件的数据;使用PreviousFileId和NextFileID字段链接文件,这是一个数据示例:

+--------+----------+-----------+----------------+------------+----------------+
| FileID | FileCode | FileOrder | PreviousFileID | NextFileID | ParentFileCode |
+--------+----------+-----------+----------------+------------+----------------+
|   1000 | FILE-A   |         1 | NULL           | 1001       | NULL           |
|   1001 | FILE-B   |         2 | 1000           | 1002       | NULL           |
|   1002 | FILE-C   |         3 | 1001           | NULL       | NULL           |
|   1003 | FILE-D   |         1 | NULL           | NULL       | FILE-A         |
|   1004 | FILE-E   |         2 | NULL           | NULL       | FILE-B         |
|   1005 | FILE-F   |         3 | NULL           | NULL       | FILE-C         |
+--------+----------+-----------+----------------+------------+----------------+

我想创建一个存储过程来更新文件1003,1004和1005之间的链接。该过程应该接受ParentFileCode作为参数,例如,如果我将'FILE-B'作为参数传递,数据应该看起来像这在执行存储过程之后:

+--------+----------+-----------+----------------+------------+----------------+
| FileID | FileCode | FileOrder | PreviousFileID | NextFileID | ParentFileCode |
+--------+----------+-----------+----------------+------------+----------------+
|   1000 | FILE-A   |         1 | NULL           | 1001       | NULL           |
|   1001 | FILE-B   |         2 | 1000           | 1002       | NULL           |
|   1002 | FILE-C   |         3 | 1001           | NULL       | NULL           |
|   1003 | FILE-D   |         1 | NULL           | 1004       | FILE-A         |
|   1004 | FILE-E   |         2 | 1003           | 1005       | FILE-B         |
|   1005 | FILE-F   |         3 | 1004           | NULL       | FILE-C         |
+--------+----------+-----------+----------------+------------+----------------+

这是表结构/插入数据代码:

CREATE TABLE Files
(
FileID INT NOT NULL,
FileCode VARCHAR(20) NOT NULL,
FileOrder INT NOT NULL,
PreviousFileID INT NULL,
NextFileID INT NULL,
ParentFileCode VARCHAR(20) NULL
)



INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1000, 'FILE-A', 1, NULL, 1001, NULL)


INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1001, 'FILE-B', 2, 1000, 1002, NULL)


INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1002, 'FILE-C', 3, 1001, NULL, NULL)

INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1003, 'FILE-D', 1, NULL, NULL, 'FILE-A')


INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1004, 'FILE-E', 2, NULL, NULL, 'FILE-B')


INSERT INTO dbo.Files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode)
VALUES (1005, 'FILE-F', 3, NULL, NULL, 'FILE-C')

关于如何实现这一点的任何想法?

2 个答案:

答案 0 :(得分:0)

尝试这样的事情:

update table
set 
previousfileid= lag(fileid, 1, 0)  over(order by fileorder) ,
nextfileid= lead(fileid, 1, 0)  over(order by fileorder) 
from table_name
where parentfilecode is not null

答案 1 :(得分:0)

好的,我将您的示例数据放入临时表中,因为我发现这更容易使用:

IF OBJECT_ID('tempdb..#files') IS NOT NULL
    DROP TABLE #files;

CREATE TABLE #files (
    FileID INT NOT NULL,
    FileCode VARCHAR(20) NOT NULL,
    FileOrder INT NOT NULL,
    PreviousFileID INT NULL,
    NextFileID INT NULL,
    ParentFileCode VARCHAR(20) NULL);

INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1000, 'FILE-A', 1, NULL, 1001, NULL);
INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1001, 'FILE-B', 2, 1000, 1002, NULL);
INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1002, 'FILE-C', 3, 1001, NULL, NULL);
INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1003, 'FILE-D', 1, NULL, NULL, 'FILE-A');
INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1004, 'FILE-E', 2, NULL, NULL, 'FILE-B');
INSERT INTO #files (FileID, FileCode, FileOrder, PreviousFileID, NextFileID, ParentFileCode) VALUES (1005, 'FILE-F', 3, NULL, NULL, 'FILE-C');

方法1是做Daniel所说的,做了一些调整(将0变成NULL,因为你不能直接在{{1}中使用LEAD / LAG }):

UPDATE

请注意,这并不是一个参数,只是更新整个表格。

这是一个使用三个UPDATE语句的方法,它有一个参数:

--Method #1
WITH x AS (
    SELECT
        FileId,
        PreviousFileID = LAG(FileId, 1, NULL) OVER (ORDER BY FileOrder),
        NextFileID = LEAD(FileId, 1, NULL) OVER (ORDER BY FileOrder)
    FROM
        #files f
    WHERE
        ParentFileCode IS NOT NULL)
UPDATE
    f
SET
    PreviousFileId = x.PreviousFileId,
    NextFileId = x.NextFileId
FROM
    #files f
    INNER JOIN x ON x.FileId = f.FileId;

这两种方法都适用于这一小部分数据,因此我建议针对较大的数据集进行测试?然后,您需要将它们变为存储过程,这只是添加--Method #2 DECLARE @file VARCHAR(50) = 'FILE-B'; UPDATE fx SET PreviousFileId = fxp.FileID, NextFileID = fxn.FileId FROM #files f --Anchor LEFT JOIN #files p ON p.FileID = f.PreviousFileID --previous file LEFT JOIN #files n ON n.FileId = f.NextFileID --current file INNER JOIN #files fx ON fx.ParentFileCode = 'FILE-B' --files to update LEFT JOIN #files fxp ON fxp.ParentFileCode = p.FileCode LEFT JOIN #files fxn ON fxn.ParentFileCode = n.FileCode WHERE f.FileCode = @file; UPDATE fxp SET NextFileID = fx.FileId FROM #files f --Anchor LEFT JOIN #files p ON p.FileID = f.PreviousFileID --previous file LEFT JOIN #files n ON n.FileId = f.NextFileID --current file INNER JOIN #files fx ON fx.ParentFileCode = 'FILE-B' --files to update INNER JOIN #files fxp ON fxp.ParentFileCode = p.FileCode WHERE f.FileCode = @file UPDATE fxn SET PreviousFileId = fx.FileID FROM #files f --Anchor LEFT JOIN #files p ON p.FileID = f.PreviousFileID --previous file LEFT JOIN #files n ON n.FileId = f.NextFileID --current file INNER JOIN #files fx ON fx.ParentFileCode = 'FILE-B' --files to update INNER JOIN #files fxn ON fxn.ParentFileCode = n.FileCode WHERE f.FileCode = @file; ...等的情况。