oracle 中的动态列使用 sql
dynamic columns in oracle using sql
我有以下 table 的例子。 Thera可以无限分行和客户。我需要将这些分支机构分组并计算他们的客户数量,然后用不同的列显示它。
BRANCHNAME CUSTOMERNO
100 1001010
100 1001011
103 1001012
104 1001013
104 1001014
104 1001015
105 1001016
105 1001017
106 1001018
注意可以有无限的分支和客户,查询必须不仅在这种情况下有效。
在这种情况下,接受的结果是:
100 103 104 105 106
2 1 3 2 1
示例SQL数据
select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual
这将在行(而不是列)中获取它:
SELECT branchname,
COUNT( DISTINCT customerno ) AS customers
FROM your_table
GROUP BY branchname;
(注意:如果 branchname
、customerno
对永远不会重复,则可以省略 DISTINCT
关键字。)
在不知道分支名称是什么的情况下,你只能做 dynamic pivot。
获取上述查询的输出(以行格式)并将其转置为您用来访问数据库的任何 front-end。
来自评论:
I need a report in this format, and don't want write some application , wants to do with sql for easily export to excell in such format
不,您不需要 SQL 中的列格式。您可以将其以行格式放入 excel,然后使用 excel 的 TRANSPOSE
函数将其(非常简单)转换为列,而无需实现复杂的动态 SQL解决方案。
我认为写一个pipelined table function that returns a variable structure是可能的,虽然很复杂。您的管道 table 函数将在运行时使用 Oracle Data Cartridge 接口和 AnyDataSet 类型的魔力 return 动态结构。然后,您可以在后续的 SQL 语句中使用它,就好像它是 table,即
SELECT *
FROM TABLE( your_pipelined_function( p_1, p_2 ));
讨论相同示例实现的更多参考资料
- Dynamic SQL Pivoting
- Oracle Data Cartridge 开发人员指南的 Implementing the Interface Approach 部分
Method4. 下载并安装开源PL/SQL代码后,这里是一个完整的实现:
--Create sample table.
create table branch_data as
select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual;
--Create a dynamic pivot in SQL.
select *
from table(method4.dynamic_query(
q'[
--Create a select statement
select
--The SELECT:
'select'||chr(10)||
--The column list:
listagg(
replace(q'!sum(case when BranchName = '#BRANCH_NAME#' then 1 else 0 end) "#BRANCH_NAME#"!', '#BRANCH_NAME#', BranchName)
, ','||chr(10)) within group (order by BranchName)||chr(10)||
--The FROM:
'from branch_data' v_sql
from
(
--Distinct BranchNames.
select distinct BranchName
from branch_data
)
]'
));
如果你只是想在某处报告结果,你可以对 select 语句使用游标:
select branchname, count(*) from test group by branchname order by branchname asc;
通过光标循环你可能会得到你的值。
这是我的样本:
declare
v_b varchar2(1000);
v_t varchar2(1000);
begin
for i in (select branchname, count(*) total from test group by branchname order by branchname asc)
loop
v_b := v_b || i.branchname || ' ';
v_t := v_t || i.total || ' ';
end loop;
dbms_output.put_line(v_b);
dbms_output.put_line(v_t);
end;
您可以使用此选择:
SELECT branchname, count(*)
FROM test
GROUP BY branchname
总的来说branchname
中的每一个数字都使用选择是不专业的。
这个解决方案怎么样。没有table创建,直接设置v_sql参数即可。
SET SERVEROUTPUT ON SIZE 100000
DECLARE
v_cursor sys_refcursor;
CURSOR get_columns
IS
SELECT EXTRACTVALUE (t2.COLUMN_VALUE, 'node()') VALUE
FROM (SELECT *
FROM TABLE (XMLSEQUENCE (v_cursor))) t1,
TABLE (XMLSEQUENCE (EXTRACT (t1.COLUMN_VALUE, '/ROW/node()'))) t2;
v_column VARCHAR2 (1000);
v_value VARCHAR2 (1000);
v_counter NUMBER (3) := 0;
v_sql VARCHAR2 (4000);
BEGIN
v_sql :=
'SELECT branchname, COUNT (DISTINCT customerno) AS customers'
|| ' FROM (SELECT 100 branchname, 1001010 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 100 branchname, 1001011 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 103 branchname, 1001012 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001013 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001014 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001015 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001016 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001017 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 106 branchname, 1001018 customerno'
|| ' FROM DUAL)'
|| ' GROUP BY branchname';
OPEN v_cursor FOR v_sql;
FOR v_record IN get_columns
LOOP
IF v_counter = 0
THEN
v_column := v_column || v_record.VALUE || ' ';
v_counter := 1;
ELSIF v_counter = 1
THEN
v_value := v_value || v_record.VALUE || ' ';
v_counter := 0;
END IF;
END LOOP;
DBMS_OUTPUT.put_line (v_column);
DBMS_OUTPUT.put_line (v_value);
END;
/
输出为
100 105 104 103 106
2 2 3 1 1
with src as
(select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual )
SELECT * FROM
(select BranchName from src)
PIVOT XML
(COUNT(*) FOR (BranchName)
IN
(SELECT DISTINCT BranchName FROM SRC))
此查询以 xml 格式提供输出。整个 xml 数据将包含在查询结果的字段中(查询只有单行单列输出)。下一步是解析 xml 数据并以表格形式显示。
我有以下 table 的例子。 Thera可以无限分行和客户。我需要将这些分支机构分组并计算他们的客户数量,然后用不同的列显示它。
BRANCHNAME CUSTOMERNO
100 1001010
100 1001011
103 1001012
104 1001013
104 1001014
104 1001015
105 1001016
105 1001017
106 1001018
注意可以有无限的分支和客户,查询必须不仅在这种情况下有效。
在这种情况下,接受的结果是:
100 103 104 105 106
2 1 3 2 1
示例SQL数据
select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual
这将在行(而不是列)中获取它:
SELECT branchname,
COUNT( DISTINCT customerno ) AS customers
FROM your_table
GROUP BY branchname;
(注意:如果 branchname
、customerno
对永远不会重复,则可以省略 DISTINCT
关键字。)
在不知道分支名称是什么的情况下,你只能做 dynamic pivot。
获取上述查询的输出(以行格式)并将其转置为您用来访问数据库的任何 front-end。
来自评论:
I need a report in this format, and don't want write some application , wants to do with sql for easily export to excell in such format
不,您不需要 SQL 中的列格式。您可以将其以行格式放入 excel,然后使用 excel 的 TRANSPOSE
函数将其(非常简单)转换为列,而无需实现复杂的动态 SQL解决方案。
我认为写一个pipelined table function that returns a variable structure是可能的,虽然很复杂。您的管道 table 函数将在运行时使用 Oracle Data Cartridge 接口和 AnyDataSet 类型的魔力 return 动态结构。然后,您可以在后续的 SQL 语句中使用它,就好像它是 table,即
SELECT *
FROM TABLE( your_pipelined_function( p_1, p_2 ));
讨论相同示例实现的更多参考资料
- Dynamic SQL Pivoting
- Oracle Data Cartridge 开发人员指南的 Implementing the Interface Approach 部分
Method4. 下载并安装开源PL/SQL代码后,这里是一个完整的实现:
--Create sample table. create table branch_data as select '100' BranchName,'1001010' CustomerNo from dual UNION ALL select '100' BranchName,'1001011' CustomerNo from dual UNION ALL select '103' BranchName,'1001012' CustomerNo from dual UNION ALL select '104' BranchName,'1001013' CustomerNo from dual UNION ALL select '104' BranchName,'1001014' CustomerNo from dual UNION ALL select '104' BranchName,'1001015' CustomerNo from dual UNION ALL select '105' BranchName,'1001016' CustomerNo from dual UNION ALL select '105' BranchName,'1001017' CustomerNo from dual UNION ALL select '106' BranchName,'1001018' CustomerNo from dual; --Create a dynamic pivot in SQL. select * from table(method4.dynamic_query( q'[ --Create a select statement select --The SELECT: 'select'||chr(10)|| --The column list: listagg( replace(q'!sum(case when BranchName = '#BRANCH_NAME#' then 1 else 0 end) "#BRANCH_NAME#"!', '#BRANCH_NAME#', BranchName) , ','||chr(10)) within group (order by BranchName)||chr(10)|| --The FROM: 'from branch_data' v_sql from ( --Distinct BranchNames. select distinct BranchName from branch_data ) ]' ));
如果你只是想在某处报告结果,你可以对 select 语句使用游标:
select branchname, count(*) from test group by branchname order by branchname asc;
通过光标循环你可能会得到你的值。
这是我的样本:
declare
v_b varchar2(1000);
v_t varchar2(1000);
begin
for i in (select branchname, count(*) total from test group by branchname order by branchname asc)
loop
v_b := v_b || i.branchname || ' ';
v_t := v_t || i.total || ' ';
end loop;
dbms_output.put_line(v_b);
dbms_output.put_line(v_t);
end;
您可以使用此选择:
SELECT branchname, count(*)
FROM test
GROUP BY branchname
总的来说branchname
中的每一个数字都使用选择是不专业的。
这个解决方案怎么样。没有table创建,直接设置v_sql参数即可。
SET SERVEROUTPUT ON SIZE 100000
DECLARE
v_cursor sys_refcursor;
CURSOR get_columns
IS
SELECT EXTRACTVALUE (t2.COLUMN_VALUE, 'node()') VALUE
FROM (SELECT *
FROM TABLE (XMLSEQUENCE (v_cursor))) t1,
TABLE (XMLSEQUENCE (EXTRACT (t1.COLUMN_VALUE, '/ROW/node()'))) t2;
v_column VARCHAR2 (1000);
v_value VARCHAR2 (1000);
v_counter NUMBER (3) := 0;
v_sql VARCHAR2 (4000);
BEGIN
v_sql :=
'SELECT branchname, COUNT (DISTINCT customerno) AS customers'
|| ' FROM (SELECT 100 branchname, 1001010 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 100 branchname, 1001011 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 103 branchname, 1001012 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001013 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001014 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 104 branchname, 1001015 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001016 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 105 branchname, 1001017 customerno'
|| ' FROM DUAL'
|| ' UNION ALL'
|| ' SELECT 106 branchname, 1001018 customerno'
|| ' FROM DUAL)'
|| ' GROUP BY branchname';
OPEN v_cursor FOR v_sql;
FOR v_record IN get_columns
LOOP
IF v_counter = 0
THEN
v_column := v_column || v_record.VALUE || ' ';
v_counter := 1;
ELSIF v_counter = 1
THEN
v_value := v_value || v_record.VALUE || ' ';
v_counter := 0;
END IF;
END LOOP;
DBMS_OUTPUT.put_line (v_column);
DBMS_OUTPUT.put_line (v_value);
END;
/
输出为
100 105 104 103 106
2 2 3 1 1
with src as
(select '100' BranchName,'1001010' CustomerNo from dual UNION ALL
select '100' BranchName,'1001011' CustomerNo from dual UNION ALL
select '103' BranchName,'1001012' CustomerNo from dual UNION ALL
select '104' BranchName,'1001013' CustomerNo from dual UNION ALL
select '104' BranchName,'1001014' CustomerNo from dual UNION ALL
select '104' BranchName,'1001015' CustomerNo from dual UNION ALL
select '105' BranchName,'1001016' CustomerNo from dual UNION ALL
select '105' BranchName,'1001017' CustomerNo from dual UNION ALL
select '106' BranchName,'1001018' CustomerNo from dual )
SELECT * FROM
(select BranchName from src)
PIVOT XML
(COUNT(*) FOR (BranchName)
IN
(SELECT DISTINCT BranchName FROM SRC))
此查询以 xml 格式提供输出。整个 xml 数据将包含在查询结果的字段中(查询只有单行单列输出)。下一步是解析 xml 数据并以表格形式显示。