无论SQL Server中的列名称如何,都将整行选择到另一个表中

时间:2010-07-21 18:03:44

标签: sql-server select

有没有办法从临时表(表中只有一行)中选择行,到另一个表中有一些带有不同名称的列?例如:

不是Temptable

FirstName        LastName          Column1       Column2
------------    ------------     -----------   -----------
Joe              Smith             OKC           TX

OtherTable

FirstName       LastName          Region1        Region2        Region3
------------    ------------     -----------   -----------     ----------
NULL              NULL             NULL           NULL           NULL

我需要以与TempTable中的列相同的顺序将数据复制到OtherTable中。 TempTable并不总是相同....有时它会有3列,有时只有2 ......等。如果它与OtherTable的列数不同,则剩余的“Region”列应保持为null。

最终结果应为:

OtherTable

FirstName       LastName         Region1       Region2         Region3
------------    ------------     -----------   -----------     ----------
Joe              Smith             OKC           TX               NULL

加上TEMPTable中的列名永远不会相同......因为在一次它将是“Column1”......下次它可能是“XXXXX1”。这就是为什么我只想复制数据......数据总是按照正确的顺序......

大声笑......这甚至有意义吗?这适用于SQL Server 2005

3 个答案:

答案 0 :(得分:1)

编辑........添加了动态SQL生成

此代码将生成INSERT语句,以便从#TEMP INSERT到#TEMP。如果从#temp到常规表,你可以调整它以适合你的目的。

SET NOCOUNT ON
DROP Table #TempTable1
DROP Table #TempTable2
GO
DROP Function GenerateInserts
GO
Create Function GenerateInserts
(
    @SourceTable    VarChar (100),
    @DestinationTable   VarChar (100)
)
Returns VarChar (MAX)
AS
BEGIN

DECLARE @SelectString VarChar (MAX)
DECLARE @InsertString VarChar (MAX)
DECLARE @SQLString VarChar (MAX)

DECLARE @SourceColumnCount  INTEGER
DECLARE @DestinationColumnCount INTEGER
DECLARE @ColumnCount    INTEGER
DECLARE @Counter    INTEGER

SELECT @SourceColumnCount = COUNT (*)
FROM tempdb..syscolumns 
WHERE id=object_id(@SourceTable)

SELECT @DestinationColumnCount = COUNT (*)
FROM tempdb..syscolumns 
WHERE id=object_id(@DestinationTable)

SET @ColumnCount = @SourceColumnCount

IF @DestinationColumnCount < @ColumnCount
    SET @ColumnCount = @DestinationColumnCount

SET @Counter = 0

SET @SelectString = ' INSERT INTO ' + @DestinationTable + ' '
SET @InsertString = ' INSERT INTO ' + @DestinationTable + ' '

SET @SelectString = ''
SET @InsertString = ''

WHILE @Counter <= @ColumnCount
BEGIN
    SELECT @SelectString = @SelectString  + ', ' + Name
    FROM TempDB..SysColumns 
    WHERE Id = Object_Id (@SourceTable)
    AND ColOrder = @Counter

    SELECT @InsertString = @InsertString  + ', ' + Name
    FROM TempDB..SysColumns 
    WHERE Id = Object_Id (@DestinationTable)
    AND ColOrder = @Counter

    SET @Counter = @Counter  + 1
END

SET @InsertString = 'INSERT INTO ' + @DestinationTable + ' (' +  STUFF (    @InsertString, 1, 2, '') + ') '
SET @SelectString = 'SELECT ' +  STUFF (    @SelectString, 1, 2, '') + ' FROM ' + @SourceTable

SET @SQLString = @InsertString + '
'+ @SelectString

RETURN @SQLString
END

GO

Create Table #TempTable1
(
    Col1 VarChar (10), 
    Col2 VarChar (10), 
    Col3 VarChar (10),
    Col4 VarChar (10), 
    Col5 VarChar (10) 
)
Create Table #TempTable2
(
    MyCol1 VarChar (10), 
    MyCol2 VarChar (10), 
    MyCol3 VarChar (10),
    MyCol4 VarChar (10), 
    MyCol5 VarChar (10), 
    MyCol6 VarChar (10)
)

