转置并插入具有不同值的多行

Posted

技术标签:

【中文标题】转置并插入具有不同值的多行【英文标题】:Transpose and insert multiple rows with differing values 【发布时间】:2013-03-20 20:30:34 【问题描述】:

我有一个更复杂的下表:

ID | FIRST  | LAST     | EMAIL
1  | John   | Doe      | jdoe@example.com
1  | Mack   | Johnson  | mjohnson@example.com
1  | Steven | Michaels | smichaels@example.com
2  | Sarah  | Sampson  | ssampson@example.com
2  | Tom    | Smith    | tsmith@example.com
2  | Jane   | Rogers   | jrogers@example.com
3  | Bob    | Johns    | bjohns@example.com
3  | Kim    | Lane     | klane@example.com
3  | Ron    | Swanson  | rswanson@example.com

我想编写一个查询,将这些数据插入到另一个表中,看起来像这样(该表已经存在):

ID | first1 | last1    | email1               | first2 | last2    | email2               | first3 | last3    | email3 
1  | John   | Doe      | jdoe@example.com     | Mack   | Johnson  | mjohnson@example.com | Steven | Michaels | smichaels@example.com
2  | Sarah  | Sampson  | ssampson@example.com | Tom    | Smith    | tsmith@example.com   | Jane   | Rogers      | jrogers@example.com
3  | Bob    | Johns    | bjohns@example.com   | Kim    | Lane     | klane@example.com    | Ron    | Swanson     | rswanson@example.com

我觉得这应该很容易,但这个概念让我难以理解。实现此目的的最佳做法是什么?

也许我还应该提到我写了一个函数,我可以传递 ID、索引号和列名来返回一个值(即 getpersoninfo(2,'1','first') 来返回 Sarah )。

select a_id,
  FIRST1, LAST1, EMAIL1,
  FIRST2, LAST2, EMAIL2,
  FIRST3, LAST3, EMAIL3
from
(
  select a_id, col||rn as new_col, value
  from
  (
    select a_id, first_name, last_name, email,
      cast(row_number() over(partition by a_id order by a_id) as varchar2(10)) rn
    from dump_recs_2015
  ) 
  unpivot
  (
    value
    for col in (first_name, last_name, email)
  )
) 
pivot
(
  max(value)
  for new_col in ('FIRST1' FIRST1, 'LAST1' LAST1, 'EMAIL1' EMAIL1,
                  'FIRST2' FIRST2, 'LAST2' LAST2, 'EMAIL2' EMAIL2,
                  'FIRST3' FIRST3, 'LAST3' LAST3, 'EMAIL3' EMAIL3)
);

【问题讨论】:

什么版本的Oracle?每个ID 只会有 3 个条目吗? 11g。有些会有两个,但最多 3 个 【参考方案1】:

由于您使用的是 Oracle 11g,因此您可以同时实现 UNPIVOTPIVOT 函数。

UNPIVOT 会将您的列 firstlastemail 转换为行。然后你可以将PIVOT 新名称First1 等放入列中:

select id,
  First1, Last1, Email1,
  First2, Last2, Email2,
  First3, Last3, Email3
from
(
  select id, col||rn as new_col, value
  from
  (
    select id, first, last, email,
      cast(row_number() over(partition by id order by id) as varchar2(10)) rn
    from yourtable
  ) 
  unpivot
  (
    value
    for col in (first, last, email)
  )
) 
pivot
(
  max(value)
  for new_col in ('FIRST1' First1, 'LAST1' Last1, 'EMAIL1' Email1,
                  'FIRST2' First2, 'LAST2' Last2, 'EMAIL2' Email2,
                  'FIRST3' First3, 'LAST3' Last3, 'EMAIL3' Email3)
) 

见SQL Fiddle with Demo。然后可以在INSERT 语句中使用它来将数据加载到新表中。

编辑,根据您的列名更改,您将使用:

select a_id,
  First1, Last1, Email1,
  First2, Last2, Email2,
  First3, Last3, Email3
from
(
  select a_id, col||rn as new_col, value
  from
  (
    select a_id, first_name, last_name, email,
      cast(row_number() over(partition by a_id order by a_id) as varchar2(10)) rn
    from yourtable
  ) 
  unpivot
  (
    value
    for col in (first_name, last_name, email)
  )
) 
pivot
(
  max(value)
  for new_col in ('FIRST_NAME1' First1, 'LAST_NAME1' Last1, 'EMAIL1' Email1,
                  'FIRST_NAME2' First2, 'LAST_NAME2' Last2, 'EMAIL2' Email2,
                  'FIRST_NAME3' First3, 'LAST_NAME3' Last3, 'EMAIL3' Email3)
) 

见SQL Fiddle with Demo

【讨论】:

这太棒了。进行一些更改以与我的实际列名兼容,我的名字和姓氏将变为空。 我已经在上面添加了我的更改。 @sgd 查看我的编辑,您只需更改 UNPIVOTPIVOT 块中使用的列名。 嗯。这看起来和我所拥有的完全一样。除了一个完全工作。无论如何,谢谢你的提示。这东西效果很好,让我的一天有个愉快的结束。再次感谢。

以上是关于转置并插入具有不同值的多行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL - 在一个查询中更新具有不同值的多行

在具有不同值的多行上更新同一列

SQL 将多行转置到不同的列

将具有相同值的多行合并为pandas中的一行

我将如何同时插入具有所有不同子查询值的同一行,几乎就像通过子查询进行迭代一样?

如何在 LINQ sql 中将两个表与一个具有不同值的表连接起来?