【问题标题】:Display columns from multiple rows in single row oracle在单行 oracle 中显示多行中的列
【发布时间】:2014-09-11 16:15:16
【问题描述】:

我的数据是从我的 sql 中返回的

node_no  code  value1  order
100       AB     001     1
100       AB     007     2
101       AB     010     3

我必须使用 sql 进一步处理这些数据,以获得类似的输出

node_no   code  value1  value2
100        AB     001     007
101        AB     010     null

要求将两行(或具有相同 node_no 的行)中的列值显示为单行作为两个不同的列。 必须维持秩序。

注意:这可能看起来像重复 SQL Query to concatenate column values from multiple rows in Oracle SQL Query to concatenate column values from multiple rows in Oracle

但我们将值显示为单个聚合列。

【问题讨论】:

  • 您需要更清楚地定义所需的业务逻辑。例如,您如何确定001 进入哪一列?是因为它小于007 还是因为它的order 值最低?如果一个节点有两个以上的值,会发生什么?等等等等等等……
  • 它基于 `order' 字段,按顺序排列。节点的值不会超过两个,后续问题只有 1 个或最多 2 个 Thx。

标签: sql oracle


【解决方案1】:

试试这个:

with cte as 
(select node_no, code, value1,
row_number() over (partition by node_no order by order) rn
from tbl)

select a.node_no, a.code, a.value1 x, b.value1 value2 
from
cte a
left join cte b on a.node_no = b.node_no
and b.rn = 2
and a.rn = 1
where a.rn = 1

SQLFiddle

请注意,这假定您的 value1 字段是 varchar2,因此如果您想要执行一些自定义排序而不是标准字典排序,您需要在 order by 子句中自己实现它。

@MatBailie 在 cmets 中建议的另一个解决方案消除了对连接的需要(仍然需要 CTE):

SELECT node_no, 
MAX(code) as code, 
MAX(CASE WHEN rn=1 THEN value1 END) AS value1, 
MAX(CASE WHEN rn=2 THEN value1 END) AS value2 
FROM cte 
GROUP BY node_no

【讨论】:

  • 您不需要使用连接... SELECT node_no, MAX(code) as code, MAX(CASE WHEN rn=1 THEN value1 END) AS value1, MAX(CASE WHEN rn=2 THEN value2 END) AS value2 FROM cte GROUP BY node_no 这将减少读取次数和 CPU 周期数,因为不需要处理两次数据。 (另外,通过在 WHERE 子句中添加 b.rn=2,您已经破坏了 LEFT JOIN 并将其转换为 INNER JOIN;因为如果它不存在于连接中,则该值将是 NULL,它永远不会等于2.)
  • @MatBailie 你说得对,WHERE 确实改变了意思。我应该根据您的建议编辑我的答案,还是会像窃取您的信用一样?
  • @MatBailie 我的理解是,由于 node_no 可以有 2 行,如果输入中存在rn = 1 的行,则它必须始终存在于结果中。因此,连接指定了a.rn = 1 and b.rn = 2,另外一个where 仅从每个node_no 中获取第一行。这有意义吗?
  • 如果您PARTITION BY 列,ORDER BY 子句不必包含该列。
  • 总是随意从那些没有自己写答案的人那里“窃取信用”:)
【解决方案2】:

Oracle 的最新版本也支持PIVOT 子句。不过,您仍然必须获得一个常量列标识符:

SELECT node_no, code, value1, 
         ROW_NUMBER() OVER(PARTITION BY node_no ORDER BY ordering) rn
 FROM <table_name_here>) 

(我将order改名为ordering,因为前者是保留字,需要转义/尽可能避免)
...就像@Shree 的回答一样,将根据节点对所有行进行编号。这意味着我们每个部分都有一个常量值:

node_no   code   value1  order  rn
100       AB     001     1      1
100       AB     007     2      2
101       AB     010     3      1

此时,变成标准的PIVOT查询:

SELECT node_no, code, value1, value2
FROM (SELECT node_no, code, value1, 
             ROW_NUMBER() OVER(PARTITION BY node_no ORDER BY ordering) rn
      FROM Pivot_Example) Indexed
PIVOT (MAX(value1) FOR (rn) IN (1 AS value1, 2 AS value2))
ORDER BY node_no

PIVOT 需要一个聚合函数,但在这种情况下我们没有要聚合的东西,所以...)

SQL Fiddle Example

不过,我不确定这是否会比现有答案更有效。

【讨论】:

  • 哇,所以 Oracle PIVOT 语法与 SQL Server 几乎相同。应该立即尝试:D
猜你喜欢
  • 2014-06-07
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-20
相关资源
最近更新 更多