Sql ORACLE one热编码:对所有可用列使用PIVOT运算符

Sql ORACLE one热编码:对所有可用列使用PIVOT运算符,sql,oracle,pivot,one-hot-encoding,Sql,Oracle,Pivot,One Hot Encoding,假设我有一个名为t1的表: CLID PRODUCT 1 A 1 B 2 A 2 C 3 A 3 C 我需要达到的是“产品”领域的某种热门编码。 在Oracle中,我们至少可以这样做: select * from( select clid, product from t1 pivot( count(product) for product in('A', 'B', 'C')

假设我有一个名为t1的表:

CLID PRODUCT
1    A
1    B
2    A
2    C
3    A
3    C
我需要达到的是“产品”领域的某种热门编码。 在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”中?
如果没有这样的选项,那么也许有其他方法可以在Oracle sql(或pl/sql?)中执行一个热编码?

您可以使用pl/sql匿名块自动构建查询,而不管您的表中有多少不同的产品,但您需要了解,在一个pivot子句中不能放入超过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构造

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.
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, chr(10), l_offset, 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_chars - l_offset, 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,'Maximum number of 1000 columns are not allowed',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,' for product in ( '''||out_string||''' , ');
 44                          elsif c_ids%rowcount < item.tot_rows then
 45                  dbms_lob.append(v_query,''||chr(10)||'');
 46                  dbms_lob.append(v_query,' '''||out_string||''' ,');
 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' ,
'B' ,
'C' ,
'D' ,
'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
然后,无论有多少种不同的产品,都可以自动获取查询

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,''||chr(10)||'');
            dbms_lob.append(v_query,' from t '); 
            dbms_lob.append(v_query,''||chr(10)||'');
            dbms_lob.append(v_query,' pivot( '); 
            dbms_lob.append(v_query,''||chr(10)||'');
            dbms_lob.append(v_query,' count(product) '); 
            dbms_lob.append(v_query,''||chr(10)||'');
            dbms_lob.append(v_query,' for product in ( '''||out_string||''' , ');
        elsif c_ids%rowcount < item.tot_rows then
            dbms_lob.append(v_query,''||chr(10)||'');
            dbms_lob.append(v_query,' '''||out_string||''' ,');
        else 
            dbms_lob.append(v_query,''||chr(10)||'');
            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;
/
在大小不限的行上设置serveroutput 220页0
声明
v_查询clob;
输出字符串varchar2(100);
游标c_id
是
选择不同的产品,按1 asc从t订单中总计()行计数(不同的(产品));
程序打印到输出(clob中的p\U clob)
是
l_偏移量pls_整数:=1;
l_字符pls_整数;
开始
环
当l_offset>dbms_lob.getlength(p_clob)时退出;
l_字符:=dbms_lob.instr(p_clob,chr(10),l_偏移量,1);
如果l_chars为null或l_chars=0,则
l_chars:=dbms_lob.getlength(p_clob)+1;
如果结束;
dbms_output.put_line(dbms_lob.substr(p_clob,l_chars-l_offset,l_offset));
l_偏移量:=l_字符+1;
端环;
结束打印输出;
开始
dbms_output.enable(null);
对于c_ID中的项目
环
如果item.tot_行>=1000
然后
raise_应用程序_错误(-20001,“不允许最大1000列数”,true);
如果结束;
out_字符串:=item.product;
如果c_id%rowcount=1
然后
v_query:=“选择*自(”;
dbms|u lob.append(v|u query,| | chr(10)| |');
dbms_lob.append(v_查询'select*');
dbms|u lob.append(v|u query,| | chr(10)| |');
dbms_lob.append(v_query,'from t');
dbms|u lob.append(v|u query,| | chr(10)| |');
附加(v_查询,'pivot(');
dbms|u lob.append(v|u query,| | chr(10)| |');
dbms_lob.append(v_查询,'count(product)');
dbms|u lob.append(v|u query,| | chr(10)| |');
dbms|u lob.append(v|u query,'for product in(''''| | | out| u string',');
elsif c_id%rowcount
执行

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.
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, chr(10), l_offset, 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_chars - l_offset, 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,'Maximum number of 1000 columns are not allowed',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,' for product in ( '''||out_string||''' , ');
 44                          elsif c_ids%rowcount < item.tot_rows then
 45                  dbms_lob.append(v_query,''||chr(10)||'');
 46                  dbms_lob.append(v_query,' '''||out_string||''' ,');
 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' ,
'B' ,
'C' ,
'D' ,
'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
SQL>@query.SQL
SQL>设置服务器输出的大小不限行220页0
SQL>声明
2 v_查询clob;
3个输出字符串varchar2(100);
4个光标c_ID
5是
6选择不同的产品,按1 asc从t订单中总计()行计数(不同的(产品));
7程序打印到输出(clob中的p_clob)
8是
9 l_偏移量pls_整数:=1;
10个字符,请输入整数;
11开始
12环路
13当l_offset>dbms_lob.getlength(p_clob)时退出;
14 l_字符:=dbms_lob.instr(p_clob,chr(10),l_偏移量,1);
15如果l_chars为null或l_chars=0,则
16个l_字符:=dbms_lob.getlength(p_clob)+1;
17如果结束,则结束;
18 dbms_output.put_line(dbms_lob.substr(p_clob,l_chars-l_offset,l_offset));
19 l_偏移量:=l_字符+1;
20端环;
21结束打印输出;
22开始
23 dbms_输出.启用(空);
24用于c_ID中的项目
25圈
26如果item.tot_行>=1000
27那么
28 raise_应用程序_错误(-20001,“不允许最大1000列数”,true);
29如果有,结束;
30 out_字符串:=item.product;
31如果c_ID%rowcount=1
32那么
33 v_query:=“选择*自(”;
34 dbms|u lob.append(v|u query,| | chr(10)| |');
35 dbms_lob.append(v_query,'select*');
36 dbms|u lob.append(v|u query,| | chr(10)| |');
37 dbms_lob.append(v_query,'from t');
38 dbms|u lob.append(v|u query,| | chr(10)| |');
39 dbms_lob.append(v_query,'pivot(');
40 dbms_lob.append(v_query,“| | chr(10)| |””;
41 dbms_lob.append(v_查询,'计数(产品)');
42 dbms|u lob.append(v|u query,| | chr(10)| |');
43 dbms|u lob.append(v|u query,'for product in(''''| | out| |''',');
44如果c_id%rowcount