Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
oraclesql中的动态透视_Sql_Oracle_Pivot_Dynamic Pivot - Fatal编程技术网

oraclesql中的动态透视

oraclesql中的动态透视,sql,oracle,pivot,dynamic-pivot,Sql,Oracle,Pivot,Dynamic Pivot,。。。枢轴(X中B的总和(A)) 现在B是数据类型varchar2,X是由逗号分隔的varchar2值字符串。 X的值是从同一表的列(如CL)中选择不同的值。这样,pivot查询就开始工作了 但问题是,每当CL列中有新值时,我都必须手动将其添加到字符串X中 我尝试用CL中的select distinct值替换X。但查询未运行。 我之所以这样认为,是因为替换X时,我们需要用逗号分隔值。 然后我创建了一个函数来返回与字符串X匹配的精确输出。但查询仍然没有运行。 显示的错误消息如“缺少righr Pa

。。。枢轴(X中B的总和(A))

现在B是数据类型varchar2,X是由逗号分隔的varchar2值字符串。
X的值是从同一表的列(如CL)中选择不同的值。这样,pivot查询就开始工作了

但问题是,每当CL列中有新值时,我都必须手动将其添加到字符串X中

我尝试用CL中的select distinct值替换X。但查询未运行。
我之所以这样认为,是因为替换X时,我们需要用逗号分隔值。
然后我创建了一个函数来返回与字符串X匹配的精确输出。但查询仍然没有运行。
显示的错误消息如“缺少righr Paranthes”、“文件通信通道结束”等
我尝试了pivot xml,而不是pivot,查询运行,但给出了oraxxx等根本没有值的Vlaue

也许我没有正确地使用它。

你能告诉我一些用动态值创建透视图的方法吗?

你不能在透视图子句的
中的
中放入非常量字符串。
您可以使用PivotXML来实现这一点

发件人:

子查询子查询仅与XML关键字结合使用。 指定子查询时,将使用该子查询找到的所有值 旋转用

应该是这样的:

select xmlserialize(content t.B_XML) from t_aa
pivot xml(
sum(A) for B in(any)
) t;
SELECT 
  *
FROM   
  table( 
        pivot('
                SELECT DISTINCT
                    P.proj_id,
                    REPLACE(substr(T.UDF_TYPE_LABEL, 1, 30), '''''''','','') as Attribute,
                    CASE
                      WHEN V.udf_text is null     and V.udf_date is null and      V.udf_number is NOT null  THEN to_char(V.udf_number)
                      WHEN V.udf_text is null     and V.udf_date is NOT null and  V.udf_number is null      THEN to_char(V.udf_date)
                      WHEN V.udf_text is NOT null and V.udf_date is null and      V.udf_number is null      THEN V.udf_text
                      ELSE NULL END
                    AS VALUE
                FROM
                    project   P
                LEFT JOIN UDFVALUE V ON P.proj_id     = V.proj_id 
                LEFT JOIN UDFTYPE  T ON V.UDF_TYPE_ID = T.UDF_TYPE_ID
                WHERE 
                    P.delete_session_id  IS NULL AND
                    T.TABLE_NAME = ''PROJECT''
    ')
)
您还可以使用子查询代替
ANY
关键字:

select xmlserialize(content t.B_XML) from t_aa
pivot xml(
sum(A) for B in (select cl from t_bb)
) t;

如果不使用PIVOT XML,则无法将动态语句放入PIVOT的in语句中,因为PIVOT XML会输出一些不理想的输出。但是,您可以创建IN字符串并将其输入到语句中

首先,这是我的样品表

  myNumber    myValue myLetter
---------- ---------- --------
         1          2 A        
         1          4 B        
         2          6 C        
         2          8 A        
         2         10 B        
         3         12 C        
         3         14 A      
首先设置要在in语句中使用的字符串。在这里,您将字符串放入“str_in_statement”。我们正在使用和来设置字符串

clear columns
COLUMN temp_in_statement new_value str_in_statement
SELECT DISTINCT 
    LISTAGG('''' || myLetter || ''' AS ' || myLetter,',')
        WITHIN GROUP (ORDER BY myLetter) AS temp_in_statement 
    FROM (SELECT DISTINCT myLetter FROM myTable);
您的字符串将如下所示:

'A' AS A,'B' AS B,'C' AS C
现在在PIVOT查询中使用String语句

SELECT * FROM 
    (SELECT myNumber, myLetter, myValue FROM myTable)
    PIVOT (Sum(myValue) AS val FOR myLetter IN (&str_in_statement));
以下是输出:

  MYNUMBER      A_VAL      B_VAL      C_VAL
---------- ---------- ---------- ----------
         1          2          4            
         2          8         10          6 
         3         14                    12 

但也有一些限制。最多只能连接4000字节的字符串

对于以后的读者,这里是另一个解决方案

允许像这样的查询

select * from table( pivot(  'select deptno,  job, count(*) c from scott.emp group by deptno,job' ) )
我使用了上面的方法(Anton PL/SQL自定义函数pivot()),它完成了这项工作!由于我不是一名专业的Oracle开发人员,我已经完成了以下简单步骤:

1) 下载zip包以在其中找到pivotFun.sql。 2) 运行pivotFun.sql一次以创建新函数 3) 在普通SQL中使用该函数

