XML ... oder nicht XML ...?
- Speichert man die XML-Dokumente als solche (XMLTYPE) ...?
- Oder verteilt man die Inhalte eher auf gewöhnliche relationale Tabellen ...?
- Welche Vorteile bietet die Speicherung als XMLTYPE ...?
Eingestellt von
Carsten Czarski
um
14:47
0
Kommentare
Lesen
declare
v_rindex binary_integer := dbms_application_info.set_session_longops_nohint;
v_slno binary_integer;
v_sofar number := 0;
v_seconds binary_integer := 120;
begin
dbms_application_info.set_session_longops(
rindex => v_rindex
,slno => v_slno
,op_name => 'TEST_SESSION_LONGOPS'
,totalwork => v_seconds
,sofar => v_sofar
);
while v_sofar < v_seconds loop
dbms_lock.sleep(v_seconds / 10);
v_sofar := v_sofar + (v_seconds / 10);
dbms_application_info.set_session_longops(
rindex => v_rindex
,slno => v_slno
,op_name => 'TEST_SESSION_LONGOPS'
,totalwork => v_seconds
,sofar => v_sofar
);
end loop;
end;
/
sho err
SQL> select opname, sofar, totalwork from v$session_longops where opname like 'TEST%'; OPNAME SOFAR TOTALWORK ------------------------------ ---------- --------------- TEST_SESSION_LONGOPS 60 120
Eingestellt von
Carsten Czarski
um
13:47
1 Kommentare
Lesen
Labels: DBMS_APPLICATION_INFO, Job, LONGOPS, Session
SQL> select sid, serial#, username, client_info
2 from v$session
3 where username is not null;
SID SERIAL# USERNAME CLIENT_INFO
---------- ---------- -------------------- ---------------
147 35 DEMO_WS
149 73 DEMO_WS
159 285 SYSTEM
: : :
begin
DBMS_APPLICATION_INFO.SET_CLIENT_INFO(
client_info => 'APPLIKATION MIS 01'
);
DBMS_APPLICATION_INFO.SET_MODULE(
module_name => 'ADMIN_MODUL',
action_name => 'BATCH_JOB_FRIDAY_001'
);
end;
SID SERIAL# USERNAME CLIENT_INFO MODULE ACTION
---------- ---------- --------------- -------------------- ------------------ -------------------------
138 82 SCOTT APPLIKATION MIS 01 ADMIN_MODUL BATCH_JOB_FRIDAY_001
: : : : : :
Eingestellt von
Carsten Czarski
um
14:17
0
Kommentare
Lesen
Labels: DBMS_APPLICATION_INFO, Session
SELECT rownum zeile FROM dual connect BY level <= xalso ...
SELECT rownum zeile FROM dual connect BY level <= 100Probiert's mal aus ...
Eingestellt von
Carsten Czarski
um
16:13
4
Kommentare
Lesen
BEZEICHNUNG START_DATU END_DATUM ------------------------------ ---------- ---------- Veranstaltung 1 01.05.2007 10.05.2007 Veranstaltung 2 16.05.2007 19.05.2007 Veranstaltung 3 07.07.2007 12.07.2007Zuerst lege man sich eine Hilfstabelle mit allen Datumswerten wie folgt an:
create table datum (
datum date,
constraint pk_datum primary key (datum)
) organization index
/
declare
v_curr_date date := to_date('2005-01-01', 'YYYY-MM-DD');
v_end_date date := to_date('2015-01-01', 'YYYY-MM-DD');
begin
while v_curr_date < v_end_date loop
insert into datum values (v_curr_date);
v_curr_date := v_curr_date + 1;
end loop;
end;
/
sho err
commit
/
Um den Zugriff auf die Hilfstabelle zu optimieren, wählen wir eine index-organized-table. Nun lassen sich die Tage zwischen Beginn- und Ende-Datum einfach durch einen Join ermitteln:
select v.bezeichnung, d.datum from veranstaltung v join datum d on (d.datum between v.start_datum and v.end_datum) / BEZEICHNUNG DATUM ------------------------------ ---------- Veranstaltung 1 01.05.2007 Veranstaltung 1 02.05.2007 Veranstaltung 1 03.05.2007 Veranstaltung 1 04.05.2007 Veranstaltung 1 05.05.2007 Veranstaltung 1 06.05.2007 Veranstaltung 1 07.05.2007 Veranstaltung 1 08.05.2007 Veranstaltung 1 09.05.2007 Veranstaltung 1 10.05.2007 Veranstaltung 2 16.05.2007 Veranstaltung 2 17.05.2007 Veranstaltung 2 18.05.2007 Veranstaltung 2 19.05.2007 Veranstaltung 3 07.07.2007 Veranstaltung 3 08.07.2007 Veranstaltung 3 09.07.2007 Veranstaltung 3 10.07.2007 Veranstaltung 3 11.07.2007 Veranstaltung 3 12.07.2007Natürlich können auch die Wochenenden ausgefiltert werden:
select v.bezeichnung, d.datum
from test v join datum d on (
d.datum between v.start_datum and v.end_datum
and rtrim(to_char(d.datum, 'DAY', 'nls_date_language=''GERMAN''')) not in ('SAMSTAG','SONNTAG')
)
/
BEZEICHNUNG DATUM
------------------------------ ----------
Veranstaltung 1 01.05.2007
Veranstaltung 1 02.05.2007
Veranstaltung 1 03.05.2007
Veranstaltung 1 04.05.2007
Veranstaltung 1 07.05.2007
Veranstaltung 1 08.05.2007
:
Eingestellt von
Carsten Czarski
um
15:26
1 Kommentare
Lesen
create or replace function getPivotSql(
p_sql in varchar2,
p_x_col in varchar2,
p_x_col_type in varchar2 default 'DATE',
p_x_col_start in varchar2,
p_x_col_interval in varchar2,
p_x_col_int_unit in varchar2 default 'DAY',
p_x_col_count in number,
p_y_col in varchar2,
p_cell_col in varchar2,
p_cell_col_aggr in varchar2 default NULL
) return varchar2
is
v_sql varchar2(32767);
begin
v_sql := '';
v_sql := v_sql || 'with data as ('||chr(10);
v_sql := v_sql || ' '||p_sql||chr(10);
v_sql := v_sql || ')';
if p_x_col_type = 'VARCHAR2' then
v_sql := v_sql ||', x_dist_values as ('||chr(10);
v_sql := v_sql ||' select distinct '||p_x_col||' val from data order by 1'||chr(10);
v_sql := v_sql ||'), x_values_rownum as ('||chr(10);
v_sql := v_sql ||' select rownum zeile, val from x_dist_values where rownum <= '||p_x_col_count||chr(10);
v_sql := v_sql ||')'||chr(10);
else
v_sql := v_sql || chr(10);
end if;
v_sql := v_sql || 'select distinct '||chr(10);
v_sql := v_sql || ' data.'||p_y_col||','||chr(10);
for i in 1..p_x_col_count loop
if p_cell_col_aggr is not null then
v_sql := v_sql || p_cell_col_aggr||'(';
end if;
v_sql := v_sql || ' case when ';
if p_x_col_type = 'VARCHAR2' then
v_sql := v_sql || 'x.zeile = '||i;
elsif p_x_col_type = 'NUMBER' then
v_sql := v_sql || ' data.'||p_x_col||' >= '||p_x_col_start||
' + ('||(i - 1)||' * '||p_x_col_interval || ') ' ||
' and data.'||p_x_col||' < '||p_x_col_start||
' + ('||i||' * '||p_x_col_interval||') ';
elsif p_x_col_type = 'DATE' then
v_sql := v_sql || ' data.'||p_x_col||' >= '||p_x_col_start||
' + interval '''||((i - 1) * p_x_col_interval )||''' '||p_x_col_int_unit||
' and data.'||p_x_col||' < '||p_x_col_start||
' + interval '''||i * p_x_col_interval ||''' '||p_x_col_int_unit;
end if;
v_sql := v_sql ||' then '||p_cell_col|| ' else null end';
if p_cell_col_aggr is not null then
v_sql := v_sql || ')';
end if;
v_sql := v_sql || ' as "VALUE['||i||']"';
if i < p_x_col_count then
v_sql := v_sql || ',';
end if;
v_sql := v_sql ||chr(10);
end loop;
v_sql := v_sql || 'from data'||chr(10);
if p_x_col_type = 'VARCHAR2' then
v_sql := v_sql || 'join x_values_rownum x on (data.'||p_x_col||' = x.val)'||chr(10);
end if;
if p_cell_col_aggr is not null then
v_sql := v_sql || 'group by data.'||p_y_col||chr(10);
end if;
return v_sql;
end;
/
Sie wird wie folgt aufgerufen:
getPivotSql( P_SQL => [SQL, dessen Ergebnismenge pivotiert werden soll] P_X_COL => [X-Spalte] P_X_COL_TYPE => [Datentyp der X-Spalte] P_X_COL_START => [Bei NUMBER und DATE: Startwert der X-Spalte] P_X_COL_INTERVAL => [Bei NUMBER und DATE: Intervall, umwelches sich X mit jeder Spalte erhöhen soll] P_X_COL_INT_UNIT => [Bei DATE: Einheit des Intervalls (DAY, MONTH, YEAR)] P_X_COL_COUNT => [Anzahl der X-Spalten] P_Y_COL => [Y-Spalte] P_CELL_COL => [Spalte, mit der die Zellen gefüllt werden sollen] P_CELL_COL_AGGR => [Aggregatsfunktion für die Zellen] )Ein Beispiel: Auf der X-Achse sollen die Jobs, auf der Y-Achse die Departments aufgetragen werden; in den Zellen soll die Gehaltssumme stehen, so dass man sehen kann, in welchen Jobs und in welchen Abteilungen welche Gehälter gezahlt werden.
select getPivotSql( 'select deptno, job, sal from emp', /* SQL mit den Daten */ 'JOB', /* X-Spalte */ 'VARCHAR2', /* Datentyp der X-Spalte */ null, /* VARCHAR2: Kein Startwert */ null, /* VARCHAR2: Kein Intervall */ null, /* VARCHAR2: Keine Einheit für das Intervall */ 5, /* maximal 5 X-Spalten */ 'DEPTNO', /* Y-Achse (Zeilen) */ 'SAL', /* Zellenwerte (Gehalt) */ 'SUM' /* Aggregatsfunktion (Summe) */ ) from dual /Als Ergebnis kommt folgendes SQL heraus ...
with data as ( select deptno, job, sal from emp ), x_dist_values as ( select distinct JOB val from data order by 1 ), x_values_rownum as ( select rownum zeile, val from x_dist_values where rownum <= 5 ) select distinct data.DEPTNO, SUM( case when x.zeile = 1 then SAL else null end) as "VALUE[1]", SUM( case when x.zeile = 2 then SAL else null end) as "VALUE[2]", SUM( case when x.zeile = 3 then SAL else null end) as "VALUE[3]", SUM( case when x.zeile = 4 then SAL else null end) as "VALUE[4]", SUM( case when x.zeile = 5 then SAL else null end) as "VALUE[5]" from data join x_values_rownum x on (data.JOB = x.val) group by data.DEPTNO... und ausgeführt ergibt sich:
DEPTNO VALUE[1] VALUE[2] VALUE[3] VALUE[4] VALUE[5]
---------- ---------- ---------- ---------- ---------- ----------
30 950 2850 5600
20 6000 1900 2975
10 1300 2450 5000
3 Zeilen ausgewählt.
Andere Beispiele: Es soll anhand des Gehalts selektiert werden. Ausgehend von einem Startgehalt
von 1.000 sollen drei Gruppen gebildet werden (1000 - 2500, 2500 - 4000, 4000 - 5500). Diese werden
auf der X-Achse aufgetragen - Die Y-Achse bilden diesmal die Jobs:
select getPivotSql( 'select job, sal, empno from emp', /* SQL mit den Daten */ 'SAL', /* X-Spalte */ 'NUMBER', /* Datentyp der X-Spalte */ 1000, /* VARCHAR2: Kein Startwert */ 1500, /* VARCHAR2: Kein Intervall */ null, /* VARCHAR2: Keine Einheit für das Intervall */ 3, /* maximal 5 X-Spalten */ 'JOB', /* Y-Achse (Zeilen) */ 'EMPNO', /* Zellenwerte (Gehalt) */ 'COUNT' /* Aggregatsfunktion (Summe) */ ) from dual /Dann kommt dieses SQL heraus:
with data as ( select job, sal, empno from emp ) select distinct data.JOB, COUNT( case when data.SAL between 1000 + (0 * 1500) and 1000 + (1 * 1500) then EMPNO else null end) as "VALUE[1]", COUNT( case when data.SAL between 1000 + (1 * 1500) and 1000 + (2 * 1500) then EMPNO else null end) as "VALUE[2]", COUNT( case when data.SAL between 1000 + (2 * 1500) and 1000 + (3 * 1500) then EMPNO else null end) as "VALUE[3]" from data group by data.JOBAusgeführt ...
JOB VALUE[1] VALUE[2] VALUE[3] --------- ---------- ---------- ---------- CLERK 2 0 0 SALESMAN 4 0 0 PRESIDENT 0 0 1 MANAGER 1 2 0 ANALYST 0 2 0Probiert es aus! Feedback bzw. Kommentare sind natürlich stets erwünscht ...
Eingestellt von
Carsten Czarski
um
14:04
7
Kommentare
Lesen
select deptno, job, count(ename) anzahl
from emp
group by deptno, job
order by deptno, job;
DEPTNO JOB ANZAHL
---------- --------- ----------
10 CLERK 1
10 MANAGER 1
10 PRESIDENT 1
20 ANALYST 2
20 CLERK 2
20 MANAGER 1
30 CLERK 1
30 MANAGER 1
30 SALESMAN 4
Möchte man die Tabelle nun "kippen" ...
DEPTNO JOB_1 JOB_2 JOB_3 JOB_4 JOB_5
---------- --------- ---------- ---------- --------- ----------
10 1 1 1
20 2 2 1
30 1 1 4
... muss man die Abfrage für jede Spalte wie folgt mit sich selbst joinen. Wenn die "Grundabfrage" keine einfache Tabelle ist, kann man mit der WITH ... AS-Klausel auch eine SQL-Abfrage als Inline-View definieren.
with data as ( select deptno, job, count(ename) anzahl from emp group by deptno, job deptno ), x_dist_values as ( select distinct JOB val from data order by 1 ), x_values_rownum as ( select rownum zeile, val from x_dist_values where rownum <= 5 ) select distinct data.DEPTNO, p1.ANZAHL "VALUE[1]", p2.ANZAHL "VALUE[2]", p3.ANZAHL "VALUE[3]", p4.ANZAHL "VALUE[4]", p5.ANZAHL "VALUE[5]" from data join (select val from x_values_rownum where zeile = 1) xvr1 on (1=1) join (select val from x_values_rownum where zeile = 2) xvr2 on (1=1) join (select val from x_values_rownum where zeile = 3) xvr3 on (1=1) join (select val from x_values_rownum where zeile = 4) xvr4 on (1=1) join (select val from x_values_rownum where zeile = 5) xvr5 on (1=1) left outer join data p1 on ( data.deptno = p1.deptno and p1.JOB = xvr1.val ) left outer join data p2 on ( data.deptno = p2.deptno and p2.JOB = xvr2.val ) left outer join data p3 on ( data.deptno = p3.deptno and p3.JOB = xvr3.val ) left outer join data p4 on ( data.deptno = p4.deptno and p4.JOB = xvr4.val ) left outer join data p5 on ( data.deptno = p5.deptno and p5.JOB = xvr5.val )Das Prinzip einer relationalen Datenbank und damit eines jeden SQL ist, dass die Spalten stets fix sind. Ein SQL-Kommando, welches stets eine dynamische Anzahl von Spalten anzeigt, ist nicht so einfach. Lösbar ist das Problem jedoch mit dynamischem SQL. Wie das geht, steht dann in der nächsten Ausgabe.
Eingestellt von
Carsten Czarski
um
09:12
4
Kommentare
Lesen
|
|
|
|