SELECT dbo.GenerateInserts ('tempdb..#TempTable1', 'tempdb..#TempTable2')



OLD ANSWER

是的,你可以这样做,但你必须为每种INSERT编写不同的陈述。您必须在两个位置指定列名称 - INSERT INTOSELECT


如果源表和目标表中的列数相同,请执行此操作

INSERT INTO Table1 (Column1, Column2, Column3)
SELECT MyColumn01, MyColumn02, MyColumn03
FROM MyTable 

这将做的是如下地图:

MyTable.MyColumn01 - &gt; Table1.Column1 MyTable.MyColumn02 - &gt; Table1.Column2 MyTable.MyColumn03 - &gt; Table1.Column3


如果Source的列数较少,则可以使用NULL值代替列名

INSERT INTO Table1 (Column1, Column2, Column3)
SELECT MyColumn01, MyColumn02, NULL AS MyColumn03
FROM MyTable 

OR 您可以使用两个列名称

INSERT INTO Table1 (Column1, Column2)
SELECT MyColumn01, MyColumn02
FROM MyTable 

如果目标表的列数少于源,则必须忽略源

中的列
INSERT INTO Table1 (Column1, Column2, Column3)
SELECT MyColumn01, MyColumn02, NULL AS MyColumn03 /* MyColumn04, MyColumn05 are ignored */
FROM MyTable 

答案 1 :(得分:1)

您可以使用动态SQL执行某些操作。

我建议阅读“动态SQL的诅咒和祝福 - Dealing with Dynamic Table and Column Names“如果这对你来说是新的。

示例如下。您可以改进这一点以确保源列和目标列是兼容类型或排除标识或计算列,但它应该给你一个想法。

DECLARE @SourceTable sysname
DECLARE @DestTable sysname

SET @SourceTable = '[dbo].[#TempTable]'
SET @DestTable = '[dbo].[OtherTable]'


DECLARE @DynSQL1 NVARCHAR(MAX)
DECLARE @DynSQL2 NVARCHAR(MAX)


SELECT 
@DynSQL1 = ISNULL(@DynSQL1 + ',','') + QUOTENAME(sc1.name),  
@DynSQL2 = ISNULL(@DynSQL2 + ',','') + QUOTENAME(sc2.name)
FROM tempdb..syscolumns sc1
JOIN syscolumns sc2 
  ON sc1.colorder = sc2.colorder /*Match up the columns by column order*/
WHERE sc1.id=OBJECT_ID('tempdb.' + @SourceTable) AND sc2.id=OBJECT_ID(@DestTable)

IF @@ROWCOUNT = 0
  RETURN


SET @DynSQL1 = 'INSERT INTO ' + @DestTable + ' (' + @DynSQL2 + ')
  SELECT ' + @DynSQL1 + ' FROM '+ @SourceTable +';'

EXEC sp_executesql @DynSQL1

答案 2 :(得分:0)

您可以指定目标表的列:

INSERT INTO OtherTable (FirstName, LastName, Region1, Region2)
  SELECT FirstName, LastName, Column1, Column2 FROM TempTable;

在这个例子中,OtherTable.Region3将以NULL结尾(或者如果它具有DEFAULT值,它将使用它)。

INSERT 中的列数必须SELECT中的列数相匹配。因此,您必须知道TempTable中有多少列,并为插入匹配创建列列表。

但是如果你只是抛出SELECT *,就没有办法用隐式列做到这一点。


重新评论:您可以使用INFORMATION_SCHEMA查询表格中的计数和列名称。

SELECT COLUMN_NAME
FROM tempdb.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = 'tempdb' AND TABLE_SCHEMA = 'MySchema'
  AND TABLE_NAME LIKE 'MyTempTable%';

然后,您将编写应用程序代码,以根据此information_schema查询的结果创建SQL INSERT...SELECT语句。

注意:通过information_schema查询临时表需要special handling