繁体   English   中英

使用动态列创建表

[英]CREATE TABLE with Dynamic Column

我需要将一些数据插入临时表。

我有一些基于条件的列,如SalaryCode

如何为基于条件的列创建表? 我不想使用 SELECT INTO #tempTable

这是代码:

DECLARE @sql NVARCHAR(MAX)
,@sqlSelect NVARCHAR(MAX) = ''
,@sqlFrom NVARCHAR(MAX) =''

CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100))


SET @sqlSelect ='INSERT INTO #myTempTable
SELECT EMP.Id, EMP.DeptId, EMP.DeptName'

SET @sqlFrom =' FROM dbo.EMPLOYEE AS EMP'

IF (someCondition)
BEGIN
    SET @sqlSelect = @sqlSelect +', EMP.Salary, EMP.Code'            
END

SET @sql =  @sqlSelect +@sqlFrom 

EXEC sp_executesql @sql

关于我能做得更好的任何帮助/建议?


更新:

最初我使用SELECT INTO #TempTable而没有指定任何列,因为SQL Azure不支持,我决定使用INSERT INTO 但不确定如何在已定义的结构中添加动态列。 它完全动态的SQL :(

您需要多少个动态列?

如果有一个名为Dynamic of type nvarchar(MAX)之类的列,那么你可以将数据放在那里并根据需要进行格式化。

另一种选择是创建一个包含NULL列的表。

要在SQL中执行此操作,您可以执行以下操作:

CREATE TABLE tblPerson
(
    PersonId INT,
    FirstName NVARCHAR(256),
    LastName NVARCHAR(256) NULL,
    PRIMARY KEY (PersonId)
)

请注意上面的NULL列。

有关在SQL中使用Primary KeysNULL列创建表的更多说明,请参见此处:

在SQL中创建表

如上所述,您最好的选择是创建所需的所有列,并在可选时使其为NULL。 所以:

CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100), Salary INT NULL, EmpCode VARCHAR(45) NULL);

IF (someCondition)
BEGIN
    SET @sqlSelect = @sqlSelect +', EMP.Salary, EMP.Code'            
END
ELSE
BEGIN
    SET @sqlSelect = @sqlSelect +', NULL, NULL'            
END

见下面的例子:

declare @sql nvarchar(400)
declare @ColFlag int
set @ColFlag = 1
if(@ColFlag = 0)

set  @sql= 'CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100)); 
    INSERT INTO #myTempTable SELECT 1,2,''DeptName1''; 
    SELECT * FROM #myTempTable'
else
set  @sql= 'CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100), MyNewColHere VARCHAR(25)); 
    INSERT INTO #myTempTable SELECT 1,2,''DeptName1'', ''MyNewColHereValue''; 
    SELECT * FROM #myTempTable'

 exec (@sql)

下面的代码可能适合您。

DECLARE @sql NVARCHAR(MAX)
,@sqlSelect NVARCHAR(MAX) = ''

,@sqlFrom NVARCHAR(MAX) =''

IF (someCondition)
BEGIN
    CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100))    
END
ELSE
BEGIN
    CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100),Salary numeric(18,2), Code INT)    
END

SET @sqlSelect ='INSERT INTO #myTempTable
SELECT EMP.Id, EMP.DeptId, EMP.DeptName'

SET @sqlFrom =' FROM dbo.EMPLOYEE AS EMP'

IF (someCondition)
BEGIN
    SET @sqlSelect = @sqlSelect +', EMP.Salary, EMP.Code'            
END

SET @sql =  @sqlSelect +@sqlFrom 

EXEC sp_executesql @sql

您可以在条件满足时更改临时表(我假设您知道此时所需的列?)

IF (someCondition)
BEGIN
    ALTER TABLE #myTempTable ADD Salary VARCHAR(20), Code VARCHAR(20)
    SET @sqlSelect = @sqlSelect +', EMP.Salary, EMP.Code'            
END

如果您有多个可以激活的条件,您可能想要先测试该列是否存在 - 您可以这样做:

IF COL_LENGTH('#myTemptable','Salary') IS NULL
BEGIN
     -- do something if salary doesn't exist
     ALTER TABLE #myTempTable ADD Salary NUMERIC(6,2)
END

正如其他人所指出的那样,您可以将列预先创建为可为空的列 - 或者在满足条件后创建表。

你能用吗?

sp_RENAME 'TableName.[OldColumnName]' , '[NewColumnName]', 'COLUMN' 

用于更改先前定义的占位符列的名称的命令。
例如,使用额外的字段创建#tempTable ,例如"VCHAR100_1""BOOL_1""Int_1"等。如果您需要使用该字段,请将其重命名为所需的名称,以便稍后您的代码可以引用该列一个非神秘的名字。

我认为你真正想要的是SQL不可能的。 因为我想要添加列,例如符合条件的元组。 所以我认为你需要一些像NoSQL这样的其他数据库引擎(我对NoSQL不是很熟悉,但我知道它可以横向扩展)

如果你不想从sql切换我认为你应该重新考虑你的设计。
如果你坚持你的设计,你可以做一些事情,例如添加一个列,命名“列名”和另一列“列数据”,并在需要时填写它。 但是你可以看到它有自己的约束,比如“列数据”的数据应该是相同的类型。

使用代码并告诉我它是否正常工作?

-----------------------------------------------------

DECLARE @sql NVARCHAR(MAX)
,@sqlSelect NVARCHAR(MAX) = ''

,@sqlFrom NVARCHAR(MAX) =''

IF (someCondition)
BEGIN
    CREATE TABLE #tblInfo (Id INT, DeptId INT, DeptName VARCHAR(100))    
