将 SQL 查询转换为 PL/SQL
Convert SQL Query to PL/SQL
我在这里做错了什么?我希望此 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:枢轴|非枢轴值不允许非常量表达式
ORA-06512: 在第 4 行
56901.0000 - "non-constant expression is not allowed for pivot|unpivot values"
*原因:试图对枢轴|非枢轴值使用非常量表达式。
*行动:对枢轴|反枢轴值使用常量。
眼前的问题是您将 i
称为动态语句中的变量,它不在范围内:
pivot (max(c) for rn in (i as col'||i||' ))';
^
您需要将其连接起来供以后参考:
pivot (max(c) for rn in ('||i||' as col'||i||' ))';
现在可以编译了,但是正如@jva 提到的那样,您没有select进入任何东西,所以结果没有任何变化(事实上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))
但它仍然不会实际执行任何操作。您需要 select 到某个东西(一个集合),或者使用生成的查询打开一个游标并迭代结果,或者 return 一个 ref 游标,等等。不清楚你想要发生什么。
例如,您可以这样做。首先创建空 table 与您的 table.
具有相同的列
create table sorted as select * from first_table where 1=0;
现在你可以运行这个代码块(你可以把它放在过程或其他东西中)。
它用您想要的顺序填充 table 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;
这里是不使用其他的块table,收集排序的数据
在变量 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;
我在这里做错了什么?我希望此 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:枢轴|非枢轴值不允许非常量表达式 ORA-06512: 在第 4 行 56901.0000 - "non-constant expression is not allowed for pivot|unpivot values" *原因:试图对枢轴|非枢轴值使用非常量表达式。 *行动:对枢轴|反枢轴值使用常量。
眼前的问题是您将 i
称为动态语句中的变量,它不在范围内:
pivot (max(c) for rn in (i as col'||i||' ))';
^
您需要将其连接起来供以后参考:
pivot (max(c) for rn in ('||i||' as col'||i||' ))';
现在可以编译了,但是正如@jva 提到的那样,您没有select进入任何东西,所以结果没有任何变化(事实上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))
但它仍然不会实际执行任何操作。您需要 select 到某个东西(一个集合),或者使用生成的查询打开一个游标并迭代结果,或者 return 一个 ref 游标,等等。不清楚你想要发生什么。
例如,您可以这样做。首先创建空 table 与您的 table.
具有相同的列create table sorted as select * from first_table where 1=0;
现在你可以运行这个代码块(你可以把它放在过程或其他东西中)。
它用您想要的顺序填充 table 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;
这里是不使用其他的块table,收集排序的数据 在变量 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;