有没有一种方法可以基于动态值创建表数组(或动态创建的表)?例如,我知道在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语句(作为一些最大值)。我希望它是动态的和动态的。请指教。
答案 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