将SQL查询转换为PL / SQL

时间:2015-04-17 08:40:51

标签: database oracle plsql

我在这里做错了什么?我希望此SQL查询在过程FOR i列中执行。我连串错了吗?谢谢!

BEGIN
FOR i IN 1..NR_COLUMNS
LOOP
EXECUTE IMMEDIATE 'select * from (
    select id, c, row_number() over (partition by id 
        order by id, decode(mod(id, 2), 1, c, -c)) rn
      from FIRST_TABLE unpivot (c for col in (col'||i||' )))
  pivot (max(c) for rn in (i as col'||i||' ))';
END LOOP;

错误:ORA-56901:pivot | unpivot值不允许使用非常量表达式 ORA-06512:第4行 56901. 0000 - “pivot | unpivot值不允许使用非常量表达式” *原因:尝试对pivot | unpivot值使用非常量表达式。 *动作:使用常量来旋转|取消忽略值。

2 个答案:

答案 0 :(得分:1)

当前的问题是,您将i称为动态语句中的变量,而不在范围内:

  pivot (max(c) for rn in (i as col'||i||' ))';
                           ^

您需要将其连接到后面的参考:

  pivot (max(c) for rn in ('||i||' as col'||i||' ))';

现在将编译,但正如@jva所提到的,你没有选择任何东西,所以结果没有任何反应(事实上the query isn't actually executed)。但是你想要对它们做些什么并不明显。

看起来你正在尝试构建pivot / unpivot子句,而不是你实际在做什么,它试图在多个不相关的时间运行查询。我认为这可能更接近你想要实现的目标:

DECLARE
  NR_COLUMNS NUMBER := 2;
  QUERY VARCHAR2(1000);
BEGIN
  QUERY := 'select * from (
    select id, c, row_number() over (partition by id 
        order by id, decode(mod(id, 2), 1, c, -c)) rn
      from FIRST_TABLE unpivot (c for col in (';

  FOR i IN 1..NR_COLUMNS
  LOOP
    IF i > 1 THEN
      QUERY := QUERY || ', ';
    END IF;
    QUERY := QUERY || 'col' ||i;
  END LOOP;

  QUERY := QUERY || ')))
    pivot (max(c) for rn in (';

  FOR i IN 1..NR_COLUMNS
  LOOP
    IF i > 1 THEN
      QUERY := QUERY || ', ';
    END IF;
    QUERY := QUERY || i ||' as col' ||i;
  END LOOP;
  QUERY := QUERY || '))';

  -- just to debug what you're trying to run
  DBMS_OUTPUT.PUT_LINE(QUERY);
  EXECUTE IMMEDIATE QUERY;
END;
/

DBMS_OUTPUT显示生成的查询,如:

select * from (
    select id, c, row_number() over (partition by id 
        order by id, decode(mod(id, 2), 1, c, -c)) rn
      from FIRST_TABLE unpivot (c for col in (col1, col2)))
    pivot (max(c) for rn in (1 as col1, 2 as col2))

但它仍然无法做任何事情。您需要选择某个(集合),或使用生成的查询打开游标并迭代结果,或返回引用光标或其他内容。目前还不清楚你想要发生什么。

答案 1 :(得分:1)

你可以这样做。首先创建与表相同列的空表。

create table sorted as select * from first_table where 1=0;

现在您可以运行此代码块(您可以将其放入过程或其他内容中)。 它会根据您想要的值填充表sorted

declare
  v_list1 varchar2(32000); v_list2 varchar2(32000);
  v_sql varchar2(32000); v_num number; v_rec first_table%rowtype; 
begin

  select count(1) into v_num from user_tab_cols 
    where table_name = 'FIRST_TABLE';

  for i in 1..v_num-1 loop
    v_list1 := v_list1||'col'||i||', ';
    v_list2 := v_list2||i||', ';
  end loop;

  v_sql := 'select * from (
      select id, c, row_number() over (partition by id 
          order by id, decode(mod(id, 2), 1, c, -c)) rn
        from first_table unpivot (c for col in ('||rtrim(v_list1, ', ')||')))
    pivot (max(c) for rn in ('||rtrim(v_list2, ', ')||'))';

  for r in (select * from first_table) loop
    execute immediate v_sql||' where id = '||r.id into v_rec;
    insert into sorted values v_rec;
  end loop;
end;

这里是不使用其他表的块,收集了分类数据 在变量v_coll中,然后从first_table中删除旧数据并插入新数据。

declare
  v_list varchar2(32000); v_sql varchar2(32000); v_num number;  
  type tft is table of first_table%rowtype;
  v_coll tft; -- variable for sorted data collection
begin

  select count(1) into v_num from user_tab_cols where table_name = 'FIRST_TABLE';

  for i in 1..v_num-1 loop
    v_sql := v_sql||'col'||i||', ';
    v_list := v_list||i||', ';
  end loop;

  v_sql := 'select * from (
      select id, c, row_number() over (partition by id 
          order by id, decode(mod(id, 2), 1, c, -c)) rn
        from first_table unpivot (c for col in ('||rtrim(v_sql, ', ')||')))
    pivot (max(c) for rn in ('||rtrim(v_list, ', ')||'))';

  -- execute statement and collect sorted data in v_coll
  execute immediate v_sql bulk collect into v_coll;

  delete from first_table;
  forall i in 1..v_coll.count 
    insert into first_table values v_coll(i);

end;