动态T-SQL-将参数化的子查询追加到临时聚合表

时间:2019-05-10 15:35:14

标签: sql sql-server tsql dynamic-sql

此数据库的模式为奇数;所有数据均按数据类型分解并存储在相应的表中。当需要访问“表”时,需要将其缝在一起,按表ID组合字段,按字段ID组合值。它运行缓慢,并且很大程度上已由第三方意大利面条脚本处理。

我有些表格的格式如下:

dbo.TagSource:

TagSourceId | Table Name | ...
------------------------------------
01            Table 1
02            Table 2

dbo.Tag:

TagId | TagSourceId | Field Name | RawTableName | ...
------------------------------------------------------
11      01            Name         dbo.StringValue
12      01            Age          dbo.IntegerValue
13      01            Balance      dbo.DecimalValue
14      01            Document     dbo.FileValue
15      02            Name         ExternalTable1
16      02            Height       ExternalTable1
17      02            Occupation   ExternalTable2

dbo。[字符串/整数/小数/文件/ ...]值表:

ValueId | TagId | Value
-------------------------------
101       11      John Smith
102       11      Jane Smith
103       11      John Doe 
104       11      Jane Doe
105       11      Thanos

目标:要创建以TagSourceID作为参数/声明的变量的TSQL查询脚本(存储过程/函数/视图),请返回相应的表。最终,它将用于创建视图,直到我有足够的带宽来替换和替换此数据库架构为止。

实现此目的的最佳方法是什么?这是一个挑战,因为每个表中的字段数是动态的,并且列定义是未知的。

尝试: 我曾尝试使用临时表来保存我的汇总数据和要追加的数据,但是很快发现,由于必须预定义列定义,因此我不得不在临时表之间使用笨拙的数据处理方法。似乎是次优的,即使它起作用,也没有。

逻辑:

BEGIN LOOP
#B = #A Join (Select value From dbo...Value Table...)
Drop Table #A
#A = #B
Drop Table #B
END

脚本: 即使我已明确There is already an object named '#ResultSet' in the database.错误行之前的行,也会返回错误DROP TABLE #ResultSet

--*** DECLARATION ***
USE [DB_Arc];
GO

-- ***************
-- Target Table Id
DECLARE @TagSourceID INT = 130;
-- ***************

-- Temporary Tables - DROP IF EXIST
-- #TempA
IF OBJECT_ID(N'#ResultSet') IS NOT NULL DROP TABLE #ResultSet;
CREATE TABLE dbo.#ResultSet (
    DateTime DATETIME,
    GroupID NVARCHAR(50)
);
-- #TempB
IF OBJECT_ID(N'#JoinSet') IS NOT NULL DROP TABLE #JoinSet;
CREATE TABLE dbo.#JoinSet (
    DateTime DATETIME,
    GroupID NVARCHAR(50)
);

-- Target Fields - Iterator
DECLARE field_cursor CURSOR FOR
SELECT Id, Name, RawTableName
FROM dbo.[Tag]
WHERE TagSourceId = @TagSourceID
AND Name NOT IN ('DateTime','GroupId')
AND TagTypeId NOT IN (6,7)
ORDER BY Id;

-- Local Variables
DECLARE @TagId bigint, @TagName nvarchar(250), @RawTableName nvarchar(250)

OPEN field_cursor;

-- Initial first fetch and store
FETCH NEXT FROM field_cursor
INTO @Tag, @TagName, @RawTableName;

-- Verify that the table where the values are stored is not external.
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @RawTableName)
BEGIN --IF BLOCK
    -- Check @@FETCH_STATUS for any other rows to fetch
    WHILE @@FETCH_STATUS = 0
    -- Loop through each field/column...
    BEGIN --LOOP START
        -- full outer join values from rawtables to ResultSet

        -- #TempB = #TempA Join (Select value From dbo...Value Table...)
        DECLARE @field nvarchar(500);
        SET @field = 
        N'SELECT a.*, b.value AS ' + QuoteName(@TagName) +
        N'INTO #JoinSet
          FROM #ResultSet a
          FULL OUTER JOIN ( 
            SELECT
                CONVERT(datetime2, [DateTime], 1) as DateTime,
                [GroupId],
                [Value]
            FROM dbo.' + QuoteName(@RawTableName) +
            N'WHERE TagId = ' + QuoteName(@TagId) + N'AND 
            IsDeleted=0 ) b
          ON a.DateTime = b.DateTime AND a.GroupId = b.GroupId
        ';
        EXEC sp_executesql @field;

        -- DROP TABLE #TempA
        IF OBJECT_ID(N'#ResultSet') IS NOT NULL DROP TABLE #ResultSet
        -- #TempA = #TempB
        -- ***** ERROR BLOCK START *****
        -- Returns 'There is already an object named '#ResultSet' in the database.'
        SELECT *
        INTO #ResultSet
        FROM #JoinSet;
        -- ***** ERROR BLOCK END *****
        -- DROP TABLE #TempB
        DROP TABLE #JoinSet;


        -- Iterate values to next field
        FETCH NEXT FROM field_cursor
        INTO @Tag, @TagName, @RawTableName;
    END --LOOP END

END --IF BLOCK END

CLOSE field_cursor;
DEALLOCATE field_cursor;

SELECT * FROM #ResultSet;
DROP TABLE #ResultSet;

GO

我也一直在寻找创建一个递归过程/函数来处理此问题,但是我在使用游标作为递归条件时遇到了麻烦,并且具有静态列定义的表变量/临时表仍然是一个问题。

任何帮助将不胜感激。如果您对此脚本的用途有疑问或有任何一般性建议,我非常希望听到它。

1 个答案:

答案 0 :(得分:1)

脚本中的三个问题-

  1. 在#Temporary表和从动态脚本返回的行之间的列名和列号之间应该具有同步 从“ SELECT a。*,b.value AS ..........”中选择。
  2. 无需创建第二个#Temporary表(#JoinSet),因为我们可以直接将其插入#ResultSet表中。
  3. 脚本“ SELECT * INTO #Temp ......”始终尝试在已创建表的位置创建临时表。我们需要将脚本改为 类似“ INSERT INTO #ResultSet SELECT a。*,b.value .........”。