如何从动态列表创建临时表
Posted
技术标签:
【中文标题】如何从动态列表创建临时表【英文标题】:How to create a temp table from a dynamic list 【发布时间】:2014-03-11 00:35:15 【问题描述】:我有一个表 FieldList (ID int, Title varchar(50)),想为 FieldList 中的每条记录创建一个列列表的临时表,列名 = FieldList.Title,类型为 varchar。
这一切都发生在存储过程中,并将临时表返回给客户端进行报告和数据分析。
例如
字段列表:
身份证标题
1 个城市
2 用户提供字段名称
3 一些领域
结果临时表列:
City UserSuppiedFieldName SomeField
【问题讨论】:
【参考方案1】:您可以使用以下过程来做您想做的事。它只要求你:
-
在调用 proc 之前创建临时表(您将把临时表名称传递给 proc)。这允许在当前范围内使用临时表,因为一旦 proc 结束/返回,在存储过程中创建的临时表就会被删除。
在临时表中只放一个字段;数据类型无关紧要,因为该字段将被删除(您将字段名称传递给 proc)
[请务必将 proc 名称更改为您喜欢的任何名称,但后面的示例中使用的是 temp proc 名称]
CREATE PROCEDURE #Abracadabra
(
@TempTableName SYSNAME,
@DummyFieldName SYSNAME,
@TestMode BIT = 0
)
AS
SET NOCOUNT ON
DECLARE @SQL NVARCHAR(MAX)
SELECT @SQL = COALESCE(@SQL + N', [',
N'ALTER TABLE ' + @TempTableName + N' ADD [')
+ [Title]
+ N'] VARCHAR(100)'
FROM #FieldList
ORDER BY [ID]
SET @SQL = @SQL
+ N' ; ALTER TABLE '
+ @TempTableName
+ N' DROP COLUMN ['
+ @DummyFieldName
+ N'] ; '
IF (@TestMode = 0)
BEGIN
EXEC(@SQL)
END
ELSE
BEGIN
PRINT @SQL
END
GO
以下示例显示了正在使用的 proc。第一次执行是在测试模式下,它只打印将要执行的 SQL。第二次执行运行 SQL 和 SELECT,EXEC 显示字段是 FieldList 表中的内容。
/*
-- HIGHLIGHT FROM "SET" THROUGH FINAL "INSERT" AND RUN ONCE
-- to setup the example
SET NOCOUNT ON;
--DROP TABLE #FieldList
CREATE TABLE #FieldList (ID INT, Title VARCHAR(50))
INSERT INTO #FieldList (ID, Title) VALUES (1, 'City')
INSERT INTO #FieldList (ID, Title) VALUES (2, 'UserSuppliedFieldName')
INSERT INTO #FieldList (ID, Title) VALUES (3, 'SomeField')
*/
IF (OBJECT_ID('tempdb.dbo.#Tmp') IS NOT NULL)
BEGIN
DROP TABLE #Tmp
END
CREATE TABLE #Tmp (Dummy INT)
EXEC #Abracadabra
@TempTableName = N'#Tmp',
@DummyFieldName = N'Dummy',
@TestMode = 1
-- look in "Messages" tab
EXEC #Abracadabra
@TempTableName = N'#Tmp',
@DummyFieldName = N'Dummy',
@TestMode = 0
SELECT * FROM #Tmp
@TestMode = 1
的输出:
ALTER TABLE #Tmp ADD [City] VARCHAR(100), [UserSuppliedFieldName] VARCHAR(100), [SomeField] VARCHAR(100) ;更改表 #Tmp 删除列 [假人] ;
【讨论】:
我希望不使用 exec 以便进行编译优化,但我会接受它。 @Tremour101:如果您的意思是 proc 的 EXEC,那么这可以内联完成,但似乎更容易封装。如果您的意思是 proc 中的 EXEC,那么是的,我看不出有任何解决方法,因为 DDL 语句(CREATE TABLE 和 ALTER TABLE)不允许使用变量。【参考方案2】:创建这个函数并将你需要的列表传递给它。它将临时为您生成一个表,您可以将其与任何其他 SQL 查询实时使用。我也提供了一个例子。
CREATE FUNCTION [dbo].[fnMakeTableFromList]
(@List varchar(MAX), @Delimiter varchar(255))
RETURNS table
AS
RETURN (SELECT Item = CONVERT(VARCHAR, Item)
FROM (SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM (SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') + '</i>').query('.')) AS a
CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL);
GO
你可以这样使用它...
Parm1 = 由分隔符分隔的字符串中的列表 Parm2 = 分隔符
SELECT *
FROM fnMakeTableFromList('a,b,c,d,e',',')
结果是一个表格... 一种 b C d e
【讨论】:
这将创建一个包含一个字段(项目)和 5 行(a、b、c、d、e)的表。我需要的是最终得到一个没有行的表和五个字段(a、b、c、d、e)。【参考方案3】:使用之前创建的带有字段“ID”和“标题”的表“FieldList”...
第 1 步: 创建表。 “First”字段只是有一个字段,我们将在最后删除它
create table #SOE (First varchar(50))
第二步:右键选择“Result To -> Result to text”,然后运行查询:
select 'alter table #SOE add ' + Title + ' varchar(50)' from dbo.FieldList
第三步:复制粘贴结果并执行
第 4 步:删除第一个字段
alter table #SOE drop column First
第 5 步:这是你的桌子
select * from #SOE
【讨论】:
以上是关于如何从动态列表创建临时表的主要内容,如果未能解决你的问题,请参考以下文章
无法从 plpgsql 函数中的动态命名临时表运行“选择进入”