如何从另一个表创建新表

问题描述 投票:-1回答:2

我有一个名为WorkSpace的表,具有4列。

此表中的每个记录都通过Parent_id列引用其父记录。

您应继续此循环,直到您到达主要父母,并在View_Parent_id栏中指定了所有这些步骤。

主要父母编号的ID由1指定。

所以现在我想创建一个NEW_WorkSpace表并将View_Parent_id列中的每个值分隔到单独的列中。

View_Parent_id列最终为15值,因此我们需要在新表(Level_1 ... Level_15)中包含15列。

我在查询中使用了循环,但是速度很慢。

[WorkSpace表具有150万行。

WorkSpace表:

+-----+-------+-----------+------------------+
| W_ID| Title | Parent_id | View_Parent_id   |
+-----+-------+-----------+------------------+
| 1   |   AAA |    null   | null             |
| 2   |   BV  |    1      | 1                |
| 3   |   CX  |    2      | 1+2              |
| 4   |   DSO |    2      | 1+2              |
| 5   |   ER  |    3      | 1+2+3            |
| 6   |   ER  |    5      | 1+2+3+5          |
| ... |  ...  |    ...    | ...              |
| 1000|   MNV |    1      | 1                |
| 1001|   SF  |    1000   | 1+1000           |
| 1002|   EDD |    1000   | 1+1000           |
| 1003|   YSG |    1001   | 1+1000+1001      |
| 1004|   RPO |    1003   | 1+1000+1001+1003 |
+-----+-------+-----------+------------------+

NEW_WorkSpace表:

+-----+-------+-----------+---------+---------+---------+-----+----------+
| ID  |  W_id | Parent_id | Level_1 | Level_2 | Level_3 | ... | Level_15 |
+-----+-------+-----------+---------+-------- +---------+-----+----------+
| 100 |   1   |    null   | AAA     |         |         | ... |          |
| 101 |   2   |    1      | AAA     |  BV     |         | ... |          |
| 102 |   3   |    2      | AAA     |  BV     |         | ... |          |
| 103 |   4   |    2      | AAA     |  BV     |  CX     | ... |          |
| 104 |   5   |    3      | AAA     |  BV     |  CX     | ... |          |
| ... |   ... |    ...    | ...     |  ...    |  ...    | ... |  ...     |
+-----+-------+-----------+---------+---------+---------+-----+----------+

我的代码:

BEGIN    
    DECLARE @W_ID decimal(20, 0);
    DECLARE @parent_id decimal(20, 0);

    DECLARE @Level1 nvarchar(MAX);
    DECLARE @Level2 nvarchar(MAX);
    DECLARE @Level3 nvarchar(MAX);
    DECLARE @Level4 nvarchar(MAX);
    DECLARE @Level5 nvarchar(MAX);
    DECLARE @Level6 nvarchar(MAX);
    DECLARE @Level7 nvarchar(MAX);
    DECLARE @Level8 nvarchar(MAX);
    DECLARE @Level9 nvarchar(MAX);
    DECLARE @Level10 nvarchar(MAX);
    DECLARE @Level11 nvarchar(MAX);
    DECLARE @Level12 nvarchar(MAX);
    DECLARE @Level13 nvarchar(MAX);
    DECLARE @Level14 nvarchar(MAX);
    DECLARE @Level15 nvarchar(MAX);
    DECLARE @titles_tmp nvarchar(MAX);

    DECLARE @cont_spilit_tittle int;
    DECLARE @parent_titles_tmp nvarchar(MAX);
    DECLARE @cont_tmp int;
    DECLARE @cont int;

    SELECT @cont = COUNT(*) FROM dbo.WorkSpace ;
    SET @cont_tmp = 0;

    WHILE (@cont_tmp < @cont)
    BEGIN  
        SET @W_ID = (SELECT dbo.WorkSpace.W_ID FROM dbo.WorkSpace  
                     ORDER BY W_ID ASC OFFSET @cont_tmp ROWS FETCH NEXT 1 ROWS ONLY)
        SET @parent_id = (SELECT dbo.WorkSpace.parent_id FROM dbo.WorkSpace 
                          ORDER BY W_ID ASC OFFSET @cont_tmp ROWS FETCH NEXT 1 ROWS ONLY)
        SET @titles_tmp = (SELECT dbo.WorkSpace.title FROM dbo.WorkSpace 
                           ORDER BY W_ID ASC OFFSET @cont_tmp ROWS FETCH NEXT 1 ROWS ONLY)
        SET @parent_titles_tmp = (SELECT dbo.WorkSpace.parent_titles FROM dbo.WorkSpace 
                                  ORDER BY W_ID ASC OFFSET @cont_tmp ROWS FETCH NEXT 1 ROWS ONLY)

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

        SELECT IDENTITY(INT, 1, 1) AS 'RowID', * 
        INTO #MyTempTable 
        FROM StringSplitXML(@parent_titles_tmp, '+')

        INSERT INTO #MyTempTable 
        VALUES (@titles_tmp)

        SET @cont_spilit_tittle = (SELECT COUNT(*) FROM #MyTempTable)

        IF(@cont_spilit_tittle < 0)
            SET @cont_spilit_tittle = 1

        WHILE (@cont_spilit_tittle < 15)
        BEGIN
            INSERT INTO #MyTempTable VALUES ('')
            SET @cont_spilit_tittle = CAST(@cont_spilit_tittle AS INT) + 1
        END

        SET @Level1 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level2 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level3 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level4 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 3 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level5 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 4 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level6 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 5 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level7 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 6 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level8 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 7 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level9 = (SELECT Value FROM #MyTempTable 
                       ORDER BY RowID ASC OFFSET 8 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level10 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 9 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level11 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 10 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level12 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 11 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level13 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 12 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level14 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 13 ROWS FETCH NEXT 1 ROWS ONLY)
        SET @Level15 = (SELECT Value FROM #MyTempTable 
                        ORDER BY RowID ASC OFFSET 14 ROWS FETCH NEXT 1 ROWS ONLY)


        INSERT INTO [].[dbo].[NEW_WorkSpace]
           ([W_ID], [parent_id],
            [Level1], [Level2], [Level3], [Level4], [Level5],
            [Level6], [Level7], [Level8], [Level9], [Level10],
            [Level11], [Level12], [Level13], [Level14], [Level15])
        VALUES (@W_ID, @parent_id,
                @Level1, @Level2, @Level3, @Level4, @Level5,
                @Level6, @Level7, @Level8, @Level9, @Level10,
                @Level11, @Level12, @Level13, @Level14, @Level15) 

        SET @cont_tmp = CAST(@cont_tmp AS INT) + 1
    END  

    RETURN
END

谢谢您的帮助。

sql sql-server sql-server-2014
2个回答
1
投票

嗯,这很丑陋,并假设您最多有15个级别,并且您的预期结果是错误的;因为我有W_ID,所以4的值为'DSO',但您的预期结果为Level_3,即使该行未以任何方式链接到CX

CX

USE Sandbox; GO CREATE TABLE dbo.YourTable (W_ID int NOT NULL, Title varchar(3) NOT NULL, Parent_id int NULL, View_Parent_id varchar(100) NULL); GO INSERT INTO dbo.YourTable VALUES (1,'AAA',NULL,NULL), (2,'BV',1,'1'), (3,'CX',2,'1+2'), (4,'DSO',2,'1+2'), (5,'ER',3,'1+2+3'), (6,'ER',5,'1+2+3+5'); GO SELECT * FROM dbo.YourTable; GO WITH rCTE AS( SELECT (YT.W_ID + 99) AS ID, YT.W_ID , YT.Parent_id, Title AS level_1, CONVERT(varchar(3),NULL) AS Level_2, CONVERT(varchar(3),NULL) AS Level_3, CONVERT(varchar(3),NULL) AS Level_4, CONVERT(varchar(3),NULL) AS Level_5, CONVERT(varchar(3),NULL) AS Level_6, CONVERT(varchar(3),NULL) AS Level_7, CONVERT(varchar(3),NULL) AS Level_8, CONVERT(varchar(3),NULL) AS Level_9, CONVERT(varchar(3),NULL) AS Level_10, CONVERT(varchar(3),NULL) AS Level_11, CONVERT(varchar(3),NULL) AS Level_12, CONVERT(varchar(3),NULL) AS Level_13, CONVERT(varchar(3),NULL) AS Level_14, CONVERT(varchar(3),NULL) AS Level_15, 1 AS [Level] FROM dbo.YourTable YT WHERE YT.Parent_id IS NULL UNION ALL SELECT (YT.W_ID + 99) AS ID, YT.W_ID, YT.Parent_id, r.Level_1, CASE r.[Level] WHEN 1 THEN YT.Title ELSE r.Level_2 END AS Level_2, CASE r.[Level] WHEN 2 THEN YT.Title ELSE r.Level_3 END AS Level_3, CASE r.[Level] WHEN 3 THEN YT.Title ELSE r.Level_4 END AS Level_4, CASE r.[Level] WHEN 4 THEN YT.Title ELSE r.Level_5 END AS Level_5, CASE r.[Level] WHEN 5 THEN YT.Title ELSE r.Level_6 END AS Level_6, CASE r.[Level] WHEN 6 THEN YT.Title ELSE r.Level_7 END AS Level_7, CASE r.[Level] WHEN 7 THEN YT.Title ELSE r.Level_8 END AS Level_8, CASE r.[Level] WHEN 8 THEN YT.Title ELSE r.Level_9 END AS Level_9, CASE r.[Level] WHEN 9 THEN YT.Title ELSE r.Level_10 END AS Level_10, CASE r.[Level] WHEN 10 THEN YT.Title ELSE r.Level_11 END AS Level_11, CASE r.[Level] WHEN 11 THEN YT.Title ELSE r.Level_12 END AS Level_12, CASE r.[Level] WHEN 12 THEN YT.Title ELSE r.Level_13 END AS Level_13, CASE r.[Level] WHEN 13 THEN YT.Title ELSE r.Level_14 END AS Level_14, CASE r.[Level] WHEN 14 THEN YT.Title ELSE r.Level_15 END AS Level_15, r.[Level] + 1 AS [Level] FROM dbo.YourTable YT JOIN rCTe r ON YT.Parent_id = r.W_ID) SELECT r.ID, r.W_ID, r.Parent_id, r.Level_1, r.Level_2, r.Level_3, r.Level_4, r.Level_5, r.Level_6, r.Level_7, r.Level_8, r.Level_9, r.Level_10, r.Level_11, r.Level_12, r.Level_13, r.Level_14, r.Level_15 FROM rCTE r; GO DROP TABLE dbo.YourTable;


1
投票

我将在db<>fiddle上使用字符串操作来解决这个问题。然后汇总最终结果:

view_parent_id

[with cte as ( select w_id, parent_id, view_parent_id, 0 as lev, convert(varchar(max), concat(view_parent_id, '+', w_id, '+')) as parents from t union all select w_id, parent_id, view_parent_id, 1 + lev, convert(int, left(parents, charindex('+', parents) - 1)), stuff(parents, 1, charindex('+', parents), '') from cte where parents <> '' ) select w_id, parent_id, view_parent_id, max(case when lev = 1 then parent_title end) as title_1, max(case when lev = 2 then parent_title end) as title_2, max(case when lev = 3 then parent_title end) as title_3, max(case when lev = 4 then parent_title end) as title_4, max(case when lev = 5 then parent_title end) as title_5 from (select cte.*, t.title as parent_title, count(*) over (partition by cte.w_id) as cnt from cte join t on t.w_id = cte.parent where lev > 0 ) cte group by w_id, parent_id, view_parent_id; 是db <>小提琴。

至于处理。查询中最昂贵的部分可能是递归CTE之后的聚合。递归部分没有进行任何连接,因此应该相当快(字符串操作可能很慢)。

获得标签的联接使用正确的类型,因此可以使用Here上的索引。

© www.soinside.com 2019 - 2024. All rights reserved.