从另一个查询插入记录

Posted

技术标签:

【中文标题】从另一个查询插入记录【英文标题】:Inserting records from another query 【发布时间】:2014-02-12 20:03:00 【问题描述】:

我是初学者,对 SQL 有一些基本的了解。我必须编写一个查询来从表中选择记录并插入到另一个表中。我的 TABLE1 有近 180 多列,而 TABLE2 只有 6 列。在 TABLE2 中,前 4 列是静态的,将直接来自 TABLE1。 TABLE2 中的其他 2 列是动态的。它们将由 180 多个列中的每一列填充,其中列名和列值来自 TABLE1。如果不是很清楚,让我用结构来解释一下:

>T1:  
>===  
>Col1, Col2, Col3, Col4, Col5,..........,Col175, Col176, Col177, Col178, Col179, Col180
>
>T2:  
>===  
>Col1, Col2, Col3, Col4, NewCol1, NewCol2

所以我想要一个查询来从 T1 中选择记录并将它们插入到 T2 中,这样

T2.Col1 = T1.Col1 T2.Col2 = T1.Col2 T2.Col3 = T1.Col3 T2.Col4 = T1.Col4 T2.NewCol1 = 来自 T1 的 Column_Name(即 Col5、Col6、Col7... Col180) T2.NewCol2 = 我们存储在 T2.NewCol2 中的列的 Column_Value

这里是示例:

T1:

Col1 | Col2 | Col3 | Col4 | Col5 | Col6 | Col7 |科尔8 | Col9 | Col10 | Col11 | Col12


Val1 | val2 | VAL3 | val4 | VAL5 | VAL6 | VAL7 | VAL8 | VAL9 | VAL10 | VAL11 | val12

T2:

Col1 | Col2 | Col3 | Col4 | Col5 | Col6


Val1 | val2 | VAL3 | val4 | Col5 | Val5 VAL1 | val2 | VAL3 | val4 | Col6 | Val6 VAL1 | val2 | VAL3 | val4 | Col7 | Val7 VAL1 | val2 | VAL3 | val4 |科尔8 | Val8 VAL1 | val2 | VAL3 | val4 | Col9 | Val9 . . VAL1 | val2 | VAL3 | val4 | Col12 | val12

我想在单个动态查询中实现这一点。对格式表示歉意,如果有任何不清楚的地方。如果您需要任何东西,请告诉我。 谢谢, 桑杰

【问题讨论】:

一张表有 180 列?这是不对的。 嗨,Deve,实际上数据在一个文件中,我们必须处理并加载到表中。 【参考方案1】:

您可以使用联合来选择所有项目及其值。

select col1
,      col2
,      col3
,      col4
,      'col5' col_name
,      col5 col_value
from   t1
union
all
select col1
,      col2
,      col3
,      col4
,      'col6' col_name
,      col6 col_value
from   t1

...等等

另一个选项是流水线函数:

create type x_rec is object
( col1 varchar2(200)
, col2 varchar2(200)
, col3 varchar2(200)
, col4 varchar2(200)
, col5 varchar2(200)
, col6 varchar2(200)
);
;

create type x_tab is table of x_rec;

create or replace function x
return x_tab
pipelined
is
begin
  for r
  in
  ( select *
    from   y
  )
  loop
    pipe row (r.col1, r.col2, r.col3, r.col4, 'col5', r.col5);
    pipe row (r.col1, r.col2, r.col3, r.col4, 'col6', r.col6);
    -- etc
  end loop;
  --
  return;  
end;

select *
from   table(x)
;

【讨论】:

感谢帕特里克的回复。我目前正在这样做,但正如我所提到的,因为列数是 180+,这使它成为一个巨大的查询。因此,如果可能的话,我只想通过一些动态查询来实现这一点。我的意思是为每一列创建一个选择。【参考方案2】:

Patrick 使用 UNION ALL 的方法略有不同。

100 多个子查询的联合没有任何问题(尽管最终您可能会遇到一些 SQL Server 限制)。 毕竟,您不必手动编写查询;你可以生成它。 您可以使用元数据查询来执行此操作;这样,T1 的实际列名将自动出现在生成的查询中。 在 SSMS 中运行以下 SQL 查询,并选择“结果到文本”;结果是 Patrick 的原始查询。

SELECT CASE WHEN ROW_NUMBER() OVER(ORDER BY COLUMN_NAME) = 1 THEN
           'INSERT INTO T2 (Col1, Col2, Col3, Col4, NewCol1, NewCol2)'
       ELSE
           'UNION ALL'
       END +
       ' SELECT Col1, Col2, Col3, Col4, ''' + COLUMN_NAME + ''', ' + QUOTENAME(COLUMN_NAME) +
       ' FROM T1'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'T1'
AND COLUMN_NAME NOT IN (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'T2')
ORDER BY COLUMN_NAME

更进一步,您可以使用动态 SQL 将两个步骤(检索元数据和复制数据)组合在一个 SQL 语句中。 在下面的示例中,不仅“动态”列名 (Col5-Col180),而且“静态”列名 (Col1-Col4) 都从元数据中检索。 两个表中出现的任何列都被认为是“静态的”;出现在T1 但不在T2 中的列被视为“动态”。如果您需要排除某些列,请向元数据查询添加 WHERE 条件。

-- build up a string of 'static' column names
DECLARE @columnName sysname
DECLARE @columnNames nvarchar(999) = ''
DECLARE staticColumns CURSOR FOR
    SELECT c1.COLUMN_NAME
    FROM INFORMATION_SCHEMA.COLUMNS c1
    INNER JOIN INFORMATION_SCHEMA.COLUMNS c2 ON c2.COLUMN_NAME = c1.COLUMN_NAME
    WHERE c1.TABLE_NAME = 'T1' AND c2.TABLE_NAME = 'T2'
OPEN staticColumns
FETCH NEXT FROM staticColumns INTO @columnName
WHILE @@FETCH_STATUS = 0 BEGIN
    SET @columnNames = @columnNames + QUOTENAME(@columnName) + ', '
    FETCH NEXT FROM staticColumns INTO @columnName
END
CLOSE staticColumns
DEALLOCATE staticColumns

-- for each 'dynamic' column in T1, build and execute an INSERT...SELECT statement    
DECLARE @insertSelect nvarchar(999)
DECLARE dynamicColumns CURSOR FOR
    SELECT 'INSERT INTO T2 (' + @columnNames + 'NewCol1, NewCol2)' +
           ' SELECT ' + @columnNames + '''' + COLUMN_NAME + ''', ' + QUOTENAME(COLUMN_NAME) +
           ' FROM T1'
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'T1'
    AND COLUMN_NAME NOT IN (SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'T2')
    ORDER BY COLUMN_NAME
OPEN dynamicColumns
FETCH NEXT FROM dynamicColumns INTO @insertSelect
WHILE @@FETCH_STATUS = 0 BEGIN
    EXEC(@insertSelect)
    FETCH NEXT FROM dynamicColumns INTO @insertSelect
END
CLOSE dynamicColumns
DEALLOCATE dynamicColumns

【讨论】:

以上是关于从另一个查询插入记录的主要内容,如果未能解决你的问题,请参考以下文章

从另一个查询调用时,返回 SETOF 记录会丢失记录类型

Access 数据库需要从另一个表中获取最近日期的记录

如何插入多条记录并获取标识值?

MySQL:使用带有 WHERE 子句的 JOINS 从一个表中获取所有记录并从另一个表中获取可用记录

sql联接未从另一个表获取所有记录

Postgresql 插入触发器以设置值