在MS-SQL中创建动态表(可行性)

时间:2018-10-17 21:20:23

标签: arrays sql-server dynamic dynamic-memory-allocation sp-executesql

有没有一种方法可以基于动态值创建表数组(或动态创建的表)?例如,我知道在C ++中可以使用指针和动态内存,但是我需要在SQL中执行类似的操作。

用户指定他们要查看每年X年的数据,我们需要查看可以在临时表中建立的15多个列(每年相同)。

用户选择5年的数据和当前年份为2018,所以我想为2018, 2017, 2016, 2015 and 2014.动态创建一个本地表。每个表都将跟踪客户数据,销售额等。每个表相同。

如果上述操作不可行,我们是否可以限制用户仅选择年份,并且动态地始终坚持5年。用户指定他们想以2017开头,我们将默认为他们构建2017, 2016 ... 2013.

我可以继续说创建表#year1, #year2, #year3 etc.,但这需要大量的编码(主要是预先复制和粘贴)。有没有一种方法可以避免这种情况-例如创建表#years[]或指针?然后动态建立某种#years表数组。

我们最终要做的是逐年查询完全相同的查询/逻辑。然后最后比较谁/属于哪一年以及如何。底线是为了避免将相同的声明/选择/插入语句复制和粘贴5次或更多次? (并且尽可能避免出现游标/循环)

我尝试编码类似

DECLARE @season_counter int = 5

    DECLARE @cnt int = 0
    Declare @cnt_v varchar(1)  =  CONVERT(varchar(10), @cnt)

    DECLARE @SQL NVARCHAR(max) = ''

     WHILE @cnt <= @season_counter
     BEGIN
        select   @SQL =  @SQL + ' create table #year' + @cnt_v
         +  ' (customer_no int, order_no int, perf_no int, due_amt money, paid_amt money, status int ) ' 

        exec sp_executesql @SQL
        print @SQL 

        set @cnt = @cnt + 1
        set @cnt_v = CONVERT(varchar(10), @cnt)
        set @sql = ''


    END

select * from #year1
select * from #year2

上面产生的错误

Msg 208, Level 16, State 0, Line 81
Invalid object name '#year1'. 

我不能使用全局变量,我敢肯定,我不想声明20个表的Create语句(作为一些最大值)。我希望它是动态的和动态的。请指教。

2 个答案:

答案 0 :(得分:0)

如果不使用某种循环和动态SQL,我看不到任何方法。 [添加:]循环遇到SQL Server的已知限制:您无法通过动态SQL创建临时表。如果首先创建了临时表,则可以在动态SQL中对其进行引用,但这不能达到目的。但是,您可以通过SELECT INTO功能创建表。这将创建一个实际的表,但是您可以在代码中删除并重新创建它们。

就个人而言,我还喜欢为此类事物创建一个新的架构-通常为“ x”-以便它们在Management Studio中仅显示在所有“ dbo”架构表之后的底部。您只创建一次架构,因此不要在循环中包含该部分:

CREATE SCHEMA x;
GO

DECLARE @SQLCmd NVARCHAR(MAX)
--Loopify this part:
SET @SQLCmd = 
'IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ''Temp1'')
    DROP TABLE Temp1;

SELECT *
INTO x.Temp1
FROM YourDB.dbo.YourTable
WHERE foo = ''bar'';'

--PRINT @SQLCmd
EXEC(@SQLCmd);

答案 1 :(得分:0)

绝对可以在这里成为动态SQL的朋友: 例如,按照需要创建数据透视表,可以使用以下脚本:

GO
DECLARE @startYear AS INT = 2000
DECLARE @endYear AS INT =2100
--Magic insert
;
WITH L0
AS ( SELECT c
     FROM   (   SELECT 1
                UNION ALL
                SELECT 1 ) AS D(c) ) , -- 2^1
     L1
AS ( SELECT NULL AS c
     FROM   L0 AS A
            CROSS JOIN L0 AS B ) ,       -- 2^2
     L2
AS ( SELECT NULL AS c
     FROM   L1 AS A
            CROSS JOIN L1 AS B ) ,       -- 2^4
     L3
AS ( SELECT NULL AS c
     FROM   L2 AS A
            CROSS JOIN L2 AS B ) ,       -- 2^8
     L4
AS ( SELECT NULL AS c
     FROM   L3 AS A
            CROSS JOIN L3 AS B ) ,       -- 2^16
     L5
AS ( SELECT NULL AS c
     FROM   L4 AS A
            CROSS JOIN L4 AS B ) ,       -- 2^32
     Nums
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )) AS id
     FROM   L5 ) ,
     years
AS ( SELECT id AS [year]
     FROM   Nums
     WHERE  id >= @startYear AND id<=@endYear )

SELECT [year] INTO #years
FROM   years


DECLARE @columns VARCHAR(MAX)='' 
DECLARE @curentYear int = @startYear;
WHILE @curentYear <= (SELECT MAX([year]) from #years)
BEGIN
    SET @columns+= '['+(SELECT Cast([year] as VARCHAR(4)) FROM #years WHERE [year] = @curentYear)+'],'
    SET @curentYear += 1;
END

SET @columns = SUBSTRING(@columns,1,LEN(@columns)-1)

DECLARE @SQL NVARCHAR(max)=
'SELECT * FROM #years PIVOT(MAX([year]) FOR [year] IN ('+   @columns+')) AS piv'

EXEC sys.sp_executesql @SQL

enter image description here