问题描述
CLID PRODUCT
1 A
1 B
2 A
2 C
3 A
3 C
我需要解决的是在“ PRODUCT”字段上进行某种单一编码。 在Oracle中,我们至少可以通过以下方式做到这一点:
select * from(
select clid,product
from t1
pivot(
count(product)
for product
in('A','B','C')
)
)
然后我们得到结果:
CLID A B C
1 1 1 0
2 1 0 1
3 1 0 1
但是,当我们有大量产品(假设有1000个项目)时,就会发生此问题,在这种情况下,将所有产品置于IN状态会非常不便。
所以我的问题是是否有什么办法避免将所有可能的值都放入“ IN”? 如果没有这样的选择,那么也许有其他方法可以在Oracle sql(或pl / sql?)中进行一次热编码?
解决方法
无论表中有多少个不同的产品,都可以使用PL / SQL匿名块自动构建查询,但是您需要了解,在数据透视子句中不能放置超过1000个值,因为不能超过1000列。
我会做这样的事情(假设总是少于1000个值)
测试用例(创建表和测试值)
SQL> create table t ( CLID number,PRODUCT varchar2(10) ) ;
Table created.
SQL> insert into t ( clid,product )
2 with x ( a,b ) as
(
select 1,'A' from dual union all
select 1,'B' from dual union all
select 2,'A' from dual union all
select 2,'C' from dual union all
select 3,'A' from dual union all
select 3,'C' from dual union all
select 4,'D' from dual union all
select 4,'E' from dual union all
select 5,'B' from dual union all
select 5,'C' from dual union all
select 5,'D' from dual union all
select 5,'E' from dual
)
select a,b from x ;
12 rows created.
SQL> commit ;
Commit complete.
PLSQL构建
然后,无论有多少种不同的产品自动获取查询
set serveroutput on size unlimited lines 220 pages 0
declare
v_query clob;
out_string varchar2(100);
cursor c_ids
is
select distinct product,count(distinct(product)) over () tot_rows from t order by 1 asc;
procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob,chr(10),l_offset,1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line(dbms_lob.substr(p_clob,l_chars - l_offset,l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;
begin
dbms_output.enable(null);
for item in c_ids
loop
if item.tot_rows >= 1000
then
raise_application_error(-20001,'Maximum number of 1000 columns are not allowed',true);
end if;
out_string := item.product;
if c_ids%rowcount = 1
then
v_query := 'select * from (';
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' select * ');
dbms_lob.append(v_query,' from t ');
dbms_lob.append(v_query,' pivot( ');
dbms_lob.append(v_query,' count(product) ');
dbms_lob.append(v_query,' for product in ( '''||out_string||''',');
elsif c_ids%rowcount < item.tot_rows then
dbms_lob.append(v_query,' '''||out_string||''',');
else
dbms_lob.append(v_query,' '''||out_string||''' ) ');
end if;
end loop;
dbms_lob.append(v_query,''||chr(10)||'');
dbms_lob.append(v_query,' ) )');
print_clob_to_output(v_query);
end;
/
执行
SQL> @query.sql
SQL> set serveroutput on size unlimited lines 220 pages 0
SQL> declare
2 v_query clob;
3 out_string varchar2(100);
4 cursor c_ids
5 is
6 select distinct product,count(distinct(product)) over () tot_rows from t order by 1 asc;
7 procedure print_clob_to_output (p_clob in clob)
8 is
9 l_offset pls_integer := 1;
10 l_chars pls_integer;
11 begin
12 loop
13 exit when l_offset > dbms_lob.getlength(p_clob);
14 l_chars := dbms_lob.instr(p_clob,1);
15 if l_chars is null or l_chars = 0 then
16 l_chars := dbms_lob.getlength(p_clob) + 1;
17 end if;
18 dbms_output.put_line(dbms_lob.substr(p_clob,l_offset));
19 l_offset := l_chars + 1;
20 end loop;
21 end print_clob_to_output;
22 begin
23 dbms_output.enable(null);
24 for item in c_ids
25 loop
26 if item.tot_rows >= 1000
27 then
28 raise_application_error(-20001,true);
29 end if;
30 out_string := item.product;
31 if c_ids%rowcount = 1
32 then
33 v_query := 'select * from (';
34 dbms_lob.append(v_query,''||chr(10)||'');
35 dbms_lob.append(v_query,' select * ');
36 dbms_lob.append(v_query,''||chr(10)||'');
37 dbms_lob.append(v_query,' from t ');
38 dbms_lob.append(v_query,''||chr(10)||'');
39 dbms_lob.append(v_query,' pivot( ');
40 dbms_lob.append(v_query,''||chr(10)||'');
41 dbms_lob.append(v_query,' count(product) ');
42 dbms_lob.append(v_query,''||chr(10)||'');
43 dbms_lob.append(v_query,');
44 elsif c_ids%rowcount < item.tot_rows then
45 dbms_lob.append(v_query,''||chr(10)||'');
46 dbms_lob.append(v_query,');
47 else
48 dbms_lob.append(v_query,''||chr(10)||'');
49 dbms_lob.append(v_query,' '''||out_string||''' ) ');
50 end if;
51 end loop;
52 dbms_lob.append(v_query,''||chr(10)||'');
53 dbms_lob.append(v_query,' ) )');
54 print_clob_to_output(v_query);
55 end;
56 /
select * from (
select *
from t
pivot(
count(product)
for product in ( 'A','B','C','D','E' )
) )
PL/SQL procedure successfully completed.
SQL> select * from (
select *
from t
pivot(
count(product)
for product in ( 'A','E' )
) ) ;
CLID 'A' 'B' 'C' 'D' 'E'
---------- ---------- ---------- ---------- ---------- ----------
1 1 1 0 0 0
2 1 0 1 0 0
4 0 0 0 1 1
5 0 1 1 1 1
3 1 0 1 0 0