如何从动态列表创建临时表

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 函数中的动态命名临时表运行“选择进入”

Postgres 从动态 sql 字符串创建本地临时表(在提交删除时)

具有动态结果的存储过程到临时表中

oracle存储过程中临时表的使用,该怎么处理

在 FUNCTION 中创建临时表 [重复]

从 SQL 动态结果插入临时表