Sql 将所有列转换为行

Sql 将所有列转换为行,sql,oracle,Sql,Oracle,我的问题是: select * from some_table where id = 4045432 返回包含60多列的单行。我不应该依赖列名(因为列名经常更改,我必须“按原样”获取所有数据,而不必每次更新sql查询) 我想要的是将所有列更改为行,如: COLUMN|VALUE ============= C1|V1 C2|V2 我怎样才能做到这一点 提前谢谢你 您可能需要使用一些动态SQL来实现您的目标 您可以使用Oracle的UNPIVOT关键字将包含许多列的短胖表转换为包含列/值对

我的问题是:

select * from some_table where id = 4045432
返回包含60多列的单行。我不应该依赖列名(因为列名经常更改,我必须“按原样”获取所有数据,而不必每次更新sql查询)

我想要的是将所有列更改为行,如:

COLUMN|VALUE 
=============
C1|V1
C2|V2 
我怎样才能做到这一点


提前谢谢你

您可能需要使用一些动态SQL来实现您的目标

您可以使用Oracle的
UNPIVOT
关键字将包含许多列的短胖表转换为包含
/
对的高瘦结果集

以下是一个基于古老的
EMP
表的示例:

select empno, col, val from 
(
  -- This query needs to convert all columns to a common datatype
  select empno, ename, job, to_char(sal) sal, to_char(comm) comm, to_char(hiredate, 'YYYY-MM-DD') hiredate, to_char(deptno) deptno
    from emp
)
unpivot
(
  val for col
  in(
    ename,
    job,
    sal,
    comm,
    hiredate,
    deptno
   )
)
这就产生了你想要的东西:

EMPNO COL      VAL
----- -------- ----------
7839  ENAME    KING
7839  JOB      PRESIDENT
7839  SAL      5000
7839  HIREDATE 1981-11-17
7839  DEPTNO   10
...
为了使数据有意义,您可能需要将表的主键包含为一列(如
EMPNO

请注意,必须转换数据类型。如果您试图同时取消日期、数字和文本,则
UNPIVOT
机制将不起作用。 因此,您的PL/SQL可能需要在查询
DBA\u TAB\u COLS
USER\u TAB\u COLS
并通过适当的转换建立查询时做一些工作


对于60多个列来说,这可能会很乏味,但对于其他宽表来说,这将是一次性的工作。

最简单的方法是使用动态sql,而不用在select语句中编写所有列名。 对基础查询(Tablename/Filter)的任何更改都不需要在select语句中添加相关的列名,因为这将由动态sql负责

创建表:

create table match_results (
  match_date       date,
  location         varchar2(20),
  home_team_name   varchar2(20),
  away_team_name   varchar2(20),
  home_team_points integer,
  away_team_points integer
);
插入一行:

insert into match_results values ( date'2018-01-01', 'Snowley', 'Underrated United', 'Terrible Town', 2, 0 );
用于将行转换为列的Pl/sql块:

declare 

plsql_block VARCHAR2(500);
lv_col_value VARCHAR2(500);

begin 


dbms_output.put_line('ColumnName|Value');

for v1 in (select column_name 
            from user_tab_columns where table_name ='MATCH_RESULTS'
           order by column_id)
 loop
    
    --Add filter as desired but restrict result set to one row
    plsql_block := 'select ' || v1.column_name  || ' from MATCH_RESULTS Where LOCATION = ''Snowley'' and rownum < 2';

    execute immediate plsql_block into lv_col_value;
    dbms_output.put_line(v1.column_name||'| '||lv_col_value);

 end loop;

end;
/
参考DBfiddle演示@

1 rows affected

dbms_output:
ColumnName|Value
MATCH_DATE| 01-JAN-18
LOCATION| Snowley
HOME_TEAM_NAME| Underrated United
AWAY_TEAM_NAME| Terrible Town
HOME_TEAM_POINTS| 2
AWAY_TEAM_POINTS| 0