只需小心使用动态列名称。在我的环境中,我发现列名限制为30个字符,不能包含一个引号。所以,我的问题是这样的:

select xmlserialize(content t.B_XML) from t_aa
pivot xml(
sum(A) for B in(any)
) t;
SELECT 
  *
FROM   
  table( 
        pivot('
                SELECT DISTINCT
                    P.proj_id,
                    REPLACE(substr(T.UDF_TYPE_LABEL, 1, 30), '''''''','','') as Attribute,
                    CASE
                      WHEN V.udf_text is null     and V.udf_date is null and      V.udf_number is NOT null  THEN to_char(V.udf_number)
                      WHEN V.udf_text is null     and V.udf_date is NOT null and  V.udf_number is null      THEN to_char(V.udf_date)
                      WHEN V.udf_text is NOT null and V.udf_date is null and      V.udf_number is null      THEN V.udf_text
                      ELSE NULL END
                    AS VALUE
                FROM
                    project   P
                LEFT JOIN UDFVALUE V ON P.proj_id     = V.proj_id 
                LEFT JOIN UDFTYPE  T ON V.UDF_TYPE_ID = T.UDF_TYPE_ID
                WHERE 
                    P.delete_session_id  IS NULL AND
                    T.TABLE_NAME = ''PROJECT''
    ')
)

可以很好地处理多达100万条记录

对于OP提出的问题,我不打算给出确切的答案,相反,我将只描述如何实现动态轴心

这里我们必须使用动态sql,首先将列值检索到变量中,然后在动态sql中传递变量

示例

我们有一张如下的桌子

如果我们需要将
YR
列中的值显示为列名,以及
QTY
中这些列中的值,那么我们可以使用以下代码

declare
  sqlqry clob;
  cols clob;
begin
  select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
  into   cols
  from   (select distinct YR from EMPLOYEE);


  sqlqry :=
  '      
  select * from
  (
      select *
      from EMPLOYEE
  )
  pivot
  (
    MIN(QTY) for YR in (' || cols  || ')
  )';

  execute immediate sqlqry;
end;
/
结果

如果需要,还可以创建临时表,并在该临时表中执行select查询以查看结果。很简单,只需在上面的代码中添加
创建表TABLENAME作为

sqlqry :=
'    
  CREATE TABLE TABLENAME AS
  select * from

使用动态查询

测试代码如下



如果不使用PIVOT-XML,就不能将动态语句放入PIVOT的in语句中,但是可以使用小技巧在PIVOT中使用动态语句。在PL/SQL中,在字符串值中,两个撇号等于一个撇号

declare
  sqlqry clob;   
  search_ids  varchar(256) := '''2016'',''2017'',''2018'',''2019''';
begin
  search_ids := concat( search_ids,'''2020''' ); -- you can append new search id dynamically as you wanted
  sqlqry :=
  '      
  select * from
  (
      select *
      from EMPLOYEE
  )
  pivot
  (
    MIN(QTY) for YR in (' || search_ids   || ')
  )';

  execute immediate sqlqry;
end;

Oracle的SQL中没有直接的动态数据透视方法,除非它返回XML类型的结果。 对于非XML结果,可以通过创建
SYS\u REFCURSOR
返回类型的函数来使用PL/SQL

  • 使用条件聚合

    CREATE OR REPLACE FUNCTION Get_Jobs_ByYear RETURN SYS_REFCURSOR IS
      v_recordset SYS_REFCURSOR;
      v_sql       VARCHAR2(32767);
      v_cols      VARCHAR2(32767); 
    BEGIN
      SELECT LISTAGG( 'SUM(  CASE  WHEN job_title =  '''||job_title||'''  THEN  1  ELSE  0  END )  AS  "'||job_title||'"' , ',' )
                     WITHIN GROUP ( ORDER BY job_title )
        INTO v_cols
        FROM ( SELECT DISTINCT job_title
                 FROM jobs j );
    
      v_sql :=
      'SELECT "HIRE YEAR",'|| v_cols ||
      '  FROM
         (
          SELECT TO_NUMBER(TO_CHAR(hire_date,''YYYY'')) AS "HIRE YEAR", job_title
            FROM employees e
            JOIN jobs j
              ON j.job_id = e.job_id
         )
        GROUP BY "HIRE YEAR"
        ORDER BY "HIRE YEAR"';
    
      OPEN v_recordset FOR v_sql;
      DBMS_OUTPUT.PUT_LINE(v_sql);
      RETURN v_recordset;
    END;
    /
    
  • 枢轴子句

    CREATE OR REPLACE FUNCTION Get_Jobs_ByYear RETURN SYS_REFCURSOR IS
      v_recordset SYS_REFCURSOR;
      v_sql       VARCHAR2(32767);
      v_cols      VARCHAR2(32767);
    BEGIN
      SELECT LISTAGG( ''''||job_title||''' AS "'||job_title||'"' , ',' )
                     WITHIN GROUP ( ORDER BY job_title )
        INTO v_cols
        FROM ( SELECT DISTINCT job_title
                 FROM jobs j  );
    
      v_sql :=
      'SELECT *
         FROM
         (
          SELECT TO_NUMBER(TO_CHAR(hire_date,''YYYY'')) AS "HIRE YEAR", job_title
            FROM employees e
            JOIN jobs j
              ON j.job_id = e.job_id  
         )
        PIVOT
        (
         COUNT(*) FOR job_title IN ( '|| v_cols ||' )
        )
        ORDER BY "HIRE YEAR"';
    
      OPEN v_recordset FOR v_sql;
      DBMS_OUTPUT.PUT_LINE(v_sql);
      RETURN v_recordset;
    END;
    /
    
但是编码为ORA-01489的
listag()
有一个缺点:
只要第一个参数中的连接字符串超过4000个字符的长度,字符串连接的结果就会太长。在这种情况下,返回
v_cols
变量值的查询可能会替换为嵌套在
XMLAGG()
中的
xmlement()
函数,例如

CREATE OR REPLACE FUNCTION Get_Jobs_ByYear RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_cols      VARCHAR2(32767); 
BEGIN
  SELECT RTRIM(DBMS_XMLGEN.CONVERT(
         XMLAGG(
                XMLELEMENT(e, 'SUM(  CASE  WHEN job_title =  '''||job_title||
                            '''  THEN  1  ELSE  0  END )  AS  "'||job_title||'",')
               ).EXTRACT('//text()').GETCLOBVAL() ,1),',') AS "v_cols"
    FROM ( SELECT DISTINCT job_title
               FROM jobs j);
           
  v_sql :=
  'SELECT "HIRE YEAR",'|| v_cols ||
  '  FROM
     (
      SELECT TO_NUMBER(TO_CHAR(hire_date,''YYYY'')) AS "HIRE YEAR", job_title
        FROM employees e
        JOIN jobs j
          ON j.job_id = e.job_id
     )
    GROUP BY "HIRE YEAR"
    ORDER BY "HIRE YEAR"';
  DBMS_OUTPUT.put_line(LENGTH(v_sql));
  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/
除非超过VARCHAR2类型的上限32767。最后一种方法也可能适用于Oracle 11g Release 2之前版本为的数据库,因为它们不包含
listag()
函数

顺便说一句,在签出
v_cols
期间,可以使用
LISTAGG()
函数,即使对于生成的非常长的连接字符串,也不会出现ORA-01489错误,而如果数据库的版本为12.2+,则通过使用ON OVERFLOW TRUNCATE子句截断字符串的尾部,如

从SQL开发人员的命令行

从PL/SQL开发人员的测试窗口获取结果 设定


您可以使用开源程序在单个SQL语句中动态透视数据

安装包后,调用函数并以字符串形式传入SQL语句。SQL语句的最后一列定义值,倒数第二列定义列名。默认聚合函数是MAX,它适用于以下常见的实体属性值查询:

select * from table(method4.pivot(
    q'[
        select 'A' name, 1 value from dual union all
        select 'B' name, 2 value from dual union all
        select 'C' name, 3 value from dual
    ]'
));

A   B   C
-   -   -
1   2   3
该程序还通过参数p_AGGREGATE_函数支持不同的聚合函数,如果添加名为PIVOT_column_ID的列,则允许自定义列名顺序

包裹
BEGIN
  :result := Get_Jobs_ByYear;
END;
select * from table(method4.pivot(
    q'[
        select 'A' name, 1 value from dual union all
        select 'B' name, 2 value from dual union all
        select 'C' name, 3 value from dual
    ]'
));

A   B   C
-   -   -
1   2   3