END
ELSE
BEGIN
    CREATE TABLE #tblInfo (Id INT, DeptId INT, DeptName VARCHAR(100),Salary numeric(18,2), Code INT)    
END

SET @sqlSelect ='INSERT INTO #tblInfo 
SELECT EMP.Id, EMP.DeptId, EMP.DeptName'

SET @sqlFrom =' FROM dbo.EMPLOYEE AS EMP'

IF (someCondition)
BEGIN
    SET @sqlSelect = @sqlSelect +', EMP.Salary, EMP.Code'            
END

SET @sql =  @sqlSelect +@sqlFrom 

EXEC sp_executesql @sql

------------------------------------

我希望它能奏效

如果这个表是BIG,我认为你和你的逻辑你用这个表进行JOINS你需要在TARGET TABLE中创建索引

您可以使用物理表而不是TEMP

DECLARE @guid NVARCHAR(64), @sql NVARCHAR(MAX)
,@sqlSelect NVARCHAR(MAX) = ''
,@sqlFrom NVARCHAR(MAX) ='', @sqlSchema NVARCHAR(MAX) =''

SET @guid = NEWID()  

declare @tableName NVARCHAR(64)= 'myTempTable'+ @guid

select @tableName

--use some transaction

set @sql = 'CREATE TABLE ' + @tableName  
set @sqlSchema = '(Id INT, DeptId INT, DeptName VARCHAR(100)'  -- DO INDEXES IF YOU ARE JOIN 

SET @sqlSelect ='INSERT INTO ' + @tableName +
'SELECT EMP.Id, EMP.DeptId, EMP.DeptName'


IF (1=1) -- your condition
BEGIN
  SET @sqlSchema = @sqlSchema +', EMP.Salary, EMP.Code'            
END

SET @sqlSchema =   @sqlSchema + ')' -- close last )

set @sql =  @sql +@sqlSchema --create the TargetTable


--DO YOUR logic

EXEC sp_executesql @sql

set @sql = N'DROP TABLE ' + @tableName

EXEC sp_executesql @sql

尝试这个。

Begin Tran


IF (someCondition)

    Begin 
      CREATE TABLE #myTempTable (Id INT, DeptId INT, DeptName VARCHAR(100), Salary money , Code Int)

        Insert Into #myTempTable(Id, DeptId, DeptName, Salary, Code)
        Select Emp.Id, Emp.DeptID, Emp.DeptName, EMP.Salary, EMP.Code 
        From dbo.Employee As Emp

        Select Id, DeptID, DeptName, Salary, Code From dbo.Employee
              Drop Table #myTempTable     
    End

    Else

    Begin

      CREATE TABLE #myTempTable2 (Id INT, DeptId INT, DeptName VARCHAR(100))

        Insert Into #myTempTable(Id, DeptId, DeptName)
        Select Emp.Id, Emp.DeptID, Emp.DeptName 
        From dbo.Employee As Emp

        Select Id, DeptID, DeptName From dbo.Employee

                    Drop Table #myTempTable2 
    End



Commit Tran

这是另一个具有完全动态列的解决方案:

DECLARE @sql NVARCHAR(MAX)
,@sqlTableName NVARCHAR(MAX) = ''
,@sqlColumnsDefinitions NVARCHAR(MAX) =''
,@sqlColumnsList NVARCHAR(MAX) =''
,@sqlFrom NVARCHAR(MAX) =''

SET @sqlTableName = 'myTempTable'
SET @sqlFrom = 'FROM dbo.EMPLOYEE AS EMP'

--conditions to define columns
IF (1=1)
    set @sqlColumnsDefinitions='Col1 int, Col2 int, Col3 int'
else
    set @sqlColumnsDefinitions='Col1 int, Col2 int, Col3 int, Col4 int, Col5 int'

--new table with dynamic fields creation
SET @sql = 'if (object_id('''+@sqlTableName+''') is not null) DROP TABLE '+@sqlTableName+'
CREATE TABLE '+@sqlTableName+' ('+@sqlColumnsDefinitions+')'+char(10)
print (@sql)
exec (@sql)

--get columns list
select @sqlColumnsList=STUFF((SELECT ',' + column_name
from INFORMATION_SCHEMA.COLUMNS where table_name like @sqlTableName+'%' FOR XML PATH('')), 1, 1, '')

--main insert
SET @sql = 'INSERT INTO '+@sqlTableName+char(10)+'SELECT '+@sqlColumnsList+char(10)+@sqlFrom
print (@sql)
exec  (@sql)

如果因为SQL引擎而将myTempTable替换为#myTempTable,则这将不起作用。 要修复它并获得正确的列名列表,您可能会使用超出范围的一些技巧。 但它仍适用于非临时表。

您可以生成动态改变表结构的ALTER语句。 下面显示的是临时表,但当然这种方法也适用于普通表。

 IF OBJECT_ID( 'tempdb..#temp') IS NOT NULL
    BEGIN
   DROP TABLE #temp
   END
CREATE TABLE #temp
    (
    [CVRelID]       INT,
    [CustomerID]    INT,
    [VendorID]      INT,
    [TransactionID] INT
    )

DECLARE @script VARCHAR(8000)
SET     @script = 'ALTER TABLE #temp ADD '

SELECT  @script = @script + QUOTENAME(SDName) + ' VARCHAR(100),'
FROM    tblSupportDocuments
WHERE   SDIsActive = 1


SET     @script = SUBSTRING( @script, 1, LEN(@script) - 1)-- remove last ","
PRINT   @script
EXEC    (@script)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM