<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3592984248764138907</atom:id><lastBuildDate>Sat, 25 Feb 2012 10:10:47 +0000</lastBuildDate><category>dbms_stat_funcs</category><category>subquery</category><category>apex</category><category>DBMS_EPG</category><category>package</category><category>sqlpath</category><category>postings</category><category>community</category><category>FILE_PKG</category><category>tabellenkalkulation</category><category>hamburg</category><category>tokenizer</category><category>array</category><category>truncate</category><category>Job</category><category>SIMPLE_INTEGER</category><category>with</category><category>best db project</category><category>odci</category><category>message</category><category>rss</category><category>11g</category><category>like</category><category>inhalt</category><category>gleichung</category><category>wget</category><category>start with</category><category>plsql</category><category>transactional</category><category>table</category><category>regexp_replace</category><category>foreign key</category><category>type</category><category>workshop</category><category>Geodaten</category><category>textbasiert</category><category>group by</category><category>authentication</category><category>commit</category><category>connect by</category><category>ols_regression</category><category>where</category><category>analytic function</category><category>inventory</category><category>Session</category><category>diff</category><category>getpivotsql</category><category>xmldiff</category><category>beta</category><category>c</category><category>objektrelational</category><category>oerr</category><category>SDO_GEOM</category><category>report</category><category>bytes</category><category>alert</category><category>instead-of</category><category>dml</category><category>view</category><category>UTL_SMTP</category><category>treffen</category><category>to_char</category><category>network</category><category>external</category><category>datetime</category><category>error</category><category>sysman</category><category>UTL_HTTP</category><category>securefiles</category><category>NUMBER</category><category>space</category><category>DBMS_ACL_ADMIN</category><category>Betriebssystem</category><category>java mail</category><category>MAIL_CLIENT</category><category>magic</category><category>BINARY_FLOART</category><category>recursive</category><category>doag</category><category>import</category><category>ctx_doc</category><category>quote</category><category>xmlpatch</category><category>event</category><category>gqlplus</category><category>sql developer</category><category>tracing</category><category>identifiers</category><category>Shell</category><category>drop</category><category>add_months</category><category>DBMS_CQ_NOTIFICATION</category><category>enterprise manager</category><category>xml db</category><category>entwickler</category><category>bulk</category><category>lookup</category><category>xdb</category><category>xmltable</category><category>tuning</category><category>apex 4.0 plugins</category><category>rollen</category><category>remote database</category><category>update</category><category>repository</category><category>v$sesstat</category><category>dwh</category><category>time zone</category><category>dburi</category><category>tracefile</category><category>unique</category><category>extensions</category><category>login</category><category>cloud computing</category><category>11.2</category><category>ref</category><category>dba</category><category>dbms_shared_pool</category><category>FILE_TYPE</category><category>size</category><category>Skript</category><category>version</category><category>sqldeveloper</category><category>ordvideo</category><category>select as of</category><category>DBMS_PREPROCESSOR</category><category>BINARY_DOUBLE</category><category>SQL*Plus</category><category>create</category><category>replace</category><category>v$session</category><category>DBMS_LDAP</category><category>unload</category><category>sql</category><category>twitter</category><category>bind variablen</category><category>index</category><category>updatable</category><category>md5</category><category>Kreuztabelle</category><category>dbms_xplan</category><category>os_command</category><category>unzip</category><category>ftp</category><category>privilegien</category><category>virtual Column</category><category>datafile</category><category>SDO_GEOMETRY</category><category>execution plan</category><category>webseminar</category><category>NLS_SORT</category><category>DBMS_SPACE</category><category>initialize</category><category>NLS_COMP</category><category>encoding</category><category>oradb</category><category>etl</category><category>sys_guid</category><category>storage</category><category>sqlplus</category><category>date</category><category>insert</category><category>CLOB</category><category>pl/scope</category><category>kalender</category><category>product</category><category>utl_i18n</category><category>regression</category><category>hint</category><category>dba_segments</category><category>cursor</category><category>table functions</category><category>publish</category><category>daten</category><category>11gr2</category><category>installer</category><category>servlet</category><category>performance</category><category>group</category><category>vortrag</category><category>reverse</category><category>Oracle11g</category><category>xml</category><category>LOB</category><category>statistic</category><category>UTL_TCP</category><category>security</category><category>sequence</category><category>dbms_alert</category><category>optimizer</category><category>resumable</category><category>oracle414</category><category>httpuritype</category><category>user</category><category>query rewrite</category><category>filter</category><category>STRUCT</category><category>entwicklung</category><category>data_only</category><category>software</category><category>segment</category><category>odd</category><category>html</category><category>sig</category><category>regular expressions</category><category>linguistisch</category><category>binary xml</category><category>Datentyp</category><category>DBMS_XDB</category><category>dbms_assert</category><category>proxy</category><category>jdbc</category><category>debugging</category><category>tkprof</category><category>sql/xml</category><category>IN clause</category><category>map</category><category>change</category><category>dbms_datapump</category><category>extractvalue</category><category>load</category><category>pivot</category><category>export</category><category>Spatial</category><category>http</category><category>sql injection</category><category>string</category><category>umlaut</category><category>download</category><category>having</category><category>delete</category><category>dbms_metadata</category><category>transactions</category><category>ORACLE_HOME</category><category>regexp_like</category><category>Function</category><category>browser</category><category>script</category><category>windows</category><category>data cartridge</category><category>aggregat</category><category>timestamp</category><category>csv</category><category>flashback</category><category>intelligent cursor sharing</category><category>explain plan</category><category>BLOB</category><category>database</category><category>merge</category><category>memory leak</category><category>release 2</category><category>nlssort</category><category>konferenz</category><category>primary key</category><category>Umgebungsvariablen</category><category>sure</category><category>otn</category><category>relational</category><category>convert</category><category>DBMS_LOB</category><category>document</category><category>objects</category><category>trigger</category><category>2010</category><category>datenbank</category><category>force</category><category>ratio_to_report</category><category>jvm</category><category>Java</category><category>Datei</category><category>constraint</category><category>null</category><category>dbms_flashback</category><category>stock quote</category><category>arithmetic</category><category>matrix</category><category>DBMS_CONNECTION_POOL</category><category>imap</category><category>Metadaten</category><category>DBMS_APPLICATION_INFO</category><category>dictionary</category><category>LONGOPS</category><category>tablespace</category><category>model</category><category>dbms_advanced_rewrite</category><category>UTL_FILE</category><category>pldoc</category><category>oraclexe</category><category>iana</category><category>password</category><category>boolean</category><category>zip</category><category>Compile</category><category>checksum</category><category>deferred</category><title>Oracle SQL und PL/SQL ...</title><description>Tipps, Tricks, "Best Practice"</description><link>http://sql-plsql-de.blogspot.com/</link><managingEditor>noreply@blogger.com (Carsten Czarski)</managingEditor><generator>Blogger</generator><openSearch:totalResults>185</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SqlUndPlsqlInOracle" /><feedburner:info uri="sqlundplsqlinoracle" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>48.1800773</geo:lat><geo:long>11.536734</geo:long><feedburner:emailServiceId>SqlUndPlsqlInOracle</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-2190141705167884235</guid><pubDate>Fri, 24 Feb 2012 09:14:00 +0000</pubDate><atom:updated>2012-02-24T10:14:35.906+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">having</category><category domain="http://www.blogger.com/atom/ns#">group</category><title>SQL HAVING ... Kennt jeder, oder?</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Everyone knows SQL HAVING ...?&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;p&gt;
 Dieses Blog Posting widme SQL &lt;b&gt;HAVING&lt;/b&gt;. Das sieht dann zwar eher nach "SQL Grundkurs" aus, aber
 mir fällt schon auf, dass &lt;b&gt;HAVING&lt;/b&gt; in der Praxis gerne vergessen und durch Subselects "emuliert" wird.
 Und das muss ja nicht sein. Also machen wir heute ein kurzes, aber einfaches Blog Posting zum Thema
 &lt;b&gt;HAVING&lt;/b&gt;. Wie immer, reicht die Tabelle &lt;b&gt;EMP&lt;/b&gt; als Beispiel völlig aus.
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
  d.dname, 
  sum(e.sal) sal_sum,
  count(e.empno) emp_cnt
&lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname

DNAME             SAL_SUM    EMP_CNT
-------------- ---------- ----------
ACCOUNTING           8750          3
RESEARCH            10875          5
SALES                9400          6
&lt;/pre&gt;
&lt;p&gt;
 Nun möchten wir nur die Abteilungen mit mindestens 5 Mitarbeitern haben ... häufig findet man dann
 diese Lösung, die auch durchaus funktioniert ... 
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; (
  &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
    d.dname, 
    sum(e.sal) sal_sum,
    count(e.empno) emp_cnt
  &lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
  &lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname
) 
&lt;font color="#6a5acd"&gt;where&lt;/font&gt; emp_cnt &amp;gt;= &lt;font color="#ff00ff"&gt;5&lt;/font&gt;

DNAME             SAL_SUM    EMP_CNT
-------------- ---------- ----------
RESEARCH            10875          5
SALES                9400          6
&lt;/pre&gt;
&lt;p&gt;
 Analog geht es natürlich auch mit der WITH-Klausel. Es geht aber auch eleganter, denn für das
 Filtern auf aggregierten Werten gibt es eben &lt;b&gt;HAVING&lt;/b&gt;.
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
  d.dname, 
  sum(e.sal) sal_sum,
  count(e.empno) emp_cnt
&lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname
&lt;font color="#6a5acd"&gt;having&lt;/font&gt; count(e.empno) &amp;gt; &lt;font color="#ff00ff"&gt;5&lt;/font&gt;
&lt;/pre&gt;
&lt;p&gt;
 So ... und das war's auch schon für heute ...
&lt;/p&gt;
&lt;/div&gt;










&lt;div lang="en" style="display: none;"&gt;
&lt;p&gt;
 Today I'll post about SQL &lt;b&gt;HAVING&lt;/b&gt;. This looks a bit like "SQL - Lesson 1", but my observation is
 that HAVING is very often "emulated" with subqueries or &lt;b&gt;WITH&lt;/b&gt; clauses. Using the &lt;b&gt;HAVING&lt;/b&gt; clause would make
 some SQL queries simpler - and for that reason: This short posting is about SQL &lt;b&gt;HAVING&lt;/b&gt; . As always,
 I'll use the well-known table &lt;b&gt;EMP&lt;/b&gt; as example.
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
  d.dname, 
  sum(e.sal) sal_sum,
  count(e.empno) emp_cnt
&lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname

DNAME             SAL_SUM    EMP_CNT
-------------- ---------- ----------
ACCOUNTING           8750          3
RESEARCH            10875          5
SALES                9400          6
&lt;/pre&gt;
&lt;p&gt;
 Now we want to have only the departments with more than 5 employees. The following
 query is quite often being used in  such scenarios. And it works fine ...
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; (
  &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
    d.dname, 
    sum(e.sal) sal_sum,
    count(e.empno) emp_cnt
  &lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
  &lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname
) 
&lt;font color="#6a5acd"&gt;where&lt;/font&gt; emp_cnt &amp;gt;= &lt;font color="#ff00ff"&gt;5&lt;/font&gt;

DNAME             SAL_SUM    EMP_CNT
-------------- ---------- ----------
RESEARCH            10875          5
SALES                9400          6
&lt;/pre&gt;
&lt;p&gt;
 A SQL WITH clause would also work, of course. But the more elegant solution to filter 
 on aggregated values is &lt;b&gt;HAVING&lt;/b&gt;.
&lt;/p&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
  d.dname, 
  sum(e.sal) sal_sum,
  count(e.empno) emp_cnt
&lt;font color="#6a5acd"&gt;from&lt;/font&gt; emp e join dept d &lt;font color="#6a5acd"&gt;on&lt;/font&gt; (d.deptno = e.deptno)
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; d.dname
&lt;font color="#6a5acd"&gt;having&lt;/font&gt; count(e.empno) &amp;gt; &lt;font color="#ff00ff"&gt;5&lt;/font&gt;
&lt;/pre&gt;
&lt;p&gt;
 And that's it ... 
&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-2190141705167884235?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/OgLHJ0zw1Yc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/OgLHJ0zw1Yc/sql-having-kennt-jeder-oder.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2012/02/sql-having-kennt-jeder-oder.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-8095290745361161262</guid><pubDate>Fri, 10 Feb 2012 07:56:00 +0000</pubDate><atom:updated>2012-02-10T09:01:01.368+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">vortrag</category><category domain="http://www.blogger.com/atom/ns#">entwickler</category><category domain="http://www.blogger.com/atom/ns#">konferenz</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>DOAG Entwicklerkonferenz im Juni 2012!</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;DOAG Developer conference&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;p&gt;
 Heute ist es mal nichts technisches: Ich möchte einfach nur auf eine DOAG-Veranstaltung hinweisen, die ich sehr interessant finde.
 Ich zitiere aus dem Call for Papers der DOAG:
&lt;/p&gt;
&lt;div style="border: 1px solid black; padding: 3px;"&gt;
&lt;i&gt;
Erstmals veranstaltet die DOAG in Bonn eine &lt;b&gt;Konferenz für den Erfahrungsaustausch der Software-Entwickler&lt;/b&gt;, die DOAG 2012 Development. Am &lt;b&gt;14. Juni 2012&lt;/b&gt; verwandelt sich das Maritim Hotel Bonn zum Brennpunkt der Development-Szene im Oracle-Umfeld. Seien Sie dabei und tauchen Sie tief in die Software-Entwicklung mittels Tools und Technologien aus dem Hause Oracle ein! Im Mittelpunkt stehen der Erfahrungsaustausch zu Java, JDeveloper und PL/SQL, aber auch zu den Werkzeugen SQL Forms und Reports.
&lt;p&gt;
&lt;br/&gt;
 – C A L L&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;F O R&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbspP R E S E N T A T I O N S –
&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
Werden Sie Referent auf der DOAG 2012 Development! Reichen Sie ab sofort Ihr Vortragsangebot &lt;a href="https://www.doag.org/termine/cfp.php?id=437614" target="_blank"&gt;hier online&lt;/a&gt; ein!
&lt;/p&gt;
&lt;p&gt;
Sie haben bis zum 05. März 2012 die Gelegenheit, sich um einen Vortrag zu bewerben! Als Referent erhalten Sie natürlich freien Eintritt zur Konferenz. Wir suchen Vorträge zu folgenden Themenbereichen:
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;SQL und DB-Design&lt;/li&gt;&lt;li&gt;PL/SQL und Apex&lt;/li&gt;&lt;li&gt;Forms und ADF&lt;/li&gt;&lt;li&gt;Reporting und BI&lt;/li&gt;&lt;li&gt;Karten und Geodaten (Spatial)&lt;/li&gt;&lt;li&gt;SOA und BPM&lt;/li&gt;&lt;li&gt; Java und Open Source&lt;/li&gt;&lt;li&gt; Strategie und Software-Architektur&lt;/li&gt;&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;
Wir freuen uns auf Ihre Vortragsbewerbung!
&lt;br/&gt;
&lt;/p&gt;
&lt;p&gt;
Alle weiteren Informationen zur DOAG 2012 Development erhalten Sie hier:&lt;br/&gt;
&lt;a href="http://www.doag.org/events/konferenzen/doag-2012-development.html" target="_blank"&gt;http://www.doag.org/events/konferenzen/doag-2012-development.html&lt;/a&gt;
&lt;/p&gt;
&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;
 Ich werde auf jeden Fall Vorträge einreichen - und hoffe, dass diese a) etwas angenommen werden und b) dass ich mich dort mit vielen anderen Entwicklern austauschen kann.
&lt;/p&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;This posting is about a german users' group conference and therefore in german only.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-8095290745361161262?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/y1xW4jG2UuI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/y1xW4jG2UuI/doag-developer-conference-heute-ist-es.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2012/02/doag-developer-conference-heute-ist-es.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-6139405337299966715</guid><pubDate>Mon, 30 Jan 2012 13:04:00 +0000</pubDate><atom:updated>2012-01-30T14:04:33.583+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">xdb</category><category domain="http://www.blogger.com/atom/ns#">xmlpatch</category><category domain="http://www.blogger.com/atom/ns#">xml</category><category domain="http://www.blogger.com/atom/ns#">xmldiff</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>XML Dokumente mit SQL vergleichen: XMLDIFF und XMLPATCH</title><description>&lt;div lang="en" style="color: #cc6600; display: none;"&gt;
Comparing XML with SQL: XMLDIFF and XMLPATCH&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;div&gt;
Heute möchte ich etwas über zwei  ganz interessante SQL-Funktionen in der Datenbank schreiben: &lt;b&gt;XMLDIFF&lt;/b&gt; 
 und &lt;b&gt;XMLPATCH&lt;/b&gt;. Fangen wir mit &lt;b&gt;XMLDIFF&lt;/b&gt; an: Es vergleicht XML-Dokumente. Und dazu am besten mal ein
 Beispiel ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;document&lt;/span&gt;&lt;span style="color: teal;"&gt; &lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;xmlns&lt;/b&gt;&lt;/span&gt;=&lt;span style="color: magenta;"&gt;"my-namespace"&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;leeres-xmltag&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;/leeres-xmltag&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-inhalt&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;"&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;/xmltag-inhalt&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: teal;"&gt;&amp;lt;/document&amp;gt;&lt;/span&gt;

&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;document&lt;/span&gt;&lt;span style="color: teal;"&gt; &lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;xmlns&lt;/b&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;ns&lt;/b&gt;&lt;/span&gt;=&lt;span style="color: magenta;"&gt;"my-namespace"&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;leeres-xmltag&lt;/span&gt;&lt;span style="color: teal;"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-inhalt&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;&amp;amp;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;quot&lt;/b&gt;&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;/ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-inhalt&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: teal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;document&amp;gt;&lt;/span&gt; 
&lt;/pre&gt;
&lt;div&gt;
Die Frage "Worin unterscheiden sich die beiden XML-Dokumente?" ist nur auf den ersten
Blick einfach. Probieren wir die &lt;b&gt;XMLDIFF&lt;/b&gt;-Funktion einfach mal aus ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmldiff(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;leeres-xmltag&amp;gt;&amp;lt;/leeres-xmltag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;xmltag-inhalt&amp;gt;"&amp;lt;/xmltag-inhalt&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ), xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;ns:document xmlns:ns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:leeres-xmltag/&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:xmltag-inhalt&amp;gt;&amp;amp;quot;&amp;lt;/ns:xmltag-inhalt&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/ns:document&amp;gt;'&lt;/span&gt;
 )
) &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/ 

XMLDIFF(XMLTYPE('&amp;lt;DOCUMENTXMLNS="MY-NAMESPACE"&amp;gt;&amp;lt;LEERES-XMLTAG&amp;gt;&amp;lt;/LEERES-XMLTAG&amp;gt;&amp;lt;X
--------------------------------------------------------------------------------
&amp;lt;xd:xdiff xsi:schemaLocation="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt; &lt;a href="http://xmlns/"&gt;http://xmlns&lt;/a&gt;
.oracle.com/xdb/xdiff.xsd" xmlns:xd="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt;" xmln
s:ns="my-namespace" xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/a&gt;"&amp;gt;
  &amp;lt;?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-al
gorithm="global"?&amp;gt;
&amp;lt;/xd:xdiff&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
Die XMLDIFF-Funktion liefert zwar etwas zurück, bei genauer Betrachtung stellt man jedoch
 fest, dass das Tag &lt;b&gt;xd:xdiff&lt;/b&gt; leer ist - es wurden also keine Unterschiede zwischen den XML-Dokumenten
 festgestellt - und das ist auch richtig so. Denn die im Text sichtbaren Unterschiede haben nach
 dem XML-Standard keine Bedeutung. Ein leeres Tag darf sowohl &lt;b&gt;&amp;lt;tag&amp;gt;&amp;lt;/tag&amp;gt;&lt;/b&gt; als auch
 &lt;b&gt;&amp;lt;tag/&amp;gt;&lt;/b&gt; geschrieben werden. Gleiches gilt für Zeichenentities oder Namensräume. XMLDIFF
 ist also zunächst eine sehr interessante Funktion, um überhaupt Unterschiede zwischen XML-Dokumenten
 zu erkennen. Doch &lt;b&gt;XMLDIFF&lt;/b&gt; leistet noch mehr: Nehmen wir mal zwei XML-Dokumente, die sich tatsächlich
 unterscheiden ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmldiff(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text 1&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text 3&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ), xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;ns:document xmlns:ns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag&amp;gt;Text 1&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag&amp;gt;Text 2&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag option="a"&amp;gt;Text 3&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/ns:document&amp;gt;'&lt;/span&gt;
 )
) as xml_diff &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/ 

XML_DIFF
------------------------------------------------------------------------------------------
&amp;lt;xd:xdiff xsi:schemaLocation="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt; &lt;a href="http://xmlns.oracle.co/"&gt;http://xmlns.oracle.co&lt;/a&gt;
m/xdb/xdiff.xsd" xmlns:xd="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt;" xmlns:ns="my-namespace"
xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/a&gt;"&amp;gt;
  &amp;lt;?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-algorithm="g
lobal"?&amp;gt;&lt;span style="color: red;"&gt;
  &amp;lt;xd:update-node xd:node-type="text" xd:xpath="/ns:document[1]/ns:tag[2]/text()[1]"&amp;gt;
    &amp;lt;xd:content&amp;gt;Text 2&amp;lt;/xd:content&amp;gt;
  &amp;lt;/xd:update-node&amp;gt;
  &amp;lt;xd:append-node xd:node-type="element" xd:parent-xpath="/ns:document[1]"&amp;gt;
    &amp;lt;xd:content&amp;gt;
      &amp;lt;ns:tag option="a"&amp;gt;Text 3&amp;lt;/ns:tag&amp;gt;
    &amp;lt;/xd:content&amp;gt;
  &amp;lt;/xd:append-node&amp;gt;&lt;/span&gt;
&amp;lt;/xd:xdiff&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
Wie man sehen kann, werden die Unterschiede nicht einfach nur aufgelistet: Wie sein Unix-Vorbild
 &lt;b&gt;diff&lt;/b&gt; liefert auch &lt;b&gt;XMLDIFF&lt;/b&gt; Anweisungen zurück, wie man das erste XML-Dokument in das
 zweite überführen kann. Und ebenso wie das Ergebnis eines Unix &lt;b&gt;diff&lt;/b&gt; mit dem &lt;b&gt;patch&lt;/b&gt; Werkzeug
 auf andere XML-Dokumente angewendet werden kann, kann auch das Ergebnis von &lt;b&gt;XMLDIFF&lt;/b&gt; auf ein neues
 XML-Dokument mit Hilfe von &lt;b&gt;XMLPATCH&lt;/b&gt; angewendet werden. 
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; diff &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: blue;"&gt;-- Obiges SELECT XMLDIFF hier ...&lt;/span&gt;
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmlpatch(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text a&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text b&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ),
 xml_diff
) &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; diff
/ 
&lt;/pre&gt;
&lt;div&gt;
Die zuerst ermittelten XMLDIFF-Anweisungen ...
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Ändere den Text des zweiten XML-Tags &lt;b&gt;tag&lt;/b&gt; innerhalb von &lt;b&gt;document&lt;/b&gt; auf &lt;b&gt;Text 2&lt;/b&gt; &lt;/li&gt;
&lt;li&gt;Hänge innerhalb des Tags &lt;b&gt;document&lt;/b&gt; ein neues Tag &lt;b&gt;tag&lt;/b&gt; mit dem Inhalt &lt;b&gt;Text 3&lt;/b&gt; und dem Attribut &lt;b&gt;option="a"&lt;/b&gt; 
    an.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
... werden auf das im zweiten Parameter übergebene XML-Dokument angewendet. Das Ergebnis sieht in etwa wie folgt aus (die durch XMLPATCH ausgelösten Änderungen sind &lt;span style="color: red;"&gt;rot&lt;/span&gt; markiert):
&lt;/div&gt;
&lt;pre&gt;XMLPATCH
------------------------------------------------------------------------------------------
&amp;lt;document xmlns="my-namespace"&amp;gt;
  &amp;lt;tag&amp;gt;Text a&amp;lt;/tag&amp;gt;
  &amp;lt;tag&amp;gt;&lt;span style="color: red;"&gt;&lt;b&gt;Text 2&lt;/b&gt;&lt;/span&gt;&amp;lt;/tag&amp;gt;
  &lt;span style="color: red;"&gt;&lt;b&gt;&amp;lt;tag xmlns:ns="my-namespace" option="a"&amp;gt;Text 3&amp;lt;/tag&amp;gt;&lt;/b&gt;&lt;/span&gt;
&amp;lt;/document&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
Intern nutzt Oracle die Funktionen auch selbst - speziell für die &lt;i&gt;in Place Schema Evolution&lt;/i&gt; der
 XML DB sind sie wichtig. Allerdings kann man sie auch selbst nutzen, wenn es darum geht, Änderungen an
 einem XML-Dokument zu erkennen und diese ggfs. auf andere Dokumente zu übertragen ...
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions241.htm#CIHFDJAA" target="_blank"&gt;Oracle SQL Language Reference: XMLDIFF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions247.htm#CIHDAEEC" target="_blank"&gt;Oracle SQL Language Reference: XMLPATCH&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;div&gt;
Today I'd like to write something about two interesting SQL functions in the Oracle database: &lt;b&gt;XMLDIFF&lt;/b&gt; 
 and &lt;b&gt;XMLPATCH&lt;/b&gt;. I'll start with &lt;b&gt;XMLDIFF&lt;/b&gt; : As its name indicates - it compares XML documents. I'll illustrate this
 with an example ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;document&lt;/span&gt;&lt;span style="color: teal;"&gt; &lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;xmlns&lt;/b&gt;&lt;/span&gt;=&lt;span style="color: magenta;"&gt;"my-namespace"&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;empty-xmltag&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;/empty-xmltag&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-content&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;"&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;/xmltag-content&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: teal;"&gt;&amp;lt;/document&amp;gt;&lt;/span&gt;

&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;document&lt;/span&gt;&lt;span style="color: teal;"&gt; &lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;xmlns&lt;/b&gt;&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;ns&lt;/b&gt;&lt;/span&gt;=&lt;span style="color: magenta;"&gt;"my-namespace"&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;empty-xmltag&lt;/span&gt;&lt;span style="color: teal;"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-content&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;&amp;amp;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;quot&lt;/b&gt;&lt;/span&gt;&lt;span style="color: seagreen;"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: slateblue;"&gt;/ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;xmltag-content&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: teal;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: slateblue;"&gt;ns&lt;/span&gt;&lt;span style="color: blue;"&gt;:&lt;/span&gt;&lt;span style="color: teal;"&gt;document&amp;gt;&lt;/span&gt; 
&lt;/pre&gt;
&lt;div&gt;
What do you think? Are these XML documents equal ... or do they differ? This seems to be easy only at the first glance. But let's have &lt;b&gt;XMLDIFF&lt;/b&gt; do the work ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmldiff(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;empty-xmltag&amp;gt;&amp;lt;/empty-xmltag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;xmltag-content&amp;gt;"&amp;lt;/xmltag-content&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ), xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;ns:document xmlns:ns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:empty-xmltag/&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:xmltag-content&amp;gt;&amp;amp;quot;&amp;lt;/ns:xmltag-content&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/ns:document&amp;gt;'&lt;/span&gt;
 )
) &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/ 

XMLDIFF(XMLTYPE('&amp;lt;DOCUMENTXMLNS="MY-NAMESPACE"&amp;gt;&amp;lt;LEERES-XMLTAG&amp;gt;&amp;lt;/LEERES-XMLTAG&amp;gt;&amp;lt;X
--------------------------------------------------------------------------------
&amp;lt;xd:xdiff xsi:schemaLocation="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt; &lt;a href="http://xmlns/"&gt;http://xmlns&lt;/a&gt;
.oracle.com/xdb/xdiff.xsd" xmlns:xd="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt;" xmln
s:ns="my-namespace" xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/a&gt;"&amp;gt;
  &amp;lt;?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-al
gorithm="global"?&amp;gt;
&amp;lt;/xd:xdiff&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
The functions' output indicates that the documents are equal - from the XML point of view. And this
 makes sense since the XML standard allows different markup for the same content. Empty tags, for instance,
 can be expressed as a single tag with a trailing slash (&amp;lt;tag/&amp;gt;) as well as with an opening and a closing
 tag (&amp;lt;tag&amp;gt;&amp;lt;/tag&amp;gt;). Character entities like &amp;amp;quot; have the same meaning as the character itself (").
 And there are more examples beyond these two. So comparing XML documents means more than just comparing
 the text contents - the XML standard must be kept in mind, and &lt;b&gt;XMLDIFF&lt;/b&gt; does exactly this. In the next example
 we'll compare two documents which &lt;i&gt;are&lt;/i&gt; different; also from the "XML point of view". 
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmldiff(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text 1&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text 3&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ), xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;ns:document xmlns:ns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag&amp;gt;Text 1&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag&amp;gt;Text 2&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;ns:tag option="a"&amp;gt;Text 3&amp;lt;/ns:tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/ns:document&amp;gt;'&lt;/span&gt;
 )
) as xml_diff &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/ 

XML_DIFF
------------------------------------------------------------------------------------------
&amp;lt;xd:xdiff xsi:schemaLocation="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt; &lt;a href="http://xmlns.oracle.co/"&gt;http://xmlns.oracle.co&lt;/a&gt;
m/xdb/xdiff.xsd" xmlns:xd="&lt;a href="http://xmlns.oracle.com/xdb/xdiff.xsd"&gt;http://xmlns.oracle.com/xdb/xdiff.xsd&lt;/a&gt;" xmlns:ns="my-namespace"
xmlns:xsi="&lt;a href="http://www.w3.org/2001/XMLSchema-instance"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/a&gt;"&amp;gt;
  &amp;lt;?oracle-xmldiff operations-in-docorder="true" output-model="snapshot" diff-algorithm="g
lobal"?&amp;gt;&lt;span style="color: red;"&gt;
  &amp;lt;xd:update-node xd:node-type="text" xd:xpath="/ns:document[1]/ns:tag[2]/text()[1]"&amp;gt;
    &amp;lt;xd:content&amp;gt;Text 2&amp;lt;/xd:content&amp;gt;
  &amp;lt;/xd:update-node&amp;gt;
  &amp;lt;xd:append-node xd:node-type="element" xd:parent-xpath="/ns:document[1]"&amp;gt;
    &amp;lt;xd:content&amp;gt;
      &amp;lt;ns:tag option="a"&amp;gt;Text 3&amp;lt;/ns:tag&amp;gt;
    &amp;lt;/xd:content&amp;gt;
  &amp;lt;/xd:append-node&amp;gt;&lt;/span&gt;
&amp;lt;/xd:xdiff&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
We can see, that &lt;b&gt;XMLDIFF&lt;/b&gt; returns more than just the information that these two documents are
 different. As it's UNIX pendant &lt;b&gt;diff&lt;/b&gt; it returns a "delta" - instructions how to modify
 the first document in order to get the second. This output can be consumed by &lt;b&gt;XMLPATCH&lt;/b&gt;; as we'll see
 in the next example: We'll apply the "patch instruction" to another XML document ...
&lt;/div&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; diff &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: blue;"&gt;-- Obiges SELECT XMLDIFF hier ...&lt;/span&gt;
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; xmlpatch(
 xmltype(&lt;span style="color: magenta;"&gt;'&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;document xmlns="my-namespace"&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text a&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;   &amp;lt;tag&amp;gt;Text b&amp;lt;/tag&amp;gt;&lt;/span&gt;
&lt;span style="color: magenta;"&gt;  &amp;lt;/document&amp;gt;'&lt;/span&gt;
 ),
 xml_diff
) &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; diff
/ 
&lt;/pre&gt;
&lt;div&gt;
The "patching" instructions ...
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Modify the text contents of the second tag &lt;b&gt;tag&lt;/b&gt; within &lt;b&gt;document&lt;/b&gt; to &lt;b&gt;Text 2&lt;/b&gt; &lt;/li&gt;
&lt;li&gt;Append another tag &lt;b&gt;tag&lt;/b&gt; containing the text &lt;b&gt;Text 3&lt;/b&gt; and the attrbute &lt;b&gt;option="a"&lt;/b&gt; within &lt;b&gt;document&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
... are now being applied to another XML document which is (in this case) even different
 from the very first one (which we used to compare initially). The output of the &lt;b&gt;XMLPATCH&lt;/b&gt; operation
 is as follows ...
&lt;/div&gt;
&lt;pre&gt;XMLPATCH
------------------------------------------------------------------------------------------
&amp;lt;document xmlns="my-namespace"&amp;gt;
  &amp;lt;tag&amp;gt;Text a&amp;lt;/tag&amp;gt;
  &amp;lt;tag&amp;gt;&lt;span style="color: red;"&gt;&lt;b&gt;Text 2&lt;/b&gt;&lt;/span&gt;&amp;lt;/tag&amp;gt;
  &lt;span style="color: red;"&gt;&lt;b&gt;&amp;lt;tag xmlns:ns="my-namespace" option="a"&amp;gt;Text 3&amp;lt;/tag&amp;gt;&lt;/b&gt;&lt;/span&gt;
&amp;lt;/document&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
&lt;b&gt;XMLDIFF&lt;/b&gt; and &lt;b&gt;XMLPATCH&lt;/b&gt; are used internally by Oracle for the XML DB functionality of &lt;i&gt;In Place XML Schema
 Evolution&lt;/i&gt;. But one can (as we have seen) use them also for own purposes - the functions are interesting when
 it's about comparing XML documents and computing deltas between them.
 einem XML-Dokument zu erkennen und diese ggfs. auf andere Dokumente zu übertragen ...
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions241.htm#CIHFDJAA" target="_blank"&gt;Oracle SQL Language Reference: XMLDIFF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions247.htm#CIHDAEEC" target="_blank"&gt;Oracle SQL Language Reference: XMLPATCH&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-6139405337299966715?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/kFsJw59cVrU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/kFsJw59cVrU/xml-dokumente-mit-sql-vergleichen.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2012/01/xml-dokumente-mit-sql-vergleichen.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-7868347398587535553</guid><pubDate>Mon, 09 Jan 2012 09:00:00 +0000</pubDate><atom:updated>2012-01-09T10:00:13.725+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">login</category><category domain="http://www.blogger.com/atom/ns#">Java</category><category domain="http://www.blogger.com/atom/ns#">password</category><category domain="http://www.blogger.com/atom/ns#">user</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">authentication</category><category domain="http://www.blogger.com/atom/ns#">jdbc</category><category domain="http://www.blogger.com/atom/ns#">proxy</category><title>Login als User "A" - mit dem Password von "B": Proxy Authentication!</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Log in as user "A" - with the password of "B": Proxy Authentication&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;div&gt;
 Es ist in der Tat möglich: Ich kann mich an der Oracle-Datenbank als User "A" mit
 dem Passwort des Benutzers "B" anmelden - und das ist keine Sicherheitslücke. Ich 
 möchte dieses Blog-Posting dem Thema &lt;i&gt;Proxy Authentication&lt;/i&gt; widmen. Das kann man
 ganz besonders in einer dreischichtigen Webarchitektur gebrauchen. Denn dort werden Datenbankverbindungen
 nahezu immer statisch im Application Server konfiguriert ( &lt;i&gt;data-sources.xml&lt;/i&gt;). Wenn
 man in einer solchem Umgebung mit den Nutzerkonten der Datenbank arbeiten möchte, hat
 man ein Problem: Man kann sie nicht alle in der data-sources.xml einrichten; erstmal
 sind es oft zu viele und zweitens kann man die data-sources.xml nicht so einfach im 
 laufenden Betrieb ändern.  Die Lösung ist Proxy Authentication: Dabei wird  die
 Datenbankverbidnung 
 im Application Server fest mit einem technischen User und einem Passwort eingerichtet;
 der tatsächliche Datenbankuser, nach dem sich auch die Privilegien richten, wird
 zur Laufzeit festgelegt. Und das ganze funktioniert wie folgt: Zuerst brauchen wir
 einen technischen User &lt;b&gt;TECHUSER&lt;/b&gt; (mit Passwort &lt;b&gt;TECHUSER&lt;/b&gt;) und zwei "echte" User (&lt;b&gt;REALUSER1&lt;/b&gt; und
 &lt;b&gt;REALUSER2&lt;/b&gt;).
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; techuser &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; techuser
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; techuser
/

reate &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser1 &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; realuser1
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt;, &lt;font color="#6a5acd"&gt;resource&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; realuser1
/

reate &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser2 &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; realuser2
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt;, &lt;font color="#6a5acd"&gt;resource&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; realuser2
/
&lt;/pre&gt;
&lt;div&gt;
  Und damit die User in einer Anwendung unterscheidbar werden, bekommen Sie nun eine Kopie
  der &lt;b&gt;EMP&lt;/b&gt;-Tabelle, aber mit unterschiedlichen Inhalten ...
&lt;/div&gt;
&lt;pre&gt;
craete &lt;font color="#6a5acd"&gt;table&lt;/font&gt; realuser1.emp &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; scott.emp &lt;font color="#6a5acd"&gt;where&lt;/font&gt; deptno = &lt;font color="#ff00ff"&gt;10&lt;/font&gt;
/

craete &lt;font color="#6a5acd"&gt;table&lt;/font&gt; realuser2.emp &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; scott.emp &lt;font color="#6a5acd"&gt;where&lt;/font&gt; deptno = &lt;font color="#ff00ff"&gt;20&lt;/font&gt;
/
&lt;/pre&gt;
&lt;div&gt;
 Und jetzt geht es los: Zuerst muss man der Datenbank sagen, dass &lt;b&gt;TECHUSER&lt;/b&gt; die Erlaubnis
 bekommt, sich mit &lt;i&gt;seinem eigenen Passwort&lt;/i&gt; als &lt;b&gt;REALUSER1&lt;/b&gt; oder &lt;b&gt;REALUSER2&lt;/b&gt; "auszugeben". Man kann
 auch sagen: &lt;b&gt;TECHUSER&lt;/b&gt; wird der &lt;i&gt;Proxy User&lt;/i&gt; für die &lt;i&gt;Clients&lt;/i&gt; &lt;b&gt;REALUSER1&lt;/b&gt; und &lt;b&gt;REALUSER2&lt;/b&gt;.
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;alter&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser1 &lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; through techuser
/

&lt;font color="#804040"&gt;&lt;b&gt;alter&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser2 &lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; through techuser
/
&lt;/pre&gt;
&lt;div&gt;
 Der Setup lässt sich in der Dictionary View &lt;b&gt;PROXY_USERS&lt;/b&gt; auch überprüfen:
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; select * from proxy_users;

PROXY           CLIENT          AUT FLAGS
--------------- --------------- --- -----------------------------------
TECHUSER        REALUSER1       NO  PROXY MAY ACTIVATE ALL CLIENT ROLES
TECHUSER        REALUSER2       NO  PROXY MAY ACTIVATE ALL CLIENT ROLES
&lt;/pre&gt;
&lt;div&gt;
 Mit SQL*Plus kann man das jetzt schon ausprobieren:
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt;sqlplus.exe techuser[realuser1]/techuser

SQL*Plus: Release 11.1.0.6.0 - Production on Do Dez 22 16:17:30 2011

Copyright (c) 1982, 2007, Oracle.  All rights reserved.


Verbunden mit:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Oracle Label Security, OLAP, Data Mining
and Real Application Testing options

SQL&amp;gt; select user from dual;

USER
------------------------------
REALUSER1
&lt;/pre&gt;
&lt;div&gt;
 Man sieht sehr schön, dass Username und Passwort des &lt;b&gt;TECHUSER&lt;/b&gt; zum Login
 verwendet werden; in eckigen Klammern wird aber festgelegt, für wen die
 Datenbankverbindung eigentlich aufgemacht werden soll.
&lt;/div&gt;
&lt;div&gt;
 So weit, so gut, so einfach. Aber für eine dreischichtige Applikation nutzt das
 bis jetzt noch gar nichts. Schließlich kann man nicht einfach den "echten" User
 in eckige Klammern in die Definition der Datenbankverbindung eintragen, denn diese
 ist ja statisch. Der User, für den der Connect gelten soll, soll sich aber beliebig
 ändern können - also dynamisch sein. Also müssen wir in der Lage sein, den Usernamen,
 den man bei SQL*Plus in eckige Klammern setzt, per Java-Code zu setzen ... Schauen wir
 uns zunächst ein kleines Java-Testprogramm an: Es gibt zuerst den Namen des angemeldeten
 Users aus ( &lt;b&gt;select user from dual&lt;/b&gt;) und dann die Inhalte der &lt;b&gt;EMP&lt;/b&gt; Tabelle.
 Achtet darauf, dass Username und Passwort des &lt;b&gt;TECHUSER&lt;/b&gt; hart kodiert sind - und das wird
 so bleiben!
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.sql.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; oracle.jdbc.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.io.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.util.*;

&lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; proxyConnect {
  &lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; main(String args[]) &lt;font color="#2e8b57"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/font&gt; Exception {
    DriverManager.registerDriver(&lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; oracle.jdbc.OracleDriver());
    Connection con = DriverManager.getConnection(&lt;font color="#ff00ff"&gt;&amp;quot;jdbc:oracle:thin:@sccloud030:1521/orcl&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;);
    
&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * Code zum Setzen des Client-Usernamens HIER !!!&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;

    Statement stmt = &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
    ResultSet rs1 = &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
    stmt = con.createStatement();
    rs1 = stmt.executeQuery(&lt;font color="#ff00ff"&gt;&amp;quot;select user from dual&amp;quot;&lt;/font&gt;);
    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; (rs1.next()) {
      System.out.println(&lt;font color="#ff00ff"&gt;&amp;quot;Database userid: &amp;quot;&lt;/font&gt; + rs1.getString(&lt;font color="#ff00ff"&gt;1&lt;/font&gt;));
    }  
    rs1.close();
    stmt.close();

    stmt = con.createStatement();
    rs1 = stmt.executeQuery(&lt;font color="#ff00ff"&gt;&amp;quot;select * from emp&amp;quot;&lt;/font&gt;);
    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; (rs1.next()) {
      System.out.println(&lt;font color="#ff00ff"&gt;&amp;quot;EMPNO: &amp;quot;&lt;/font&gt; + rs1.getString(&lt;font color="#ff00ff"&gt;1&lt;/font&gt;) + &lt;font color="#ff00ff"&gt;&amp;quot; [&amp;quot;&lt;/font&gt;+rs1.getString(&lt;font color="#ff00ff"&gt;2&lt;/font&gt;)+&lt;font color="#ff00ff"&gt;&amp;quot;] - DEPTNO: &amp;quot;&lt;/font&gt;+rs1.getString(&lt;font color="#ff00ff"&gt;&amp;quot;DEPTNO&amp;quot;&lt;/font&gt;));
    }  
    rs1.close();
    stmt.close();
    con.close();
  }
} 
&lt;/pre&gt;
&lt;div&gt;
 Beim ersten Test sagt uns das Programm nur, dass wir als &lt;b&gt;TECHUSER&lt;/b&gt; verbunden sind und
 dass es keine &lt;b&gt;EMP&lt;/b&gt;-Tabelle gibt ...
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt; java.exe proxyConnect realuser1
Database userid: TECHUSER
Exception in thread "main" java.sql.SQLSyntaxErrorException: 
ORA-00942: Tabelle oder View nicht vorhanden
        at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:91)
        at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:112)
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:173)
        :
&lt;/pre&gt;
&lt;div&gt;
 Dann bauen wir jetzt den Code ein, der den "richtigen" User setzt. Tauscht die Zeilen ...
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * Code zum Setzen des Client-Usernamens HIER !!!&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;
&lt;/pre&gt;
&lt;div&gt;
  ... durch diese hier aus: Als Usernamen nehmen wir den ersten Parameter der Kommandozeile.
&lt;/div&gt;
&lt;pre&gt;
    Properties props = &lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; Properties();
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, args[&lt;font color="#ff00ff"&gt;0&lt;/font&gt;]);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
&lt;/pre&gt;
&lt;div&gt;
 Neu kompilieren und wieder ausführen. Und .. voilá:
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt; java proxyConnect realuser1
Database userid: REALUSER1
EMPNO: 7782 [CLARK] - DEPTNO: 10
EMPNO: 7839 [KING] - DEPTNO: 10
EMPNO: 7934 [MILLER] - DEPTNO: 10

D:\&amp;gt; java proxyConnect realuser2
Database userid: REALUSER2
EMPNO: 7369 [SMITH] - DEPTNO: 20
EMPNO: 7566 [JONES] - DEPTNO: 20
EMPNO: 7788 [SCOTT] - DEPTNO: 20
EMPNO: 7876 [ADAMS] - DEPTNO: 20
EMPNO: 7902 [FORD] - DEPTNO: 20
&lt;/pre&gt;
&lt;div&gt;
 Nur durch die Angabe des Namens wird nun festgelegt, als welcher User die Datenbanksession 
 laufen soll.  Damit kann ein Java-Programm (bspw. in einem Application Server) mit einer statischen
 Datasource-Definition dennoch dynamisch den Datenbankuser wechseln. Denn eine bestehende 
 Proxy-Verbindung kann geschlossen werden, um danach &lt;i&gt;auf der gleichen "physikalischen" Datenbankverbindung&lt;/i&gt;
 eine neue Proxy-Verbindung für einen anderen User zu öffnen. Im folgenden Code
 habe ich das mal illustriert - zur besseren Übersicht habe ich die Datenbankaktionen
 entfernt und gegen den Pseudocall auf &lt;b&gt;erledigeDatenbankaktionen()&lt;/b&gt; ausgetauscht.
&lt;/div&gt;
&lt;pre&gt;
  &lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; main(String args[]) &lt;font color="#2e8b57"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/font&gt; Exception {
    &lt;font color="#0000ff"&gt;// Physikalische Verbindung öffnen als TECHUSER&lt;/font&gt;
    DriverManager.registerDriver(&lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; oracle.jdbc.OracleDriver());
    Connection con = DriverManager.getConnection(&lt;font color="#ff00ff"&gt;&amp;quot;jdbc:oracle:thin:@sccloud030:1521/orcl&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;);
    
    &lt;font color="#0000ff"&gt;// Proxy-Verbindung für User REALUSER1 öffnen, etwas tun und schließen&lt;/font&gt;
    Properties props = &lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; Properties();
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot;realuser1&amp;quot;&lt;/font&gt;);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
    erledigeDatenbankaktionen(con);
    ((OracleConnection)con).close(OracleConnection.PROXY_SESSION); 

    &lt;font color="#0000ff"&gt;// Die physikalische Verbindung ist immer noch offen ...&lt;/font&gt;
    &lt;font color="#0000ff"&gt;// Proxy-Verbindung für User REALUSER2 öffnen, etwas tun und schließen&lt;/font&gt;
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot;realuser2&amp;quot;&lt;/font&gt;);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
    erledigeDatenbankaktionen(con);
    ((OracleConnection)con).close(OracleConnection.PROXY_SESSION); 

    &lt;font color="#0000ff"&gt;// Physikalische Verbindung schließen&lt;/font&gt;
    con.close();
  }
&lt;/pre&gt;
&lt;div&gt;
 Beim Umstieg von Client/Server-
 zu Webanwendungen ist ein solches Vorgehen hochinteressant.
&lt;/div&gt;
&lt;div&gt;
 Wichtig ist, dass &lt;b&gt;REALUSER1&lt;/b&gt; bzw.  &lt;b&gt;REALUSER2&lt;/b&gt; immer noch das &lt;b&gt;CREATE SESSION&lt;/b&gt;-Privileg brauchen; auch
 darf der Account nicht gelockt sein. Es ist aber durchaus möglich, direkte Connects zu unterbinden - 
 dazu muss man "nur" das Passwort auf einen nicht ermittelbaren Wert setzen ...
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; alter user realuser1 identified by values 'Hallo'
&lt;/pre&gt;
&lt;div&gt;
 Nun wird der Text "&lt;b&gt;Hallo&lt;/b&gt;" als Hashwert in die Oracle-Passworttabelle geschrieben - ein Connect als
 &lt;b&gt;REALUSER1&lt;/b&gt; ist nun theoretisch möglich: wenn man das Passwort herausbekommt, dessen Hashwert
 "&lt;b&gt;Hallo&lt;/b&gt;" ergibt. Defacto jedoch kann man sich nur noch über den &lt;b&gt;TECHUSER&lt;/b&gt; als &lt;b&gt;REALUSER1&lt;/b&gt; anmelden. 
 Aber auch ein Parallelbetrieb mit direkten und Proxy-Verbindungen ist natürlich problemlos
 machbar.
&lt;/div&gt;
&lt;div&gt;
 Mehr zur Proxy Authentication in der Dokumentation: Dazu sind zwei Links wichtig:
 &lt;ul&gt;
  &lt;li&gt;Security Guide: Using a Middle Tier Server for Proxy Authentication&lt;br/&gt;
      &lt;a href="http://docs.oracle.com/cd/E11882_01/network.112/e16543/authentication.htm#i1010326" target="_blank"&gt;http://docs.oracle.com/cd/E11882_01/network.112/e16543/authentication.htm#i1010326&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;JDBC Developer's Guide: Proxy Authentication&lt;br/&gt;
  &lt;a href="http://docs.oracle.com/cd/E11882_01/java.112/e16548/proxya.htm#CHDHHAAD" target="_blank"&gt;http://docs.oracle.com/cd/E11882_01/java.112/e16548/proxya.htm#CHDHHAAD&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;div&gt;
 Yes - it is possible: You can connect to the Oracle database as say: User "A" with
 the password of User "B" - and that is &lt;i&gt;not&lt;/i&gt; a security vulnerability.  In this
 blog posting I'd like to elaborate a bit on &lt;i&gt;proxy authentication&lt;/i&gt; - this feature
 is particular useful in three-tier-applications. Database connections are typically
 part of the static application server configuration (&lt;i&gt;"data-sources.xml"&lt;/i&gt;).
 And when such a java environments want to use the user accounts in the database
 there is a problem: We cannot add each individual user to the datasource configuration. 
 The first arguments is, that there might be just too many users - the second one is that 
 changes to data-sources.xml are often not possible without downtime.
 So we need a connection using one single technical user's credentials and the ability
 to set the desired username at runtime.
 And that is all what proxy authentication is about. We'll start with creating  
 the technical user (&lt;b&gt;TECHUSER&lt;/b&gt;) and two "real" user accounts (&lt;b&gt;REALUSER1&lt;/b&gt; and &lt;b&gt;REALUSER2&lt;/b&gt;).
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; techuser &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; techuser
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; techuser
/

reate &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser1 &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; realuser1
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt;, &lt;font color="#6a5acd"&gt;resource&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; realuser1
/

reate &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser2 &lt;font color="#6a5acd"&gt;identified&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; realuser2
/

&lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt;, &lt;font color="#6a5acd"&gt;resource&lt;/font&gt; &lt;font color="#6a5acd"&gt;to&lt;/font&gt; realuser2
/
&lt;/pre&gt;
&lt;div&gt;
  &lt;b&gt;REALUSER1&lt;/b&gt; and &lt;b&gt;REALUSER2&lt;/b&gt; now get a copy of the &lt;b&gt;EMP&lt;/b&gt; table with different contents: we 
  want to differentiate between the two later on.
&lt;/div&gt;
&lt;pre&gt;
craete &lt;font color="#6a5acd"&gt;table&lt;/font&gt; realuser1.emp &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; scott.emp &lt;font color="#6a5acd"&gt;where&lt;/font&gt; deptno = &lt;font color="#ff00ff"&gt;10&lt;/font&gt;
/

craete &lt;font color="#6a5acd"&gt;table&lt;/font&gt; realuser2.emp &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; * &lt;font color="#6a5acd"&gt;from&lt;/font&gt; scott.emp &lt;font color="#6a5acd"&gt;where&lt;/font&gt; deptno = &lt;font color="#ff00ff"&gt;20&lt;/font&gt;
/
&lt;/pre&gt;
&lt;div&gt;
 Now we declare &lt;b&gt;TECHUSER&lt;/b&gt; as the &lt;i&gt;proxy user&lt;/i&gt; for &lt;b&gt;REALUSER1&lt;/b&gt; and &lt;b&gt;REALUSER2&lt;/b&gt;. This is kind of
 a GRANT statement. The privilege to act as (&lt;i&gt;the clients&lt;/i&gt;) REALUSER1 or REALUSER2 is granted to TECHUSER. 
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;alter&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser1 &lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; through techuser
/

&lt;font color="#804040"&gt;&lt;b&gt;alter&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;user&lt;/font&gt; realuser2 &lt;font color="#804040"&gt;&lt;b&gt;grant&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; through techuser
/
&lt;/pre&gt;
&lt;div&gt;
 You might review this in the dictionary view &lt;b&gt;PROXY_USERS&lt;/b&gt;:
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; select * from proxy_users;

PROXY           CLIENT          AUT FLAGS
--------------- --------------- --- -----------------------------------
TECHUSER        REALUSER1       NO  PROXY MAY ACTIVATE ALL CLIENT ROLES
TECHUSER        REALUSER2       NO  PROXY MAY ACTIVATE ALL CLIENT ROLES
&lt;/pre&gt;
&lt;div&gt;
 A first test with SQL*Plus:
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt;sqlplus.exe techuser[realuser1]/techuser

SQL*Plus: Release 11.1.0.6.0 - Production on Do Dez 22 16:17:30 2011

Copyright (c) 1982, 2007, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Oracle Label Security, OLAP, Data Mining
and Real Application Testing options

SQL&amp;gt; select user from dual;

USER
------------------------------
REALUSER1
&lt;/pre&gt;
&lt;div&gt;
 TECHUSER used his own credentials to log in. But the user &lt;i&gt;as which&lt;/i&gt; the
 connection should be established was provided within the brackets. In SQL*Plus it 
 is that easy: We &lt;i&gt;logged in&lt;/i&gt; as &lt;b&gt;TECHUSER/techuser&lt;/b&gt; and we now &lt;i&gt;are&lt;/i&gt; &lt;b&gt;REALUSER1&lt;/b&gt;.
&lt;/div&gt;
&lt;div&gt;
 So far  - so good. But for real world environments this is virtually useless - no end
 user connects with SQL*Plus. And we cannot add the brackets to the static datasource definition
 in the application server: we need to set the client user dynamically with some code - and
 the following example will show how to do this. First I have a little testing program in
 java language. It first connects to the database with &lt;i&gt;hardcoded&lt;/i&gt; &lt;b&gt;TECHUSER&lt;/b&gt; credentials,
 then it looks up "as who" it is connected and finally it shows the contents of the &lt;b&gt;EMP&lt;/b&gt; table.
 Again: The username and password arguments in the call to &lt;b&gt;DriverManager.getConnection&lt;/b&gt; are 
 hard coded and this will not change!
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.sql.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; oracle.jdbc.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.io.*;
&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.util.*;

&lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; proxyConnect {
  &lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; main(String args[]) &lt;font color="#2e8b57"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/font&gt; Exception {
    DriverManager.registerDriver(&lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; oracle.jdbc.OracleDriver());
    Connection con = DriverManager.getConnection(&lt;font color="#ff00ff"&gt;&amp;quot;jdbc:oracle:thin:@sccloud030:1521/orcl&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;);
    
&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * The java code to set the client username goes here !!!&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;

    Statement stmt = &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
    ResultSet rs1 = &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
    stmt = con.createStatement();
    rs1 = stmt.executeQuery(&lt;font color="#ff00ff"&gt;&amp;quot;select user from dual&amp;quot;&lt;/font&gt;);
    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; (rs1.next()) {
      System.out.println(&lt;font color="#ff00ff"&gt;&amp;quot;Database userid: &amp;quot;&lt;/font&gt; + rs1.getString(&lt;font color="#ff00ff"&gt;1&lt;/font&gt;));
    }  
    rs1.close();
    stmt.close();

    stmt = con.createStatement();
    rs1 = stmt.executeQuery(&lt;font color="#ff00ff"&gt;&amp;quot;select * from emp&amp;quot;&lt;/font&gt;);
    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; (rs1.next()) {
      System.out.println(&lt;font color="#ff00ff"&gt;&amp;quot;EMPNO: &amp;quot;&lt;/font&gt; + rs1.getString(&lt;font color="#ff00ff"&gt;1&lt;/font&gt;) + &lt;font color="#ff00ff"&gt;&amp;quot; [&amp;quot;&lt;/font&gt;+rs1.getString(&lt;font color="#ff00ff"&gt;2&lt;/font&gt;)+&lt;font color="#ff00ff"&gt;&amp;quot;] - DEPTNO: &amp;quot;&lt;/font&gt;+rs1.getString(&lt;font color="#ff00ff"&gt;&amp;quot;DEPTNO&amp;quot;&lt;/font&gt;));
    }  
    rs1.close();
    stmt.close();
    con.close();
  }
} 
&lt;/pre&gt;
&lt;div&gt;
 This program so far does not know anything about proxy connections - the results are
 therefore straightforward: We are connected as &lt;b&gt;TECHUSER&lt;/b&gt; and there is no &lt;b&gt;EMP&lt;/b&gt; table.
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt; java.exe proxyConnect realuser1
Database userid: TECHUSER
Exception in thread "main" java.sql.SQLSyntaxErrorException: 
ORA-00942: table or view does not exist.
        at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:91)
        at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:112)
        at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:173)
        :
&lt;/pre&gt;
&lt;div&gt;
 Now we'll add the "magic" lines of code to set the client username. Exchange those three lines ...
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * The java code to set the client username goes here !!!&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;
&lt;/pre&gt;
&lt;div&gt;
  ... with these - we'll take the first command line argument as the username.
&lt;/div&gt;
&lt;pre&gt;
    Properties props = &lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; Properties();
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, args[&lt;font color="#ff00ff"&gt;0&lt;/font&gt;]);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
&lt;/pre&gt;
&lt;div&gt;
 Recompile and test again - and ... it works. 
&lt;/div&gt;
&lt;pre&gt;
D:\&amp;gt; java proxyConnect realuser1
Database userid: REALUSER1
EMPNO: 7782 [CLARK] - DEPTNO: 10
EMPNO: 7839 [KING] - DEPTNO: 10
EMPNO: 7934 [MILLER] - DEPTNO: 10

D:\&amp;gt; java proxyConnect realuser2
Database userid: REALUSER2
EMPNO: 7369 [SMITH] - DEPTNO: 20
EMPNO: 7566 [JONES] - DEPTNO: 20
EMPNO: 7788 [SCOTT] - DEPTNO: 20
EMPNO: 7876 [ADAMS] - DEPTNO: 20
EMPNO: 7902 [FORD] - DEPTNO: 20
&lt;/pre&gt;
&lt;div&gt;
 Only by giving the username on the command line we connected as &lt;b&gt;REALUSER1&lt;/b&gt; or &lt;b&gt;REALUSER2&lt;/b&gt; - the
 password always was &lt;b&gt;TECHUSER&lt;/b&gt;'s one. With this approach a java program can obtain a database
 connection from its application server, set the client username and connect to the
 database as another "real" user. And this proxy connection can be changed while the
 main "physical" connection remains open. The following code shows this - for clarity
 I have removed the actual database actions and replaced them with the
 pseudo method &lt;i&gt;doDatabaseActions()&lt;/i&gt;.
&lt;/div&gt;
&lt;pre&gt;
  &lt;font color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; main(String args[]) &lt;font color="#2e8b57"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/font&gt; Exception {
    &lt;font color="#0000ff"&gt;// open the physical connection as TECHUSER&lt;/font&gt;
    DriverManager.registerDriver(&lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; oracle.jdbc.OracleDriver());
    Connection con = DriverManager.getConnection(&lt;font color="#ff00ff"&gt;&amp;quot;jdbc:oracle:thin:@sccloud030:1521/orcl&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;,&lt;font color="#ff00ff"&gt;&amp;quot;techuser&amp;quot;&lt;/font&gt;);
    
    &lt;font color="#0000ff"&gt;// open the proxy connection for REALUSER1, do something and close&lt;/font&gt;
    Properties props = &lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; Properties();
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot;realuser1&amp;quot;&lt;/font&gt;);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
    doDatabaseActions(con);
    ((OracleConnection)con).close(OracleConnection.PROXY_SESSION); 

    &lt;font color="#0000ff"&gt;// the physical connection is still open ...&lt;/font&gt;
    &lt;font color="#0000ff"&gt;// now open the proxy connection for REALUSER2, do something and close&lt;/font&gt;
    props.put(&lt;font color="#ff00ff"&gt;&amp;quot;PROXY_USER_NAME&amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot;realuser2&amp;quot;&lt;/font&gt;);
    ((OracleConnection)con).openProxySession(OracleConnection.PROXYTYPE_USER_NAME, props);  
    doDatabaseActions(con);
    ((OracleConnection)con).close(OracleConnection.PROXY_SESSION); 

    &lt;font color="#0000ff"&gt;// finally close the physical connection&lt;/font&gt;
    con.close();
  }
&lt;/pre&gt;
&lt;div&gt;
 When client/server applications are moving to a web environment,
 this technology gets highly interesting - because the application can keep its existing
 user, role and security model and move on to the web technology where all database connections 
 are done with one technical user.
&lt;/div&gt;
&lt;div&gt;
 &lt;b&gt;REALUSER1&lt;/b&gt; or &lt;b&gt;REALUSER2&lt;/b&gt; still need their &lt;b&gt;CREATE SESSION&lt;/b&gt; privilege - the accounts also
 &lt;i&gt;must&lt;/i&gt; exist in the database and must not be locked. But (if needed) you actually can "forbid"
 direct connections by setting the password to an "impossible" value ...
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; alter user realuser1 identified by values 'Hello'
&lt;/pre&gt;
&lt;div&gt;
 The &lt;b&gt;REALUSER1&lt;/b&gt; account is still open and connects are possible in theory. But since the
 &lt;b&gt;IDENTIFIED BY VALUES&lt;/b&gt; command directly wrote "&lt;b&gt;Hello&lt;/b&gt;" into the password table, one would
 have to find out one of the password - which evaluate to "&lt;b&gt;Hello&lt;/b&gt;" during the hashing process - I'll 
 say it that way: at least very difficult. Connections as &lt;b&gt;REALUSER1&lt;/b&gt; now are only possible as
 connections through &lt;b&gt;TECHUSER&lt;/b&gt;. But it is also possible to have both direct and proxy connections 
 in parallel.
&lt;/div&gt;
&lt;div&gt;
 More about proxy authentication is in the documentation:
 &lt;ul&gt;
  &lt;li&gt;Security Guide: Using a Middle Tier Server for Proxy Authentication&lt;br/&gt;
      &lt;a href="http://docs.oracle.com/cd/E11882_01/network.112/e16543/authentication.htm#i1010326" target="_blank"&gt;http://docs.oracle.com/cd/E11882_01/network.112/e16543/authentication.htm#i1010326&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;JDBC Developer's Guide: Proxy Authentication&lt;br/&gt;
  &lt;a href="http://docs.oracle.com/cd/E11882_01/java.112/e16548/proxya.htm#CHDHHAAD" target="_blank"&gt;http://docs.oracle.com/cd/E11882_01/java.112/e16548/proxya.htm#CHDHHAAD&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-7868347398587535553?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/AkiS4pi1dMM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/AkiS4pi1dMM/login-als-user-mit-dem-password-von-b.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2012/01/login-als-user-mit-dem-password-von-b.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-197401508026736516</guid><pubDate>Thu, 22 Dec 2011 16:24:00 +0000</pubDate><atom:updated>2011-12-22T17:26:02.749+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">oracle414</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Zum Ende von 2011: Oracle 4.1.4 ...</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;At the end of 2011: Oracle 4.1.4&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;div&gt;
Das letzte Blog Posting in 2011 soll nichts technisches mehr sein - die letzten Tage im 
 Jahr kann man ja ein wenig zur Ruhe kommen. Daher hier nur ein paar Screenshots, die
 ich gemacht habe, als ich eine alte Oracle 4.1.4 nochmals installiert habe. Kein XML, kein
 PL/SQL, kein Oracle TEXT, kein APEX ... aber EMP ... und DEPT!
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-biV4NRKqvuI/TvNZhunXALI/AAAAAAAAAJk/JYNDaB1fCE4/s1600/ora414-1.png" imageanchor="1"&gt;&lt;img border="0" height="214" src="http://3.bp.blogspot.com/-biV4NRKqvuI/TvNZhunXALI/AAAAAAAAAJk/JYNDaB1fCE4/s320/ora414-1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-xMV4rvnM_Z8/TvNZlJMT00I/AAAAAAAAAJw/XPk2tU1GVVQ/s1600/ora414-2.png" imageanchor="1"&gt;&lt;img border="0" height="214" src="http://1.bp.blogspot.com/-xMV4rvnM_Z8/TvNZlJMT00I/AAAAAAAAAJw/XPk2tU1GVVQ/s320/ora414-2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Frohe Weihnachten und ein gutes neues Jahr 2012!&lt;/b&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;div&gt;
My last blog posting in 2011 will not contain technical stuff. The last few days in a
 year are a good chance to relax a bit - and so I just would like to post some screenshots
 which I have taken while installing the Oracle 4.1.4 files which I found a couple of weeks ago.
 No XML, no PL/SQL, no Oracle TEXT, no APEX ... but EMP ... and DEPT.
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-biV4NRKqvuI/TvNZhunXALI/AAAAAAAAAJk/JYNDaB1fCE4/s1600/ora414-1.png" imageanchor="1"&gt;&lt;img border="0" height="214" src="http://3.bp.blogspot.com/-biV4NRKqvuI/TvNZhunXALI/AAAAAAAAAJk/JYNDaB1fCE4/s320/ora414-1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-xMV4rvnM_Z8/TvNZlJMT00I/AAAAAAAAAJw/XPk2tU1GVVQ/s1600/ora414-2.png" imageanchor="1"&gt;&lt;img border="0" height="214" src="http://1.bp.blogspot.com/-xMV4rvnM_Z8/TvNZlJMT00I/AAAAAAAAAJw/XPk2tU1GVVQ/s320/ora414-2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Merry Christmas and a happy new year 2012!&lt;/b&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-197401508026736516?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/k5Q4Fi-RUNk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/k5Q4Fi-RUNk/zum-ende-von-2011-oracle-414.html</link><author>noreply@blogger.com (Carsten Czarski)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-biV4NRKqvuI/TvNZhunXALI/AAAAAAAAAJk/JYNDaB1fCE4/s72-c/ora414-1.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/12/zum-ende-von-2011-oracle-414.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-235489401723484321</guid><pubDate>Wed, 07 Dec 2011 15:39:00 +0000</pubDate><atom:updated>2011-12-08T14:38:45.990+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">analytic function</category><category domain="http://www.blogger.com/atom/ns#">ratio_to_report</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Anteile in Prozent in einem Bericht kalkulieren - nur mit SQL!</title><description>&lt;div lang="en" style="color: #cc6600; display: none;"&gt;
How to calculate "ratio to report" in SQL&lt;/div&gt;
&lt;div lang="de"&gt;
Heute morgen erreichte mich eine SQL-Frage - und das Problem taucht sicherlich öfter auf,
 daher veröffentliche ich meine Antwort hier für alle. Ausgangspunkt ist eine Tabelle.
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;|art   |anzahl     |kosten       |anteil    |
|------|-----------|-------------------------
| A    |        55 |       16,95 |     null |
| B    |        55 |        5,45 |     null |
| C    |        55 |        3,20 |     null |
| D    |        55 |        1,95 |     null |
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Die rechte Spalte &lt;b&gt;anteil&lt;/b&gt; soll nun den prozentualen (hier:) Kostenanteil der Zeile im
 Verhältnis zur Summe über alle Zeilen enthalten. Damit ich die Tabelle nicht neu anlegen
 muss, übertrage ich das Beispiel auf die uns allen bekannte Tabelle &lt;b&gt;EMP&lt;/b&gt;: Wir wollen
 also zu jeder das Gehalt als prozentualen Anteil  an der Gesamt-Gehaltssumme ausgedrückt
 sehen. Fangen wir mit dem "klassischen" Ansatz an ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; summe &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; sum(sal) sal &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.sal,
  e.sal / s.sal * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e, summe s
/ 

ENAME            SAL  ANTEIL
---------- --------- -------
SMITH           1280    2,76
ALLEN           2560    5,51
WARD            2000    4,31
JONES           4760   10,25
MARTIN          2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Diese Lösung dürfte auf nahezu allen Datenbanksystemen funktionieren - mit der &lt;b&gt;WITH&lt;/b&gt;-Klausel
 wird zunächst die Gehaltsumme ermittelt und dann per Join in die eigentliche Abfrage
 integriert. Wenn man den Gehaltsanteil pro Abteilung (&lt;b&gt;DEPTNO&lt;/b&gt;) sehen möchte, müsste man
 die Abfrage in der WITH-Klausel mit einem &lt;b&gt;GROUP BY&lt;/b&gt; versehen und eine Joinbedingung in
 die Hauptabfrage einbauen ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; summe &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; deptno, sum(sal) sal &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp
  &lt;span style="color: slateblue;"&gt;group&lt;/span&gt; &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  e.sal / s.sal * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil_dept
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e join  summe s &lt;span style="color: slateblue;"&gt;on&lt;/span&gt; (e.deptno = s.deptno)
/

ENAME          DEPTNO       SAL ANTEIL_DEPT
---------- ---------- --------- -----------
SMITH              20      1280        7,36
ALLEN              30      2560       17,02
WARD               30      2000       13,30
JONES              20      4760       27,36
MARTIN             30      2000       13,30
BLAKE              30      4560       30,32
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
So weit - so gut. Aber es geht auch wesentlich schöner: Setzt man analytische
 Funktionen ein, so kann man sich die Inline-View sparen - das macht dann alles
 die Datenbank ... so könnte man die analytische Variante von &lt;b&gt;SUM&lt;/b&gt; wie folgt verwenden.
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  (e.sal / sum(sal) over ()) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/
ENAME          DEPTNO       SAL  ANTEIL
---------- ---------- --------- -------
SMITH              20      1280    2,76
ALLEN              30      2560    5,51
WARD               30      2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Hier wird &lt;b&gt;SUM&lt;/b&gt; &lt;i&gt;ohne&lt;/i&gt; &lt;b&gt; GROUP BY&lt;/b&gt; verwendet - einfach weil es die analytische Variante
 ist. Das sog. &lt;i&gt;Query Window&lt;/i&gt;, welches angibt, über welche Zeilen das Aggregat
 gebildet werden soll, wird in der &lt;b&gt;OVER&lt;/b&gt; -Klausel festgelegt. Und wenn die Klammern 
 leer sind, heißt das soviel wie "über alles". Aber auch die Variante mit den
 Anteil pro Abteilung ist machbar.
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  (e.sal / sum(sal) over (partition &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno)) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/

ENAME          DEPTNO       SAL  ANTEIL
---------- ---------- --------- -------
CLARK              10      3920   28,00
KING               10      8000   57,14
MILLER             10      2080   14,86
JONES              20      4760   27,36
FORD               20      4800   27,59
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Jetzt steht etwas in der OVER()-Klausel drin. Mit &lt;b&gt;PARTITION BY&lt;/b&gt; wird festgelegt, dass
 das Aggregat (die Summe) nach Abteilungen berechnet werden soll. Das Schlüsselwort
 PARTITION BY ist übrigens &lt;i&gt;nicht&lt;/i&gt; zu verwechseln mit der Tabellenpartitionierung und 
 im Gegensatz zu dieser erfordern die analytischen Funktionen keine separaten Lizenzen.
 Aber es geht sogar noch einfacher: Denn für diese Aufgabe gibt es eine spezielle
 analytische Funktion: &lt;b&gt;RATIO_TO_REPORT&lt;/b&gt;.
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  ratio_to_report(e.sal) over () * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/

ENAME          DEPTNO        SAL  ANTEIL
---------- ---------- ---------- -------
SMITH              20       1280    2,76
ALLEN              30       2560    5,51
WARD               30       2000    4,31
JONES              20       4760   10,25
MARTIN             30       2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Und natürlich geht auch hier die &lt;b&gt;PARTITION BY&lt;/b&gt;-Klausel ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  ratio_to_report(e.sal) over (partition &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; anteil
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Analytische Funktionen lohnen auf jeden Fall eine genauere Betrachtung. Jeder, der mit
 SQL und der Oracle-Datenbanken arbeitet, sollte sie kennen. Neben den hier beschriebenen
 Dingen lassen sich damit auch gleitende Durchschnitte, fortlaufende Summen, Rankings und
 andere Dinge, die sonst recht kompliziertes SQL mit Subselects erfordern, mit einfachen Funktionsaufrufen 
 erledigen. Zum Nachlesen ist hier noch ein &lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions004.htm#i81407" target="_blank"&gt;Link zur Dokumentation&lt;/a&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
This morning I got a SQL question - nothing difficult - but I think, this kind of requirement
 is more frequent, and therefore I decided to publish the answer for everyone. The question
 is based on table data (as always) ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;|art   |count      |cost         |cost_share |
|------|-----------|--------------------------
| A    |        55 |       16,95 |      null |
| B    |        55 |        5,45 |      null |
| C    |        55 |        3,20 |      null |
| D    |        55 |        1,95 |      null |
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The right column cost_share should contain the row's share of total cost - expressed in percent. So
 the cost column needs to be divided by &lt;b&gt;SUM(COST)&lt;/b&gt; over all rows. I'm lazy: so instead of creating
 this table I decided to solve the problem  for the &lt;b&gt;SAL&lt;/b&gt; column in the well known &lt;b&gt;EMP&lt;/b&gt; table. 
 Let's start with "classic" SQL.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; total &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; sum(sal) sal &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.sal,
  e.sal / s.sal * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e, total s
/ 

ENAME            SAL   SHARE
---------- --------- -------
SMITH           1280    2,76
ALLEN           2560    5,51
WARD            2000    4,31
JONES           4760   10,25
MARTIN          2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
This query should work on almost every database system. First we compute the total
 salary amount with an &lt;i&gt;inline view&lt;/i&gt; using the &lt;b&gt;WITH&lt;/b&gt; clause. This inline view
 will be joined in the main query. It returns only one row, so we don't need any
 join criteria and we can access the total salary amount just like a table column. And
 this can be extended - if we'd like to see the salary share expressed as "&lt;i&gt;percentage of the 
 department total&lt;/i&gt;",
 we add a &lt;b&gt;GROUP BY&lt;/b&gt; to the inline view and extend the join in the main query as follows ... 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;with&lt;/span&gt; total &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; (
  &lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; deptno, sum(sal) sal &lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp
  &lt;span style="color: slateblue;"&gt;group&lt;/span&gt; &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno
)
&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  e.sal / s.sal * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share_dept
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e join  total s &lt;span style="color: slateblue;"&gt;on&lt;/span&gt; (e.deptno = s.deptno)
/

ENAME          DEPTNO       SAL  SHARE_DEPT
---------- ---------- --------- -----------
SMITH              20      1280        7,36
ALLEN              30      2560       17,02
WARD               30      2000       13,30
JONES              20      4760       27,36
MARTIN             30      2000       13,30
BLAKE              30      4560       30,32
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
So far, so good. This works, but there are much more elegant approaches. Now I'll
 drop my inline view and use the &lt;span class="italicbodycopy"&gt;analytic variant&lt;/span&gt; 
 of &lt;b&gt;SUM()&lt;/b&gt; for the problem. 
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  (e.sal / sum(sal) over ()) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/
ENAME          DEPTNO       SAL   SHARE
---------- ---------- --------- -------
SMITH              20      1280    2,76
ALLEN              30      2560    5,51
WARD               30      2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
This query uses &lt;b&gt;SUM&lt;/b&gt; &lt;i&gt;without&lt;/i&gt; &lt;b&gt;GROUP BY&lt;/b&gt;, because it's the &lt;i&gt;analytic&lt;/i&gt; SUM function. 
 The &lt;i&gt;query window&lt;/i&gt; ,
 which defines the rows to be aggregated, is specified in the &lt;b&gt;OVER()&lt;/b&gt; clause. The aggregate
 is then calculated to each row of the query result set. An empty OVER clause means as much
 as "over all rows". But we can also do the calculation on the department level.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  (e.sal / sum(sal) over (partition &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno)) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/

ENAME          DEPTNO       SAL   SHARE
---------- ---------- --------- -------
CLARK              10      3920   28,00
KING               10      8000   57,14
MILLER             10      2080   14,86
JONES              20      4760   27,36
FORD               20      4800   27,59
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Now we have the keywords &lt;b&gt;PARTITION BY&lt;/b&gt; inside the OVER() clause. So the aggregate
 is being computed for each department.  &lt;i&gt;Don't confuse&lt;/i&gt; this PARTITION BY clause 
 with table partitioning. Opposed to the latter, PARTITION BY
 within an analytic function has nothing to do with table storage and does not
 require an additional license. But we can solve the original problem even more
 elegant. Why? Because there is a special function for this purpose: &lt;b&gt;RATIO_TO_REPORT&lt;/b&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  ratio_to_report(e.sal) over () * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/

ENAME          DEPTNO        SAL   SHARE
---------- ---------- ---------- -------
SMITH              20       1280    2,76
ALLEN              30       2560    5,51
WARD               30       2000    4,31
JONES              20       4760   10,25
MARTIN             30       2000    4,31
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
And this (of course) also works with &lt;b&gt;PARTITION BY&lt;/b&gt; ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  e.ename, 
  e.deptno,
  e.sal,
  ratio_to_report(e.sal) over (partition &lt;span style="color: slateblue;"&gt;by&lt;/span&gt; deptno) * &lt;span style="color: magenta;"&gt;100&lt;/span&gt; share
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; emp e
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Analytic functions are absolutely worth the learing effort. Beyond the problem described here,
 analytic functions provide an  easy query syntax for things like moving averages, rankings or
 other aggregates with flexible query windows. Solving this with "classic" SQL is possible (of course),
 but this most often gets cumbersome and difficult to read. You'll find more information in the
 &lt;a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions004.htm#i81407" target="_blank"&gt;documentation&lt;/a&gt;.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-235489401723484321?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/xJ1LrF9tdP4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/xJ1LrF9tdP4/how-to-calculate-ratio-to-report-in-sql.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>1</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1448353 11.5580067</georss:point><georss:box>47.9753153 11.2421497 48.314355299999995 11.8738637</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/12/how-to-calculate-ratio-to-report-in-sql.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-8980919228893107418</guid><pubDate>Mon, 21 Nov 2011 10:45:00 +0000</pubDate><atom:updated>2011-11-22T08:34:44.481+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sure</category><category domain="http://www.blogger.com/atom/ns#">truncate</category><category domain="http://www.blogger.com/atom/ns#">drop</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">table</category><title>DROP TABLE .. Sind Sie sicher?</title><description>&lt;div lang="en" style="color: #cc6600; display: none;"&gt;
"Are you sure?" for DROP TABLE&lt;/div&gt;
&lt;div lang="de" style="border: 1px solid black; margin-left: 1cm; padding: 3px;"&gt;
&lt;i&gt;UPDATE:&lt;/i&gt; Auf einem internen "Produktionsserver" (sofern man davon sprechen kann) habe ich das Package natürlich gleich installiert. Und heute morgen dann gemerkt, dass ein TRUNCATE / DROP auch mal der Normalfall sein kann. Als ich mich im APEX-Workspace einloggen wollte, kam die Fehlermeldung, dass ein DROP / TRUNCATE auf die Tabelle WWV_FLOW_USER_ACCESS_LOG2$ nicht möglich ist. APEX macht das von sich aus: &lt;b&gt;Da hilft es nix: Der Trigger muss erweitert werden!&lt;/b&gt; Ich habe den Code (unten) angepasst und eine Ausnahme für APEX eingebaut; es kann durchaus sein, dass noch ein paar hinzukommen. Wenn euch da etwas vor mir auffällt, einfach in den Kommentar schreiben.&lt;/div&gt;
&lt;div lang="de"&gt;
Jüngst bin ich nochmals über das Thema &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e25519/triggers.htm#i1007895"&gt;Database Event Triggers mit PL/SQL&lt;/a&gt; gestolpert - man kann
 ja (schon seit einiger Zeit) auch Trigger auf Datenbank-Events anlegen - ein klassisches Beispiel
 wäre das "Verbieten" einer DROP-Operation auf Produktionssystemen - einfach zur Sicherheit. Der Trigger
 dazu ist einfach und schnell gebaut ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;trigger&lt;/span&gt; tr_drop_is_prohibited
before &lt;span style="color: #804040;"&gt;&lt;b&gt;drop&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;on&lt;/span&gt; database
&lt;span style="color: slateblue;"&gt;begin&lt;/span&gt;
  raise_application_error(&lt;span style="color: magenta;"&gt;-20000&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'DROP IS NOT ALLOWED ON THIS SYSTEM'&lt;/span&gt;);
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt;;
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Einfach, aber effektvoll. Man kann nun auf dieser Datenbank nichts mehr droppen (außer dem 
 Trigger selbst, natürlich). Aber für den praktischen Einsatz etwas zu "grobstollig". Erstens 
 ist ein TRUNCATE Table mittlerweile schlimmer als ein DROP TABLE, welches man mit dem Recycle Bin
 (FLASHBACK TABLE ... TO BEFORE DROP) rückgängig machen kann, zum anderen muss es ja manchmal doch
 sein, dass man etwas droppen will ... und dann muss man erst den Trigger deaktivieren und danach wieder
 aktivieren. 
&lt;/div&gt;
&lt;div lang="de"&gt;
Nach diesem Gedanken kam ich auf die Idee, eine Art "Sind Sie Sicher?"-Mechanismus für 
 DROP- und TRUNCATE-Operationen zu bauen. In der Datenbank funktioniert er nur andersherum als bei Microsoft
 Windows: Man muss die Drop-Operation zuerst deklarieren und dann ausführen. Auf einem Produktionssystem
 ist sowas vielleicht doch ganz hilfreich und erspart unter Umständen das eine oder andere versehentlich
 gedroppte Object. Hier ist nun der Code (muss als SYS eingespielt werden) - wir beginnen mit einem
 Package, mit dem die DROP-Operation vorher deklariert wird: 
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;authid&lt;/b&gt;&lt;/span&gt; current_user &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  g_forsession &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
  g_nextobject &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
  g_objectname &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;
  g_objecttype &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;
  g_objectuser &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj(
    p_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;,
    p_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: teal;"&gt;user&lt;/span&gt;,
    p_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TABLE'&lt;/span&gt;
  );
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; sess(
    p_enable &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;
  );
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; clear; 
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; info;
&lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; PREDROP;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err

&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; sess (
    p_enable &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;
  ) &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; 
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
     g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_enable;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; sess;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;;

    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; obj;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj (
    p_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;,
    p_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: teal;"&gt;user&lt;/span&gt;,
    p_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TABLE'&lt;/span&gt;
  ) &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;;
    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objectname;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objecttype;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objectuser;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; obj;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; clear &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; clear;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; info &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'********************************************'&lt;/span&gt;);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Enable Session Flag: '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #804040;"&gt;&lt;b&gt;case&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;when&lt;/b&gt;&lt;/span&gt; g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TRUE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'FALSE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;));
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Enable Object Flag:  '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #804040;"&gt;&lt;b&gt;case&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;when&lt;/b&gt;&lt;/span&gt; g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TRUE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'FALSE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;));
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object name:         '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objectname);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object type:         '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objecttype);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object owner:        '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objectuser);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'********************************************'&lt;/span&gt;);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;''&lt;/span&gt;);
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; info;
&lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; PREDROP;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err

&lt;span style="color: teal;"&gt;grant&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;execute&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;on&lt;/span&gt; PREDROP &lt;span style="color: teal;"&gt;to&lt;/span&gt; &lt;span style="color: teal;"&gt;public&lt;/span&gt;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;

&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: teal;"&gt;public&lt;/span&gt; &lt;span style="color: teal;"&gt;synonym&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; sys.PREDROP
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Execute-Privileg und Public Synonym nicht vergessen und dann geht es auch schon
 weiter. Als nächstes kommt der Database Event Trigger, der ins Package hineinguckt,
 ob das Objekt, was da gerade bearbeitet werden soll, vorher deklariert wurde - wenn ja,
 geht die Operation durch, wenn nicht, wird ein Fehler ausgelöst ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;trigger&lt;/font&gt; tr_drop_protection 
before &lt;font color="#804040"&gt;&lt;b&gt;drop&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;truncate&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;on&lt;/font&gt; database
declare
  l_raiseerror     &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;

  l_namematch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_typematch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_usermatch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_match          &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_always_allowed &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;

  &lt;font color="#0000ff"&gt;/* UPDATE: &lt;/font&gt;
&lt;font color="#0000ff"&gt;   * Some code need to be allowed in general!&lt;/font&gt;
&lt;font color="#0000ff"&gt;   */&lt;/font&gt; 
  &lt;font color="#6a5acd"&gt;function&lt;/font&gt; always_allowed(p_owner &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;, p_object &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
    l_always &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; p_owner &lt;font color="#804040"&gt;&lt;b&gt;like&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;'APEX_%'&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; p_object &lt;font color="#804040"&gt;&lt;b&gt;like&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;'WWV_FLOW_%LOG%'&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      l_always := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
      goto ende;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
    &amp;lt;&amp;lt;ende&amp;gt;&amp;gt;
    &lt;font color="#6a5acd"&gt;return&lt;/font&gt; l_always;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; always_allowed;

  &lt;font color="#6a5acd"&gt;function&lt;/font&gt; match(p_string1 &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;, p_string2 &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
    l_match &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; p_string1 = p_string2 &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; p_string2 &lt;font color="#6a5acd"&gt;is&lt;/font&gt; &lt;font color="#6a5acd"&gt;null&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
      l_match := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
      l_match := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;return&lt;/font&gt; l_match;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; match;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    l_namematch := match(ora_dict_obj_name, PREDROP.g_objectname);
    l_typematch := match(ora_dict_obj_type, PREDROP.g_objecttype);
    l_usermatch := match(ora_dict_obj_owner, PREDROP.g_objectuser);
    l_match := l_namematch &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_usermatch &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_typematch;
    l_always_allowed := always_allowed(ora_dict_obj_owner, ora_dict_obj_name);

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; ((PREDROP.g_nextobject &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; PREDROP.g_forsession) &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_match) &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; l_always_allowed  &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      l_raiseerror := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;else&lt;/font&gt;
      l_raiseerror := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; PREDROP.g_forsession &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; l_raiseerror &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
      PREDROP.clear;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; l_raiseerror &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      raise_application_error(&lt;font color="#ff00ff"&gt;-20000&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'Enable DROP/TRUNCATE of '&lt;/font&gt;||ora_dict_obj_type|| &lt;font color="#ff00ff"&gt;' &amp;quot;'&lt;/font&gt;||ora_dict_obj_name||&lt;font color="#ff00ff"&gt;'&amp;quot; with the '&lt;/font&gt;||upper(&lt;font color="#ff00ff"&gt;'PREDROP'&lt;/font&gt;)||&lt;font color="#ff00ff"&gt;' package.'&lt;/font&gt;);
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
/&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Und das war's auch schon. Von jetzt an funktioniert DROP und TRUNCATE etwas anders ...
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;pre&gt;SQL&amp;gt; drop table emp3;
drop table emp3
*
FEHLER in Zeile 1:
ORA-00604: Fehler auf rekursiver SQL-Ebene 1
ORA-20000: Enable DROP/TRUNCATE of TABLE "EMP3" with the PREDROP package.
ORA-06512: in Zeile 36

SQL&amp;gt; exec predrop.obj('EMP3');

PL/SQL-Prozedur erfolgreich abgeschlossen.

SQL&amp;gt; drop table emp3;

Tabelle wurde gelöscht.

SQL&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Für Truncate gilt das gleiche. Lässt man den Objektnamen auf SQL NULL, gilt die Freigabe für die
 nächste Tabelle, egal, wie sie heißt.  Setzt man auch den Object Type auf SQL NULL, gilt die
 Freigabe für alle Objekte im Schema. Und der Parameter P_OBJECTUSER gilt analog. Ruft man dann
 noch die Prozedur PREDROP.SESS auf, gilt die Freigabe nicht nur für das nächste Objekt, sondern
 für die ganze Session. Auch auf Produktionsungebungen läuft ja mal ein Skript mit mehreren
 &lt;i&gt;gewollten&lt;/i&gt; DROP-Operationen - solche Vorgänge sollten nicht behindert werden; das Package
 soll helfen und nicht im Weg sehen.
 Man könnte das jetzt natürlich auch noch mit regulären Ausdrücken erweitern und so die völlige
 Flexibilität bekommen - aber das machen wir ein anderes Mal ...
&lt;/div&gt;
&lt;div lang="de"&gt;
Was denkt Ihr ...?
&lt;/div&gt;
&lt;div lang="en" style="display: none; border: 1px solid black; margin-left: 1cm; padding: 3px;"&gt;
&lt;i&gt;UPDATE:&lt;/i&gt; Just yesterday I installed this package on my own "production" instance - and as  I wanted to login into APEX today I encountered my own message &lt;b&gt;Cannot DROP/TRUNCATE table "WWV_FLOW_USER_ACCESS_LOG2$"&lt;/b&gt; - so APEX does some regular DROP / TRUNCATE operations which must not be trapped by the Trigger - So I extended the trigger code a bit (further extensions might be necessary in the future) - just have a look into the new trigger code. If you also encounter DROP or TRUNCATE operations which need to ge generally allowed in the trigger, feel free to post me a message or a comment.&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Recently I again encountered the &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e25519/triggers.htm#i1007895"&gt;database event triggers&lt;/a&gt; in PL/SQL - using these you can place a trigger not only on table or view DML, but
 also on DDL commands or database events like STARTUP, SHUTDOWN oder LOGON. One thirst thought would be prohibiting
 the DROP operation on a production instance - the trigger code for this is rather simple ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;trigger&lt;/span&gt; tr_drop_is_prohibited
before &lt;span style="color: #804040;"&gt;&lt;b&gt;drop&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;on&lt;/span&gt; database
&lt;span style="color: slateblue;"&gt;begin&lt;/span&gt;
  raise_application_error(&lt;span style="color: magenta;"&gt;-20000&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'DROP IS NOT ALLOWED ON THIS SYSTEM'&lt;/span&gt;);
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt;;
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Simple and powerful. On this instance no object can be dropped any more (except the trigger itself, of course). 
 But this can also lead to a lot of problems, of course: Even on production systems, sometimes there &lt;i&gt;must&lt;/i&gt;
 be dropped something. Then the trigger needs to be disabled before and enabled after the operation. And then
 there might be objects which are frequently dropped and re-created and other objects which not. And what about
 the TRUNCATE operation. This one cannot be undone with FLASHBACK TABLE TO BEFORE DROP - so accidentially use
 of TRUNCATE is much more dangerous than the DROP operation ... 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
So my next thought was to try a bit more sophisticated approach - I'd like to see the "Are you sure?" feature
 which we all know from Windows also in the database. And although we cannot catch the DROP operation to ask
 the "are you sure" question, we can implement a similar approach: The idea is to declare the object to be
 dropped beforehand. So we have a package which holds the declared object and a trigger which looks into
 the package and raises an error message if the object has not been declared. First we create the package.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;authid&lt;/b&gt;&lt;/span&gt; current_user &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  g_forsession &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
  g_nextobject &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
  g_objectname &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;
  g_objecttype &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;
  g_objectuser &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;''&lt;/span&gt;;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj(
    p_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;,
    p_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: teal;"&gt;user&lt;/span&gt;,
    p_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TABLE'&lt;/span&gt;
  );
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; sess(
    p_enable &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;
  );
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; clear; 
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; info;
&lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; PREDROP;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err

&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; sess (
    p_enable &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;
  ) &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; 
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
     g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_enable;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; sess;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;;

    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; obj;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; obj (
    p_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;,
    p_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: teal;"&gt;user&lt;/span&gt;,
    p_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;default&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TABLE'&lt;/span&gt;
  ) &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;true&lt;/span&gt;;
    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objectname;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objecttype;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; p_objectuser;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; obj;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; clear &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;false&lt;/span&gt;;
    g_objectname &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objecttype &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
    g_objectuser &lt;span style="color: #804040;"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; clear;

  &lt;span style="color: #804040;"&gt;&lt;b&gt;procedure&lt;/b&gt;&lt;/span&gt; info &lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;
  &lt;span style="color: #804040;"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/span&gt;
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'********************************************'&lt;/span&gt;);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Enable Session Flag: '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #804040;"&gt;&lt;b&gt;case&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;when&lt;/b&gt;&lt;/span&gt; g_forsession &lt;span style="color: #804040;"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TRUE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'FALSE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;));
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Enable Object Flag:  '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #804040;"&gt;&lt;b&gt;case&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;when&lt;/b&gt;&lt;/span&gt; g_nextobject &lt;span style="color: #804040;"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'TRUE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'FALSE'&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;));
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object name:         '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objectname);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object type:         '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objecttype);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'* Object owner:        '&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;||&lt;/b&gt;&lt;/span&gt;g_objectuser);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;'********************************************'&lt;/span&gt;);
    dbms_output.put_line(&lt;span style="color: magenta;"&gt;''&lt;/span&gt;);
  &lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; info;
&lt;span style="color: #804040;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt; PREDROP;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err

&lt;span style="color: teal;"&gt;grant&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;execute&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;on&lt;/span&gt; PREDROP &lt;span style="color: teal;"&gt;to&lt;/span&gt; &lt;span style="color: teal;"&gt;public&lt;/span&gt;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;

&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: teal;"&gt;public&lt;/span&gt; &lt;span style="color: teal;"&gt;synonym&lt;/span&gt; PREDROP &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; sys.PREDROP
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Don't forget to grant &lt;b&gt;EXECUTE&lt;/b&gt; Privileges and to create a public synonym in order to make the
 package accessible for everyone. Creating the Trigger is the next step. As said before, it simply
 checks whether the object to be dropped ( &lt;b&gt;ora_dict_obj_name&lt;/b&gt;, &lt;b&gt;ora_dict_obj_type&lt;/b&gt;, &lt;b&gt;ora_dict_obj_owner&lt;/b&gt;) 
 has been declared with the PRECODE package. If not, the trigger raises an error, otherwise it does
 nothing and the operation will succeed.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;trigger&lt;/font&gt; tr_drop_protection 
before &lt;font color="#804040"&gt;&lt;b&gt;drop&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;truncate&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;on&lt;/font&gt; database
declare
  l_raiseerror     &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;

  l_namematch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_typematch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_usermatch      &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_match          &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  l_always_allowed &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;

  &lt;font color="#0000ff"&gt;/* UPDATE: &lt;/font&gt;
&lt;font color="#0000ff"&gt;   * Some code need to be allowed in general!&lt;/font&gt;
&lt;font color="#0000ff"&gt;   */&lt;/font&gt;
  &lt;font color="#6a5acd"&gt;function&lt;/font&gt; always_allowed(p_owner &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;, p_object &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
    l_always &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; p_owner &lt;font color="#804040"&gt;&lt;b&gt;like&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;'APEX_%'&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; p_object &lt;font color="#804040"&gt;&lt;b&gt;like&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;'WWV_FLOW_%LOG%'&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      l_always := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
      goto ende;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
    &amp;lt;&amp;lt;ende&amp;gt;&amp;gt;
    &lt;font color="#6a5acd"&gt;return&lt;/font&gt; l_always;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; always_allowed;

  &lt;font color="#6a5acd"&gt;function&lt;/font&gt; match(p_string1 &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;, p_string2 &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
    l_match &lt;font color="#2e8b57"&gt;&lt;b&gt;boolean&lt;/b&gt;&lt;/font&gt; := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; p_string1 = p_string2 &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; p_string2 &lt;font color="#6a5acd"&gt;is&lt;/font&gt; &lt;font color="#6a5acd"&gt;null&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
      l_match := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
      l_match := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;return&lt;/font&gt; l_match;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; match;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    l_namematch := match(ora_dict_obj_name, PREDROP.g_objectname);
    l_typematch := match(ora_dict_obj_type, PREDROP.g_objecttype);
    l_usermatch := match(ora_dict_obj_owner, PREDROP.g_objectuser);
    l_match := l_namematch &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_usermatch &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_typematch;
    l_always_allowed := always_allowed(ora_dict_obj_owner, ora_dict_obj_name);

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; ((PREDROP.g_nextobject &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; PREDROP.g_forsession) &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; l_match) &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; l_always_allowed  &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      l_raiseerror := &lt;font color="#6a5acd"&gt;false&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;else&lt;/font&gt;
      l_raiseerror := &lt;font color="#6a5acd"&gt;true&lt;/font&gt;;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; PREDROP.g_forsession &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; l_raiseerror &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
      PREDROP.clear;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;

    &lt;font color="#6a5acd"&gt;if&lt;/font&gt; l_raiseerror &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
      raise_application_error(&lt;font color="#ff00ff"&gt;-20000&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'Enable DROP/TRUNCATE of '&lt;/font&gt;||ora_dict_obj_type|| &lt;font color="#ff00ff"&gt;' &amp;quot;'&lt;/font&gt;||ora_dict_obj_name||&lt;font color="#ff00ff"&gt;'&amp;quot; with the '&lt;/font&gt;||upper(&lt;font color="#ff00ff"&gt;'PREDROP'&lt;/font&gt;)||&lt;font color="#ff00ff"&gt;' package.'&lt;/font&gt;);
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
/&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
That's it. From now on, DROP and TRUNCATE operations need to be declared beforehand ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;pre&gt;SQL&amp;gt; drop table emp3;
drop table emp3
*
ERROR in line 1:
ORA-00604: Error at recursive SQL level 1
ORA-20000: Enable DROP/TRUNCATE of TABLE "EMP3" with the PREDROP package.
ORA-06512: line 36

SQL&amp;gt; exec predrop.obj('EMP3');

PL/SQL-Procedure successfully completed.

SQL&amp;gt; drop table emp3;

Table dropped.

SQL&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
This implementation of the PREDROP package already provides some flexibility. Setting
 the object name, type or owner to SQL NULL matches everything. Normally a declaration
 is valid until it has been matched by a DROP operation - after calling PREDROP.SESS it will be
 valid until the end of the session - this is useful when runnung SQL scripts.
 Using regular expressions or LIKE syntax would make the package even more flexible ... but
 this is a story for another blog posting ... 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Tell me what you think!
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-8980919228893107418?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/VojTnFhcFY0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/VojTnFhcFY0/drop-table-sind-sie-sicher.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>1</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1391265 11.5801863</georss:point><georss:box>47.969588 11.2643293 48.308665000000005 11.896043299999999</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/11/drop-table-sind-sie-sicher.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-3339938634803151072</guid><pubDate>Fri, 21 Oct 2011 12:37:00 +0000</pubDate><atom:updated>2011-11-14T09:58:44.718+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">vortrag</category><category domain="http://www.blogger.com/atom/ns#">konferenz</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Ab morgen: DOAG2011</title><description>&lt;div lang="de"&gt;
Bis zur &lt;a href="http://www.doag.org/de/events/konferenzen/doag-2011.html" target="_blank"&gt;DOAG2011&lt;/a&gt; ist es ja nicht mehr solange hin - ich werde an allen drei Tagen dort sein und freue mich schon darauf, das eine oder andere Gesicht aus der Oracle-Community wiederzusehen ... Wie in den letzten Jahren habe ich auch dieses Jahr wieder ein paar Vorträge - hier sind sie ...
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Demo-Kino: &lt;b&gt;Transformers 4.1: Von Standard nach Cool&lt;/b&gt; &lt;br /&gt; 
15.11.2011 10:00 - 10:45 Uhr - Foyer Tokio&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Mit nur wenig Aufwand kann man einer APEX-Applikation moderne Elemente hinzufügen. Eine
eher langweilige Geschäftsanwendung wird im Film transformiert - Elemente wie "Google Suggest",
Karten, Volltextsuche und moderne Layoutelemente kommen hinzu. Die neue Anwendung holt den
Nutzer dort ab, wo er steht, mit Anwendungsfeatures, die er aus dem Internet kennt ...
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Das Navi in der Datenbank: Oracle11g has NAVTEQ on Board&lt;/b&gt;&lt;br /&gt; 
16.11.2011 10:00 - 10:45 Uhr - Raum Tokio&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Wussten Sie schon, dass Sie eine postalische Adresse mit der Oracle-Datenbank mit einer einfachen SQL-Abfrage in Koordinaten, also Längen- und Breitengrade, umwandeln können. Mit der Geocoding-Engine ist das überhaupt kein Problem - und durch die enge Integration mit der Datenbank kann dies Teil der normalen Geschäftslogik werden.
&lt;/div&gt;
&lt;div&gt;
Basis dafür sind NAVTEQ-Daten - Oracle has NAVTEQ on Board. Der Vortrag zeigt, was das NAVTEQ ODF Dataset (Oracle Data Format) beinhaltet, wie man es installiert und wie man damit nicht nur Geocoding, sondern auch Routing oder andere Operationen durchführen kann
(diesen Vortrag mache ich gemeinsam mit Till Kreiler von NAVTEQ).
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SQL oder NoSQL? Das ist hier die Frage! Die "Oracle NoSQL Datenbank"&lt;/b&gt;&lt;br /&gt; 
16.11.2011 14:00 - 14:45 Uhr - Raum Tokio&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;i&gt;Dieses Thema finde ich ziemlich spannend - ein wenig habe ich schon mit der neuen &lt;b&gt;Oracle NoSQL Database&lt;/b&gt; herumgespielt - und ich muss sagen: Das ist wirklich ein neuer Ansatz - und auf die Reaktionen und Diskussionen bin ich auch schon sehr gespannt ...&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Bekannte Webseiten wie Twitter, Facebook oder URL-Verkürzer wie tinyurl.com setzen NoSQL-Datenbanken ein - und auf der OOW wurde jüngst die Oracle NoSQL Database angekündigt. Der Vortrag stellt die Oracle NoSQL Database vor, geht auf Unterschiede zwischen NoSQL-Datenbanken und den "klassischen" RDBMS ein und stellt mögliche Einsatzszenarien vor.

NoSQL-Datenbanken werden genutzt, um extrem große Datenmengen extrem vieler User zu speichern. Im Gegensatz zu unserer "klassischen" Oracle-Datenbank spielen das Datenmodell, Transaktionskonzepte und Datenintegrität keine Rolle - das einzige, was zählt, ist die wirklich ständige Verfügbarkeit, die mit massiver Parallelisierung erreicht wird. Eine NoSQL-Datenbank richtet sich an Entwickler, denn es gibt keine Abfragesprache und keinen Query-Optimizer. Zugriffe erfolgen über eine Programmierschnittstelle (API) - alle Intelligenz steckt in der Anwendung.
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;apex.meinefirma.de: APEX Hosting im eigenen Unternehmen&lt;/b&gt;&lt;br /&gt; 
17.11.2011 13:00 - 13:45 Uhr - Raum Istabul&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Nahezu überall ändern sich Prozesse und Anforderungen immer schneller: gebraucht wird also eine Plattform, welche die Entwicklung neuer Anwendungen genauso schnell ermöglicht.
Der öffentliche Demoserver "apex.oracle.com" zeigt, wie es geht: Entwickler können Ihre Workspaces selbstständig beantragen und verwalten, ohne manuelles des DBA Eingreifen sofort aktiv werden; neue Anwendungen stehen sofort bereit.
Der Vortrag zeigt, wie ein Server "apex.meinefirma.de" aufgesetzt und betrieben werden kann, welche Hardware man braucht, wie Ressourcenkonflikte gelöst werden und worauf geachtet werden sollte. 
Das ist Cloud Computing "in Action".
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
Auf der ODTUG Kscope-Konferenz, an der ich im Juni teilgenommen hatte, wurde Twitter ganz massiv genutzt - Tweets über die einzelnen Vorträge und neue Ideen kamen quasi im Sekundentakt. Ich bin gespannt, wie das auf der DOAG2011 läuft. Meine Teamkollegen und ich werden euch über den Twitter
 Account &lt;a href="http://www.twitter.com/oraclebudb" target="_blank"&gt;@OracleBUDB&lt;/a&gt; und natürlich mit
 dem Hashtag &lt;a href="http://twitter.com/#%21/search/%23doag2011" target="_blank"&gt;#doag2011&lt;/a&gt; auf dem
 Laufenden halten ... also dranbleiben ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
This is a posting about the DOAg2011 conference and therefore in german only.
&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-3339938634803151072?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/Tst8X_-Ug1U" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/Tst8X_-Ug1U/noch-etwas-mehr-als-drei-wochen.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><georss:featurename>Nürnberg, Deutschland</georss:featurename><georss:point>49.45052 11.08048</georss:point><georss:box>49.285357499999996 10.764623 49.6156825 11.396336999999999</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/10/noch-etwas-mehr-als-drei-wochen.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-6676452663001950262</guid><pubDate>Tue, 04 Oct 2011 07:39:00 +0000</pubDate><atom:updated>2011-10-04T14:34:29.166+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">plsql</category><category domain="http://www.blogger.com/atom/ns#">array</category><category domain="http://www.blogger.com/atom/ns#">STRUCT</category><category domain="http://www.blogger.com/atom/ns#">objects</category><category domain="http://www.blogger.com/atom/ns#">jvm</category><title>Von Java nach SQL: Java-Objekte und die Datenbank-JVM</title><description>&lt;div lang="en" style="color: #cc6600; display: none;"&gt;
From Java to SQL: Java objects and the database JVM&lt;/div&gt;
&lt;div lang="de"&gt;
In der Vergangenheit hatte ich ja schon einige Blog-Postings zum Thema "Java in der Datenbank";
 das letzte Posting &lt;a href="http://sql-plsql-de.blogspot.com/2011/09/twitter-postings-mit-der-datenbank-sql.html" target="_blank"&gt;zum Thema Twitter-Postings mit der Datenbank&lt;/a&gt;, die diversen Postings zum
 Thema &lt;a href="http://plsqlexecoscomm.sourceforge.net/" target="_blank"&gt;Dateisystem-Zugriffe&lt;/a&gt; haben
 alle eines gemein: Sie verwenden die in der Datenbank enthaltene Java-Engine. Wenn es aber darum
 geht, Java-Funktionen aus PL/SQL oder SQL heraus zu nutzen, ist &lt;i&gt;immer&lt;/i&gt; auch eine Parameter-Mapping
 gefragt. Und genau dem möchte ich mich heute widmen. Dabei geht es mir aber nicht um das Abbilden
 eines VARCHAR2, NUMBER oder DATE auf Java-Datentypen - das ist sehr einfach, wie man hier sehen kann ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: #804040;"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; compile java source named simple_test &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;

&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class SimpleTest {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static String getString() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: magenta;"&gt;"Hallo Welt"&lt;/span&gt;;
  }
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static java.sql.Timestamp getDate() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new java.sql.Timestamp(new java.util.&lt;span style="color: seagreen;"&gt;&lt;b&gt;Date&lt;/b&gt;&lt;/span&gt;().getTime());
  }
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static int getNumber() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: magenta;"&gt;4711&lt;/span&gt;;
  }
} 
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace package simple_test_plsql &lt;span style="color: slateblue;"&gt;is&lt;/span&gt;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_string &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_date &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_number &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt;;
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt; simple_test_plsql;
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace package body simple_test_plsql &lt;span style="color: slateblue;"&gt;is&lt;/span&gt;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_string &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; 
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getString() return java.lang.String'&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_date &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getDate() return java.sql.Timestamp'&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_number &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getNumber() return int'&lt;/span&gt;;
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt; simple_test_plsql;
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  simple_test_plsql.get_string,
  simple_test_plsql.get_date,
  simple_test_plsql.get_number
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/

GET_STRING           GET_DATE            GET_NUMBER
-------------------- ------------------- ----------
Hallo Welt           21.09.2011 09:19:40       4711
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Den Experten ist sicher schon aufgefallen, dass die Java-Methoden alle "static" sind; das
 ist auch logisch so, denn PL/SQL ist ja keine objektorientierte Sprache. Mit "statischen" Java-Methoden
 wird Java wie eine prozedurale Sprache genutzt - es entspricht eher dem Konzept von PL/SQL, daher
 können nur statische Java-Methoden auf PL/SQL-Pakete, Prozeduren oder Funktionen abgebildet werden.
&lt;/div&gt;
&lt;div lang="de"&gt;
Das einzige, wo man ein wenig aufpassen muss, sind DATE-Mappings - diese können auf
 die Klassen java.sql.Date und java.sql.Timestamp abgebildet werden. In Java bedeutet das
 aber etwas anderes als in SQL. Arbeitet man beim Mapping mit &lt;b&gt;java.sql.Date&lt;/b&gt;, dann
 werden nur Tag, Monat und Jahr an die SQL-Ebene zurückgegeben - also
 das Datum - möchte man die Uhrzeit haben, sollte man mit &lt;b&gt;java.sql.Timestamp&lt;/b&gt; 
 arbeiten.
 Aber abgesehen davon ist das Mapping solcher Datentypen ja wirklich einfach - und wenn
 man Java-Bibliotheken in der Datenbank verwendet, sollte man sich am besten stets 
 eine eigene "Schicht" mit Java-Methoden schreiben, die einfach auf SQL und PL/SQL
 abzubilden sind - wo die Methodensignaturen also am besten nur solche einfachen
 Datentypen nutzen und keine komplexen Objekte. 
&lt;/div&gt;
&lt;div lang="de"&gt;
Aber jetzt geht's ans Eingemachte: Angenommen, wir haben eine Java-Bibliothek (und als Beispiel 
 nehmen wir mal &lt;a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/File.html" target="_blank"&gt;java.io.File&lt;/a&gt;), die ein komplexes Objekt repräsentiert. Und wir möchten nun eben &lt;i&gt;nicht&lt;/i&gt; für jedes
 Attribut einen eigenen Call bauen, sondern alle relevanten Attribute mit &lt;i&gt;einem einzigen&lt;/i&gt; Call
 abholen. Uns prinzipiell gibt es in der Datenbank ja auch Objekttypen bzw. &lt;i&gt;User Defined Types&lt;/i&gt;,
 mit denen man sowas wie ein "File" modellieren kann. Also fangen wir mal damit an.
&lt;pre&gt;
&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;type&lt;/span&gt; file_t &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; object(
  file_path      &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;),
  file_name      &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;),
  file_size      &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt;,
  last_modified  &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt;,
  is_dir         &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  is_writeable   &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  is_readable    &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  file_exists    &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;)
)
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Allerdings kann man nun keine direkte Verbindung zwischen dem SQL-Typen &lt;b&gt;FILE_T&lt;/b&gt; und
 der Java-Klasse &lt;b&gt;java.io.File&lt;/b&gt; herstellen - beide haben ja überhaupt nichts miteinander
 zu tun - ein Mapping ist aber mit Hilfe von einer "Java-Brückenklasse" möglich: Mit 
 &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/STRUCT.html" target="_blank"&gt;oracle.sql.STRUCT&lt;/a&gt; kann man Objekttypen aus Java heraus erstellen und an SQL bzw. PL/SQL
 zurückgeben. Was wir also brauchen, ist eine (statische) Java-Methode, die mit Hilfe von 
 &lt;b&gt;java.io.File&lt;/b&gt; die Information zu einer Datei holt, damit ein &lt;b&gt;STRUCT&lt;/b&gt; für den &lt;b&gt;FILE_T&lt;/b&gt; erzeugt und
 diese kann dann in die SQL-Ebene zurückgibt.
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: #804040;"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; compile java source named java_file &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
import java.math.*;
import java.util.*;
import java.io.*;

import java.sql.*;

import oracle.sql.*;
import oracle.jdbc.*;

&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class JavaFile {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static STRUCT getFile(String pFile) throws &lt;span style="color: slateblue;"&gt;Exception&lt;/span&gt; {
    Connection       con    = DriverManager.getConnection(&lt;span style="color: magenta;"&gt;"jdbc:default:connection:"&lt;/span&gt;);
    StructDescriptor sDescr = StructDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_T"&lt;/span&gt;, con);
    Object[]         o      = new Object[&lt;span style="color: magenta;"&gt;8&lt;/span&gt;];

    &lt;span style="color: slateblue;"&gt;File&lt;/span&gt; f = new &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;(pFile);
    &lt;span style="color: slateblue;"&gt;if&lt;/span&gt; (f.&lt;span style="color: #804040;"&gt;&lt;b&gt;exists&lt;/b&gt;&lt;/span&gt;()) {
     o[&lt;span style="color: magenta;"&gt;0&lt;/span&gt;] = f.getPath();
     o[&lt;span style="color: magenta;"&gt;1&lt;/span&gt;] = f.getName();
     o[&lt;span style="color: magenta;"&gt;2&lt;/span&gt;] = new BigDecimal(f.length());
     o[&lt;span style="color: magenta;"&gt;3&lt;/span&gt;] = new java.sql.Timestamp(f.lastModified());
     o[&lt;span style="color: magenta;"&gt;4&lt;/span&gt;] = (f.isDirectory()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;5&lt;/span&gt;] = (f.canWrite()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;6&lt;/span&gt;] = (f.canRead()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;7&lt;/span&gt;] = &lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;;
     &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new STRUCT(sDescr, con, o);
    } &lt;span style="color: slateblue;"&gt;else&lt;/span&gt; {
     &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: slateblue;"&gt;null&lt;/span&gt;;
    } 
  }
}
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_file_atts (p_file &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; file_t
&lt;span style="color: slateblue;"&gt;is&lt;/span&gt; language java name &lt;span style="color: magenta;"&gt;'JavaFile.getFile(java.lang.String) return oracle.sql.STRUCT'&lt;/span&gt;;
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Hier muss der Java-Code mit der SQL-Ebene zusammenspielen - deshalb wird zuerst eine
 JDBC-"Verbindung" aufgebaut - das ist aber nichts weiter als eine Art "Pointer" auf
 die Datenbanksitzung, denn das Java läuft ja bereits in der Datenbank. Es wird 
 ein &lt;b&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/StructDescriptor.html" target="_blank"&gt;StructDescriptor&lt;/a&gt;&lt;/b&gt;-Objekt erzeugt, welches auf den vorher erzeugten Typen &lt;b&gt;FILE_T&lt;/b&gt; 
 zeigt. Alle Attribute des &lt;b&gt;FILE_T&lt;/b&gt; werden auf Java-Seite in einem Array der Klasse &lt;b&gt;Object[]&lt;/b&gt; 
 abgelegt. Hier muss man als Entwickler aufpassen, dass die verwendeten Java-Typen auf
 die Datentypen des SQL-Typen passen (siehe einfache Mappings oben). Mit diesem Array, 
 dem StructDescriptor-Objekt und dem Connection-Objekt wird dann
 ganz zum Schluß ein &lt;b&gt;STRUCT&lt;/b&gt;-Objekt generiert, welches genau auf den Typen &lt;b&gt;FILE_T&lt;/b&gt; passt. 
 Natürlich kann man auch komplexere Dinge bauen und ein "STRUCT in ein STRUCT" schachteln, man
 muss nur aufpassen, dass alles zur Definition der Objekttypen in SQL passt.
&lt;/div&gt;
&lt;div lang="de"&gt;
Zum Abschluß kommt wieder die PL/SQL-Definition der Funktion - in PL/SQL wird
 als IN Parameter ein &lt;b&gt;VARCHAR2&lt;/b&gt; und als Rückgabewert ein &lt;b&gt;FILE_T&lt;/b&gt; deklariert. Folgerichtig
 passt das auf ein &lt;b&gt;java.lang.String&lt;/b&gt; als Eingabe- und ein &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; als 
 Rückgabewert. Alle Objekttypen werden auf Java-Seite als &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; abgebildet - die
 Verknüpfung mit dem konkreten Objekttypen erledigt der &lt;b&gt;StructDescriptor&lt;/b&gt; ...
&lt;/div&gt;
&lt;div lang="de"&gt;
Alles klar? Dann können wir testen ...
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select get_file_atts('/') from dual;
select get_file_atts('/') from dual
                               *
FEHLER in Zeile 1:
ORA-29532: Java-Aufruf durch nicht abgefangene Java-Exception beendet:
java.security.AccessControlException: the Permission (java.io.FilePermission /
read) has not been granted to SCOTT. The PL/SQL to grant this is
dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission', '/', 'read'
)
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Ach ja: Zum Dateisystemzugriff braucht es Privilegien - die muss der DBA einräumen. Wenn
 Ihr vor diesen Meldungen Ruhe haben wollt, gebt eurem Datenbankschema das &lt;b&gt;JAVASYSPRIV&lt;/b&gt;-Privileg,
 dann har er alle Rechte, die man haben kann (für Produktion nicht zu empfehlen). Alternativ könnt Ihr einfach den in der
 Fehlermeldung dargestellten Aufruf ausführen - der räumt genau das fehlende Privileg ein. Wenn Ihr
 das Privileg habt, probiert es nochmal ...
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select get_file_atts('/tmp') from dual;

GET_FILE_ATTS('/TMP')(FILE_PATH, FILE_NAME, FILE_SIZE, LAST_MODIFIED, IS_DIR, IS
--------------------------------------------------------------------------------
FILE_T('/tmp', 'tmp', 126976, '21.09.2011 10:25:22', 'Y', 'Y', 'Y', 'Y')

1 Zeile wurde ausgewählt.
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
So weit so gut. Wir haben es also geschafft, ein strukturiertes Objekt von Java nach
 PL/SQL zu übertragen. Analog dazu kann man nun für alle Objekte vorgehen:
 &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;SQL-Objekttypen erzeugen&lt;/li&gt;
&lt;li&gt;Java Methode erzeugen, die das eigentliche Java-Objekt auf eine STRUCT-Instanz abbildet, dabei
      mit dem StructDescriptor und dem Object[]-Array arbeiten&lt;/li&gt;
&lt;li&gt;STRUCT-Instanz aus Java zurückgeben und in SQL übernehmen&lt;/li&gt;
&lt;li&gt;PL/SQL Wrapper für die neue Java Stored Procedure erstellen&lt;/li&gt;
&lt;/ul&gt;
Bleibt die nächste (und im Datenbankumfeld spannende) Aufgabe: Ich möchte 
 ein Directory-Listing abbilden, also eine ganze Reihe von strukturierten Objekten
 zurückgeben. Im reinen PL/SQL geht haben wir hierfür die &lt;i&gt;Table Functions&lt;/i&gt; 
 - und ein ähnliches Konzept nutzen wir auch in Java. Zunächst brauchen wir,
 wie bei der PL/SQL Table Function, einen Objekttypen, der die Dateiliste repräsentiert - das ist einfach:
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;type&lt;/span&gt; file_ct &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; &lt;span style="color: slateblue;"&gt;table&lt;/span&gt; &lt;span style="color: slateblue;"&gt;of&lt;/span&gt; file_t
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Und wieder gilt es, aus Java heraus eine Instanz dieses Typs &lt;b&gt;FILE_CT&lt;/b&gt; zu erzeugen. Für Varray- oder
 Table Types gibt es jedoch eine andere Java-"Brückenklasse": &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/ARRAY.html" target="_blank"&gt;oracle.sql.ARRAY&lt;/a&gt;. Der Umgang damit
 ist aber ganz ähnlich wie bei der Klasse oracle.sql.STRUCT. Es wird ein &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/ArrayDescriptor.html" target="_blank"&gt;ArrayDescriptor&lt;/a&gt;-Objekt benötigt, der die 
 Verbindung zum konkreten SQL-Typen herstellt, und mit diesem, dem Connection-Objekt und einem
 Standard-Java-Array wird die Instanz vom Typ &lt;b&gt;oracle.sql.ARRAY&lt;/b&gt; erzeugt, die genau auf den &lt;b&gt;FILE_CT&lt;/b&gt; 
 passt. Das ganze als Code ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class JavaFile {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static ARRAY getFileList(String pFile) throws &lt;span style="color: slateblue;"&gt;Exception&lt;/span&gt; {
    Connection       con    = DriverManager.getConnection(&lt;span style="color: magenta;"&gt;"jdbc:default:connection:"&lt;/span&gt;);
    StructDescriptor sDescr = StructDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_T"&lt;/span&gt;, con);
    ArrayDescriptor  aDescr = ArrayDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_CT"&lt;/span&gt;, con);
    Object[]         o      = new Object[&lt;span style="color: magenta;"&gt;8&lt;/span&gt;];

    &lt;span style="color: blue;"&gt;/* Array containing java File objects */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;[]   f = new &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;(pFile).listFiles();

    &lt;span style="color: blue;"&gt;/* Array containing SQL STRUCT objects */&lt;/span&gt;
    STRUCT[] a = new STRUCT[f.length];

    &lt;span style="color: blue;"&gt;/* now loop through the File array and create a STRUCT instance for each file */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;for&lt;/span&gt; (int i=&lt;span style="color: magenta;"&gt;0&lt;/span&gt;;i&amp;lt;f.length;i++) {
     o[&lt;span style="color: magenta;"&gt;0&lt;/span&gt;] = f[i].getPath();
     o[&lt;span style="color: magenta;"&gt;1&lt;/span&gt;] = f[i].getName();
     o[&lt;span style="color: magenta;"&gt;2&lt;/span&gt;] = new BigDecimal(f[i].length());
     o[&lt;span style="color: magenta;"&gt;3&lt;/span&gt;] = new java.sql.Timestamp(f[i].lastModified());
     o[&lt;span style="color: magenta;"&gt;4&lt;/span&gt;] = (f[i].isDirectory()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;5&lt;/span&gt;] = (f[i].canWrite()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;6&lt;/span&gt;] = (f[i].canRead()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;7&lt;/span&gt;] = &lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;
     a[i] = new STRUCT(sDescr, con, o);
    } 
    &lt;span style="color: blue;"&gt;/* Create and return the ARRAY object which maps to the SQL type */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new ARRAY(aDescr, con, a);
  }
}
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_file_list (p_file &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; file_ct
&lt;span style="color: slateblue;"&gt;is&lt;/span&gt; language java name &lt;span style="color: magenta;"&gt;'JavaFile.getFileList(java.lang.String) return oracle.sql.ARRAY'&lt;/span&gt;;
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Und das ist im Grunde genommen nur eine Erweiterung obigen Codes. Durch die Liste der File-Objekte,
 die von &lt;a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/File.html#listFiles%28%29" target="_blank"&gt;java.io.File.listFiles()&lt;/a&gt; zurückgegeben wird, laufen wir in einer Schleife durch,
 erzeugen für jedes File-Objekt eine &lt;b&gt;STRUCT&lt;/b&gt;-Instanz und packen auch diese in ein Array. Das
 wird dann mit dem &lt;b&gt;ArrayDescriptor&lt;/b&gt; auf den SQL-Typen &lt;b&gt;FILE_CT&lt;/b&gt; abgebildet und als &lt;b&gt;oracle.sql.ARRAY&lt;/b&gt;-Objekt
 zurückgegeben. Fertig - Test.
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select file_name, last_modified, file_size from table(get_file_list('/'))

FILE_NAME                 LAST_MODIFIED        FILE_SIZE
------------------------- ------------------- ----------
wget-log                  27.04.2011 16:24:02        496
boot                      02.02.2011 13:22:58       1024
misc                      25.07.2011 09:29:09          0
stage                     04.04.2011 11:27:57          7
lib                       15.07.2011 11:06:27       4096
etc                       25.07.2011 09:29:07       4096
root                      15.07.2011 11:14:01       4096
bin                       02.02.2011 13:28:45       4096
:                         :                            :
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Eigentlich ganz einfach, oder? Mit dem hier vorgestellten lässt sich nun jede beliebige
 Java-Bibliothek in der Datenbank nutzen - die einzige Voraussetzung ist, dass sie keinen
 Native-Code verwendet - nur 100%-Java-Bibliotheken laufen in der Datenbank. Zum Ansprechen
 aus SQL und PL/SQL überlegt man sich dann eine vernünftige Schnittstelle, erzeugt die
 passenden Java-Klassen, die entweder einfache Datentypen (String, Date, numerische)
 oder komplexe Datentypen als STRUCT oder ARRAY zurückgeben. Diese werden dann auf SQL-Ebene
 durch PL/SQL-Packages und Objekttypen repräsentiert. Die Code-Packages zum
 &lt;a href="http://plsqlexecoscomm.sourceforge.net/" target="_blank"&gt;Dateisystem-Zugriff&lt;/a&gt;,
 zum &lt;a href="http://plsqlmailclient.sourceforge.net/" target="_blank"&gt;Umgang mit einem POP3- oder IMAP-Mailserver&lt;/a&gt; oder zum &lt;a href="http://sql-plsql-de.blogspot.com/2010/11/zip-archive-einpacken-und-auspacken-das.html" target="_blank"&gt;Ein- und Auspacken von ZIP-Archiven&lt;/a&gt; arbeiten alle genau so - 
 und wie gesagt: Jede andere Java-Bibliothek lässt sich genauso 
 einbinden. Damit gibt es keine Grenzen in der Oracle-Datenbank. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
In the past I had quite a number of postinhs in which I made use of the Java engine within the Oracle
 Database. Examples are the previous posting 
 &lt;a href="http://sql-plsql-de.blogspot.com/2011/09/twitter-postings-mit-der-datenbank-sql.html" target="_blank"&gt;about automated tweets from PL/SQL&lt;/a&gt; (which was about using "twitter4j" in the database) or the
 postings about 
 &lt;a href="http://plsqlexecoscomm.sourceforge.net/" target="_blank"&gt;File- and operating system access&lt;/a&gt;.
 Today I'd like to elaborate a bit about a fundamental thing which one has to accomplish when
 using Java in the database: The parameter mapping. This posting is about how to map input or
 return paramaters in a java method to SQL and PL/SQL types in a package. And the focus will not
 be on the simple mapping of VARCHAR2, NUMBER or DATE datatypes ... these are rather simple, 
 as we can see with this code example ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: #804040;"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; compile java source named simple_test &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;

&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class SimpleTest {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static String getString() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: magenta;"&gt;"Hello World"&lt;/span&gt;;
  }
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static java.sql.Timestamp getDate() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new java.sql.Timestamp(new java.util.&lt;span style="color: seagreen;"&gt;&lt;b&gt;Date&lt;/b&gt;&lt;/span&gt;().getTime());
  }
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static int getNumber() {
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: magenta;"&gt;4711&lt;/span&gt;;
  }
} 
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace package simple_test_plsql &lt;span style="color: slateblue;"&gt;is&lt;/span&gt;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_string &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_date &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_number &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt;;
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt; simple_test_plsql;
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace package body simple_test_plsql &lt;span style="color: slateblue;"&gt;is&lt;/span&gt;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_string &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; 
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getString() return java.lang.String'&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_date &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getDate() return java.sql.Timestamp'&lt;/span&gt;;
  &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_number &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
  language java name &lt;span style="color: magenta;"&gt;'SimpleTest.getNumber() return int'&lt;/span&gt;;
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt; simple_test_plsql;
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/span&gt; 
  simple_test_plsql.get_string,
  simple_test_plsql.get_date,
  simple_test_plsql.get_number
&lt;span style="color: slateblue;"&gt;from&lt;/span&gt; dual
/

GET_STRING           GET_DATE            GET_NUMBER
-------------------- ------------------- ----------
Hello World          21.09.2011 09:19:40       4711
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The "experts" might have notices that all java methods are "static" - that's evident. PL/SQL 
 is a procedural, not an object-oriented language - so when we want to integrate PL/SQL with
 Java in the database we need to use the "procedural part" of Java which are static class methods.
 If you want to map java methods to procedures and functions in a PL/SQL package you must use
 static methods for that.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
When mapping DATE values from Java to PL/SQL a bit attention is needed. Basically
 a date can be represented in java using &lt;b&gt;java.sql.Date&lt;/b&gt; or &lt;b&gt;java.sql.Timestamp&lt;/b&gt;. When
 those are being mapped to &lt;b&gt;DATE&lt;/b&gt; in SQL or PL/SQL, the &lt;b&gt;java.sql.Date&lt;/b&gt; class only
 maps Day, Month and Year - the time in the DATE would be set to midnight. For having the time 
 component also you need to use &lt;b&gt;java.sql.Timestamp&lt;/b&gt;. Apart from this the mapping
 of simple scalar datatypes from Java to SQL and PL/SQL is quite simple. So the first rule
 is to use simple types whenever possible. Complex objects should only be used when they're
 really needed ... because, as we will see, they require additional coding ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
And now we'll handle these: Let's assume we have a Java library doing some stuff and for
 this example we use the &lt;a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/File.html" target="_blank"&gt;java.io.File&lt;/a&gt; class (which is part of standard Java). We'd like to access file
 attributes with SQL functions and we &lt;i&gt;don't want to&lt;/i&gt; have a single call for each
 attribute. We need a SQL function &lt;i&gt;which collects all attributes in one call&lt;/i&gt; - so we need
 a datatype containing all these attributes at the SQL side. We have &lt;i&gt;Object types&lt;/i&gt; (or &lt;i&gt;User-Defined-Types&lt;/i&gt;)
 for that purpose so the first thing we want to do is to create an object type representing 
 a file.
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;type&lt;/span&gt; file_t &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; object(
  file_path      &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;),
  file_name      &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;4000&lt;/span&gt;),
  file_size      &lt;span style="color: seagreen;"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/span&gt;,
  last_modified  &lt;span style="color: seagreen;"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/span&gt;,
  is_dir         &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  is_writeable   &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  is_readable    &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;),
  file_exists    &lt;span style="color: seagreen;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: magenta;"&gt;1&lt;/span&gt;)
)
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
So far we have a Java representation for a file: java.io.File - and we have a SQL representation
 for a file: Our new &lt;b&gt;FILE_T&lt;/b&gt;. But there is absolutly no connection between those. Of course, we
 cannot map the &lt;b&gt;java.io.File&lt;/b&gt; class to our &lt;b&gt;FILE_T&lt;/b&gt; type - the database has no clue how to map
 the attributes. We need to build a "bridge" 
 between &lt;b&gt;java.io.File&lt;/b&gt; and &lt;b&gt;FILE_T&lt;/b&gt;. And this bridge is a special java class:  &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/STRUCT.html" target="_blank"&gt;oracle.sql.STRUCT&lt;/a&gt;.
 So we now need to implement a static Java method (we can only use static methods) which
 uses &lt;b&gt;java.io.File&lt;/b&gt; to collect file attributes and builds a &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; instance which can
 be mapped to &lt;b&gt;FILE_T&lt;/b&gt;. This code goes here ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: #804040;"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; compile java source named java_file &lt;span style="color: slateblue;"&gt;as&lt;/span&gt;
import java.math.*;
import java.util.*;
import java.io.*;

import java.sql.*;

import oracle.sql.*;
import oracle.jdbc.*;

&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class JavaFile {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static STRUCT getFile(String pFile) throws &lt;span style="color: slateblue;"&gt;Exception&lt;/span&gt; {
    Connection       con    = DriverManager.getConnection(&lt;span style="color: magenta;"&gt;"jdbc:default:connection:"&lt;/span&gt;);
    StructDescriptor sDescr = StructDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_T"&lt;/span&gt;, con);
    Object[]         o      = new Object[&lt;span style="color: magenta;"&gt;8&lt;/span&gt;];

    &lt;span style="color: slateblue;"&gt;File&lt;/span&gt; f = new &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;(pFile);
    &lt;span style="color: slateblue;"&gt;if&lt;/span&gt; (f.&lt;span style="color: #804040;"&gt;&lt;b&gt;exists&lt;/b&gt;&lt;/span&gt;()) {
     o[&lt;span style="color: magenta;"&gt;0&lt;/span&gt;] = f.getPath();
     o[&lt;span style="color: magenta;"&gt;1&lt;/span&gt;] = f.getName();
     o[&lt;span style="color: magenta;"&gt;2&lt;/span&gt;] = new BigDecimal(f.length());
     o[&lt;span style="color: magenta;"&gt;3&lt;/span&gt;] = new java.sql.Timestamp(f.lastModified());
     o[&lt;span style="color: magenta;"&gt;4&lt;/span&gt;] = (f.isDirectory()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;5&lt;/span&gt;] = (f.canWrite()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;6&lt;/span&gt;] = (f.canRead()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;7&lt;/span&gt;] = &lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;;
     &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new STRUCT(sDescr, con, o);
    } &lt;span style="color: slateblue;"&gt;else&lt;/span&gt; {
     &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; &lt;span style="color: slateblue;"&gt;null&lt;/span&gt;;
    } 
  }
}
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_file_atts (p_file &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; file_t
&lt;span style="color: slateblue;"&gt;is&lt;/span&gt; language java name &lt;span style="color: magenta;"&gt;'JavaFile.getFile(java.lang.String) return oracle.sql.STRUCT'&lt;/span&gt;;
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The Java engine within the database needs to interact with the SQL layer - we need
 a JDBC database connection for that. This connection is not more than kind of a pointer
 to the actual database session in which the java code runs in. The 
 &lt;b&gt;&lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/StructDescriptor.html" target="_blank"&gt;StructDescriptor&lt;/a&gt;&lt;/b&gt; class is a utility which helps us to create a &lt;b&gt;STRUCT&lt;/b&gt; object
 exactly matching &lt;b&gt;FILE_T&lt;/b&gt;. Note the usage of the connection object and "&lt;b&gt;FILE_T&lt;/b&gt;" when the 
 &lt;b&gt;StructDescriptor&lt;/b&gt; instance is being created. After that we collect all relevant file
 attributes in an Array of the fundamental Java class &lt;b&gt;Object[]&lt;/b&gt;. The developer needs to take
 care about the order within that array: Our object type has eight simple, scalar attributes. The
 Java types in the &lt;b&gt;Object&lt;/b&gt; array (String, int, java.sql.Date) must match the attributes of the object type (VARCHAR, NUMBER, DATE).
 With this array, the &lt;b&gt;StructDescriptor&lt;/b&gt; instance, and the database connection the &lt;b&gt;STRUCT&lt;/b&gt; instance
 is being created and returned in the last step of the program. This &lt;b&gt;STRUCT&lt;/b&gt; instance exactly 
 matches the &lt;b&gt;FILE_T&lt;/b&gt; definition in the SQL layer.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The final step as (as always) the PL/SQL Wrapper for the static method. We create a 
 function which takes a &lt;b&gt;VARCHAR2&lt;/b&gt; (containing the file path) and returns a &lt;b&gt;FILE_T&lt;/b&gt;. These
 are being mapped to &lt;b&gt;java.lang.String&lt;/b&gt; and &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; . All object types are being
 encoded as &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; - the &lt;b&gt;StructDescriptor&lt;/b&gt; objects cares for the mapping to
 the correct SQL type.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Got it ...?  Then try it!
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select get_file_atts('/') from dual;
select get_file_atts('/') from dual
                               *
FEHLER in Zeile 1:
ORA-29532: Java-Aufruf durch nicht abgefangene Java-Exception beendet:
java.security.AccessControlException: the Permission (java.io.FilePermission /
read) has not been granted to SCOTT. The PL/SQL to grant this is
dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission', '/', 'read'
)
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Ah, yes: You need Java privileges in order to access the file system with a
 Java stored porcedure. In the developing stage you might grant yourself the &lt;b&gt;JAVASYSPRIV&lt;/b&gt; 
 privilege - you will be a "Java superuser" then - on production systems this is not recommended
 you might grant individual privileges there. The practical bit is that Oracle not only throws
 the error message - it also gives the complete PL/SQL call to grant the required permission. So when you have the
 privilege, try again ...
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select get_file_atts('/tmp') from dual;

GET_FILE_ATTS('/TMP')(FILE_PATH, FILE_NAME, FILE_SIZE, LAST_MODIFIED, IS_DIR, IS
--------------------------------------------------------------------------------
FILE_T('/tmp', 'tmp', 126976, '21.09.2011 10:25:22', 'Y', 'Y', 'Y', 'Y')

1 row selected.
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
So far - so good. We managed to create a structured object in java and pass it to
 PL/SQL. You can use this approach for any kind of structured object - and yes: You 
 can nest one &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; within another &lt;b&gt;oracle.sql.STRUCT&lt;/b&gt; - just as you
 can nest object types in each other. The basic steps are:
 &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Create the SQL object types&lt;/li&gt;
&lt;li&gt;Create the static Java method which creates the STRUCT instance matching the object type using
      the Object[] array and the StructDescriptor class.&lt;/li&gt;
&lt;li&gt;Return the STRUCT instance from java to SQL and PL/SQL&lt;/li&gt;
&lt;li&gt;Create the PL/SQL wrapper for your Java stored procedure&lt;/li&gt;
&lt;/ul&gt;
Then we'll move on to the next (and more interesting) level: We want to pass
 not only a structured object but a list of structured objects from Java to PL/SQL.
 In the PL/SQL world we have &lt;i&gt;Table Functions&lt;/i&gt; for that purpose - and as with these
 we now first create another object type representing our list of files ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: slateblue;"&gt;type&lt;/span&gt; file_ct &lt;span style="color: slateblue;"&gt;as&lt;/span&gt; &lt;span style="color: slateblue;"&gt;table&lt;/span&gt; &lt;span style="color: slateblue;"&gt;of&lt;/span&gt; file_t
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
And again: We now need to create an object within Java which maps to this &lt;b&gt;FILE_CT&lt;/b&gt; type.
 But for Varray or table types there is another "Bridging class": &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/ARRAY.html" target="_blank"&gt;oracle.sql.ARRAY&lt;/a&gt;. It's used the
 same way as oracle.sql.STRUCT. We first create an &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e13995/oracle/sql/ArrayDescriptor.html" target="_blank"&gt;ArrayDescriptor&lt;/a&gt; instance
 using the JDBC connection and the type name. This helper object, the JDBC connection
 and a plain Java array are being  used to create the actual instance of &lt;b&gt;oracle.sql.ARRAY&lt;/b&gt;.
 And the code goes here ...
&lt;br /&gt;
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;public&lt;/span&gt; class JavaFile {
  &lt;span style="color: slateblue;"&gt;public&lt;/span&gt; static ARRAY getFileList(String pFile) throws &lt;span style="color: slateblue;"&gt;Exception&lt;/span&gt; {
    Connection       con    = DriverManager.getConnection(&lt;span style="color: magenta;"&gt;"jdbc:default:connection:"&lt;/span&gt;);
    StructDescriptor sDescr = StructDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_T"&lt;/span&gt;, con);
    ArrayDescriptor  aDescr = ArrayDescriptor.createDescriptor(&lt;span style="color: magenta;"&gt;"FILE_CT"&lt;/span&gt;, con);
    Object[]         o      = new Object[&lt;span style="color: magenta;"&gt;8&lt;/span&gt;];

    &lt;span style="color: blue;"&gt;/* Array containing java File objects */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;[]   f = new &lt;span style="color: slateblue;"&gt;File&lt;/span&gt;(pFile).listFiles();

    &lt;span style="color: blue;"&gt;/* Array containing SQL STRUCT objects */&lt;/span&gt;
    STRUCT[] a = new STRUCT[f.length];

    &lt;span style="color: blue;"&gt;/* now loop through the File array and create a STRUCT instance for each file */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;for&lt;/span&gt; (int i=&lt;span style="color: magenta;"&gt;0&lt;/span&gt;;i&amp;lt;f.length;i++) {
     o[&lt;span style="color: magenta;"&gt;0&lt;/span&gt;] = f[i].getPath();
     o[&lt;span style="color: magenta;"&gt;1&lt;/span&gt;] = f[i].getName();
     o[&lt;span style="color: magenta;"&gt;2&lt;/span&gt;] = new BigDecimal(f[i].length());
     o[&lt;span style="color: magenta;"&gt;3&lt;/span&gt;] = new java.sql.Timestamp(f[i].lastModified());
     o[&lt;span style="color: magenta;"&gt;4&lt;/span&gt;] = (f[i].isDirectory()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;5&lt;/span&gt;] = (f[i].canWrite()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;6&lt;/span&gt;] = (f[i].canRead()?&lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;:&lt;span style="color: magenta;"&gt;"N"&lt;/span&gt;);
     o[&lt;span style="color: magenta;"&gt;7&lt;/span&gt;] = &lt;span style="color: magenta;"&gt;"Y"&lt;/span&gt;
     a[i] = new STRUCT(sDescr, con, o);
    } 
    &lt;span style="color: blue;"&gt;/* Create and return the ARRAY object which maps to the SQL type */&lt;/span&gt;
    &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; new ARRAY(aDescr, con, a);
  }
}
/
sho err

&lt;span style="color: #804040;"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; replace &lt;span style="color: slateblue;"&gt;function&lt;/span&gt; get_file_list (p_file &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: slateblue;"&gt;return&lt;/span&gt; file_ct
&lt;span style="color: slateblue;"&gt;is&lt;/span&gt; language java name &lt;span style="color: magenta;"&gt;'JavaFile.getFileList(java.lang.String) return oracle.sql.ARRAY'&lt;/span&gt;;
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
As you see: This code is basically just a small extension of the code above. We loop through 
 the File[] array returned by &lt;a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/File.html#listFiles%28%29" target="_blank"&gt;java.io.File.listFiles()&lt;/a&gt;, create an oracle.sql.STRUCT instance for each  
 java.io.File object and place it into a Java array (STRUCT[]). This java array is then being used
 to create the &lt;b&gt;oracle.sql.ARRAY&lt;/b&gt; instance,  which is finally passed back to PL/SQL. On the
 PL/SQL side we create the wrapper function and that's it. Try ...
&lt;br /&gt;
&lt;pre&gt;SQL&amp;gt; select file_name, last_modified, file_size from table(get_file_list('/'))

FILE_NAME                 LAST_MODIFIED        FILE_SIZE
------------------------- ------------------- ----------
wget-log                  27.04.2011 16:24:02        496
boot                      02.02.2011 13:22:58       1024
misc                      25.07.2011 09:29:09          0
stage                     04.04.2011 11:27:57          7
lib                       15.07.2011 11:06:27       4096
etc                       25.07.2011 09:29:07       4096
root                      15.07.2011 11:14:01       4096
bin                       02.02.2011 13:28:45       4096
:                         :                            :
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
It's quite simpe, isn't it? Using this approach you can pass any data structure between
 Java and PL/SQL - you can use any Java library you want. The only prerequisite is that
 your Java library does not depend on native code - it must be pure Java. 
 First you might design a simple interface consisting of static Java 
 methods which can be easily mapped to PL/SQL calls. Use simple, scalar types whenever
 possible and use object types and arrays only when you really need them. Then you
 need to implement the static java methods (using &lt;b&gt;STRUCT&lt;/b&gt; and &lt;b&gt;ARRAY&lt;/b&gt;, if necessary), 
 create the SQL object types and PL/SQL wrapper
 packages and you are done. The code packages for
 &lt;a href="http://plsqlexecoscomm.sourceforge.net/" target="_blank"&gt;filesystem access&lt;/a&gt;,
 zum &lt;a href="http://plsqlmailclient.sourceforge.net/" target="_blank"&gt;accessing POP3 or IMAP4 mail servers with PL/SQL&lt;/a&gt; or to&lt;a href="http://sql-plsql-de.blogspot.com/2010/11/zip-archive-einpacken-und-auspacken-das.html" target="_blank"&gt;pack and unpack ZIP archives&lt;/a&gt; all work that way. And as said: You can
 use integrate any Java library doing interesting stuff into the Oracle database. There are
 no limits.
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-6676452663001950262?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/PliOcPNTsb4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/PliOcPNTsb4/von-java-nach-sql-java-objekte-und-die.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1391265 11.5801863</georss:point><georss:box>47.969588 11.2643293 48.308665000000005 11.896043299999999</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/10/von-java-nach-sql-java-objekte-und-die.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-2501414756131811256</guid><pubDate>Fri, 16 Sep 2011 10:08:00 +0000</pubDate><atom:updated>2011-09-16T13:44:43.792+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">plsql</category><category domain="http://www.blogger.com/atom/ns#">Java</category><category domain="http://www.blogger.com/atom/ns#">twitter</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Twitter postings mit der Datenbank (SQL, PLSQL, Java)</title><description>&lt;div lang="en" style="color: #cc6600; display: none;"&gt;
Twitter postings by the database&lt;/div&gt;
&lt;div lang="de"&gt;
Seit einiger Zeit verwenden meine  Teamkollegen und ich den Twitter-Account 
&lt;a href="http://twitter.com/oraclebudb" target="_blank"&gt;@oraclebudb&lt;/a&gt;, um interessante
Neuerungen, die keine langen Texte erfordern, bekanntzumachen. Wenn Ihr also stets über 
Neuigkeiten zur Oracle-Datenbank wie 
neue Releases, Patchsets, deutschsprachige Veranstaltungen oder ähnliches informiert sein wollt,
einfach an diesen Account dranhängen ("Folgen").&lt;/div&gt;
&lt;div lang="de"&gt;
Nun ist man ab und zu unterwegs und kann einen Tweet nicht immer von seinem iPhone oder
PC absetzen - man möchte einen Tweet "planen" und dann zu einem festgelegten Zeitpunkt,
bspw. "Montag 10:00 Uhr" automatisch absetzen. Sowas kann übrigens auch sehr interessant
sein, wenn man Twitter für regelmäßige Statusmeldungen über etwas nutzen möchte - ich
könnte mir sehr gut vorstellen, zum Beispiel die Pegelstände von Flüssen (vor allem bei
Hochwasser) regelmäßig über Twitter zu posten. Auch hier braucht es einen Automatismus, von
Hand geht nix mehr.&lt;/div&gt;
&lt;div lang="de"&gt;
Der Nutzen ist klar - die Frage ist also: Wie setzt man es um? Und ich möchte es natürlich 
mit der Oracle-Datenbank, also mit SQL und PL/SQL machen. Eine erste Google-Suche führte
mich denn auch zu zahlreichen Blogs und Webseiten mit PL/SQL-Codefragmenten, die
alle eines gemein hatten: Ich brachte es nicht zum Laufen (wobei das wohl eher an mir lag)
Allein das von Twitter 
verwendete OAuth-Verfahren, welches von einer Anwendung genutzt werden &lt;i&gt;muss&lt;/i&gt;, implementiert
man nicht mal eben in 5 Minuten in PL/SQL.&lt;/div&gt;
&lt;div lang="de"&gt;
Im Java-Bereich gibt es allerdings eine sehr populäre Bibliothek für Twitter: 
&lt;a href="http://twitter4j.org/en/index.html" target="_blank"&gt;twitter4j&lt;/a&gt;. Und da
man in einer Oracle-Datenbank auch Java laufen lassen kann, habe ich mich entschlossen,
das Rad &lt;i&gt;nicht&lt;/i&gt; neu in PL/SQL zu erfinden, sondern das zu nutzen, was da ist ...&lt;/div&gt;
&lt;div lang="de"&gt;
Im folgenden findet Ihr also eine Anleitung, wie man eine PL/SQL-Prozedur in die
Datenbank legt, die unter einem bestimmten Account twittert. Mit dieser Variante
kann nur der Account-Eigentümer per PL/SQL twittern - die Autorisierung durch andere
Nutzer ist prinzipiell möglich, hier aber nicht beschrieben.&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Schritt 1: Applikation auf "dev.twitter.com" registrieren&lt;/b&gt;:&lt;/div&gt;
&lt;div lang="de"&gt;
Loggt euch mit eurem Twitter-Account auf &lt;a href="http://dev.twitter.com/" target="_blank"&gt;dev.twitter.com&lt;/a&gt;
ein. Navigiert im Menü oben rechts (dort, wo Ihr euren Accountnamen seht) zum Bereich
&lt;b&gt;My Applications&lt;/b&gt; und klickt dann die Schaltfläche &lt;b&gt;Create a new Application&lt;/b&gt;. Füllt dann den
Dialog aus. Ihr braucht einen Namen, eine Beschreibung und eine Webseite (die muss es für den
Anfang aber nicht wirklich geben). Die Callback-URL wird für heute nicht benötigt (Abbildung 1). Dann
müsst Ihr mit dem CAPTCHA fertig werden und eure Anwendung ist erstellt.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-EUbydMg1LC4/TnMeBD-xPsI/AAAAAAAAAH4/VKXn6aYNb0c/s1600/img01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="189" src="http://3.bp.blogspot.com/-EUbydMg1LC4/TnMeBD-xPsI/AAAAAAAAAH4/VKXn6aYNb0c/s320/img01.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;i&gt;Abbildung 1: Anwendung erstellen&lt;/i&gt; &lt;/div&gt;
&lt;div lang="de"&gt;
Wenn die Anwendung erstellt wurde, seht Ihr bereits einige wichtige URLs und das
Schlüsselpaar für die Anwendung selbst (&lt;i&gt;Consumer Key&lt;/i&gt; und &lt;i&gt;Consumer Secret&lt;/i&gt;). 
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-IxCYFlxYZmA/TnMeBPDwT7I/AAAAAAAAAIA/1PzMC-2jVew/s1600/img02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="218" src="http://2.bp.blogspot.com/-IxCYFlxYZmA/TnMeBPDwT7I/AAAAAAAAAIA/1PzMC-2jVew/s320/img02.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;i&gt;Abbildung 2: Die Anwendung wurde erstellt&lt;/i&gt; &lt;/div&gt;
&lt;div lang="de"&gt;
Nun navigiert Ihr zu den &lt;b&gt;Settings&lt;/b&gt; eurer neuen Anwendung und stellt die
Berechtigungen auf &lt;b&gt;Read and Write&lt;/b&gt;. Das ist wichtig, denn das Absenden eines 
Tweets ist ein "Write.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-I67plIM6yBY/TnMeBU7TCHI/AAAAAAAAAII/eBx4UeCco-I/s1600/img03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="175" src="http://2.bp.blogspot.com/-I67plIM6yBY/TnMeBU7TCHI/AAAAAAAAAII/eBx4UeCco-I/s320/img03.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;i&gt;Abbildung 3: Vergeben der Berechtigung "Read and Write"&lt;/i&gt; &lt;/div&gt;
&lt;div lang="de"&gt;
Nun zurück zur ersten Reiterkarte &lt;b&gt;Details&lt;/b&gt;. Unten seht Ihr eine Schaltfläche
&lt;b&gt;Create My Access Token&lt;/b&gt; - damit generiert Ihr die
nötigen Accountschlüssel für den eigenen Account (&lt;i&gt;Access Token&lt;/i&gt; und &lt;i&gt;Access Token Secret&lt;/i&gt;).
Diese, den &lt;i&gt;Consumer Key&lt;/i&gt; und das &lt;i&gt;Consumer Secret&lt;/i&gt; bitte merken  - das 
brauchen wir in der Stored Procedure.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-cRvb8MddPTk/TnMeBpP0acI/AAAAAAAAAIQ/m7XUIaQb0ZI/s1600/img04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="224" src="http://4.bp.blogspot.com/-cRvb8MddPTk/TnMeBpP0acI/AAAAAAAAAIQ/m7XUIaQb0ZI/s320/img04.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;i&gt;Abbildung 4: Access Token und Access Token Secret&lt;/i&gt; &lt;/div&gt;
&lt;div lang="de"&gt;
Nun seid Ihr mit dem Registrieren der Anwendung fertig. Jetzt geht es zur Oracle-Datenbank.&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Schritt 2: Twitter4j in die Datenbank laden.&lt;/b&gt;&lt;/div&gt;
&lt;div lang="de"&gt;
Ladet &lt;b&gt;twitter4j&lt;/b&gt; von der Webseite &lt;a href="http://www.twitter4j.org/" target="_blank"&gt;twitter4j.org&lt;/a&gt;
herunter. Twitter4j ist Open Source unter der Apache Lizenz - kann also für alle Anwendungsfälle, sei
es kommerziell oder nicht, verwendet werden. Das ZIP-Archiv muss in ein Verzeichnis eurer Wahl
ausgepackt werden - am besten legt Ihr es gleich auf den Datenbankserver.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-JDCUZ2165c4/TnMeBioS0gI/AAAAAAAAAIY/aZvWFNm0jU0/s1600/img05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="241" src="http://2.bp.blogspot.com/-JDCUZ2165c4/TnMeBioS0gI/AAAAAAAAAIY/aZvWFNm0jU0/s320/img05.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;i&gt;Abbildung 5: ZIP Archiv "twitter4j"&lt;/i&gt; &lt;/div&gt;
&lt;div lang="de"&gt;
Die Java-Bibliotheken befinden sich im Unterverzeichnis &lt;b&gt;lib&lt;/b&gt;. Für einfache Status-Updates
braucht Ihr nur das Archiv &lt;b&gt;twitter4j-core-2.2.4.jar&lt;/b&gt;. Das wird nun wie folgt in die Datenbank geladen.
&lt;pre&gt;$ loadjava -user {dbuser}/{dbpassword} -o -r -v twitter4j-core-2.2.4.jar
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Ihr sehr nun einige Meldungen und zum Schluß kommen einige Fehlermeldungen, die Ihr
aber ignorieren könnt.
&lt;pre&gt;skipping : resource META-INF/maven/org.twitter4j/twitter4j-core/pom.xml
skipping : resource META-INF/maven/org.twitter4j/twitter4j-core/pom.properties
The following operations failed
    class twitter4j/internal/logging/SLF4JLogger: resolution
    class twitter4j/internal/logging/SLF4JLoggerFactory: resolution
exiting  : Failures occurred during processing
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Schritt 3: Java-Klasse für ein Status-Update erstellen&lt;/b&gt;&lt;/div&gt;
&lt;div lang="de"&gt;
Es wäre sehr aufwändig, die Methoden der Twitter4j-Bibliothek direkt auf PL/SQL abzubilden. Dafür
sind es zu viele und vielfach werden Java-Objekte übergeben, deren Mapping auf Datenbanktypen nicht
einfach ist. Der beste Weg ist es, die Operationen, die man haben möchte, in Java zu implementieren,
dabei einfache Funktionssignaturen zu verwenden und diese "Top-Level"-Methoden dann nach
PL/SQL abzubilden.  Zuerst also die Java-Klasse, die auf Basis der Twitter4j-Beispiele gebaut wurde. Achtet darauf,
in der Methode &lt;b&gt;setOAuthAccessToken&lt;/b&gt; die Schlüssel von &lt;b&gt;dev.twitter.com&lt;/b&gt; einzutragen. Weiter
vorne in den Calls zu &lt;b&gt;System.setProperty&lt;/b&gt; müsst Ihr euren Proxy-Server eintragen, wenn die Datenbank hinter einer
Firewall steht. Wenn nicht, entfernt die Zeilen einfach.
&lt;pre&gt;create or replace and compile java source named TwitterStatusUpdate as
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.conf.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.auth.*;

&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.io.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.util.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; oracle.jdbc.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; oracle.sql.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.sql.*;

&lt;span style="color: seagreen;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt; UpdateStatus {
  &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt; Twitter twitter = &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;

  &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt;  {
    System.setProperty(&lt;span style="color: magenta;"&gt;"http.proxyHost"&lt;/span&gt;, &lt;span style="color: magenta;"&gt;"&lt;i&gt;{Proxy-Server, falls nötig}&lt;/i&gt;"&lt;/span&gt;);
    System.setProperty(&lt;span style="color: magenta;"&gt;"http.proxyPort"&lt;/span&gt;, &lt;span style="color: magenta;"&gt;"&lt;i&gt;{Proxy-Server-Port, falls nötig}&lt;/i&gt;"&lt;/span&gt;);
  
    ConfigurationBuilder confbuilder  = &lt;span style="color: #804040;"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/span&gt; ConfigurationBuilder(); 
    confbuilder.setOAuthAccessToken(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Access-Token aus dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthAccessTokenSecret(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Access-Token-Secret aus dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthConsumerKey(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Consumer-Key aus dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthConsumerSecret(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Consumer-Secret aus dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;); 
    twitter = &lt;span style="color: #804040;"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/span&gt; TwitterFactory(confbuilder.build()).getInstance(); 
  }

  &lt;span style="color: seagreen;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt; String updateStatus(String newStatus) &lt;span style="color: seagreen;"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/span&gt; Exception {
    Status status = twitter.updateStatus(newStatus);
    &lt;span style="color: #804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; status.getText();
  }
}
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Schritt 4: PL/SQL Wrapper für die Java-Methode erstellen&lt;/b&gt;&lt;/div&gt;
&lt;div lang="de"&gt;
Für diese statische Java-Metjode &lt;b&gt;updateStatus&lt;/b&gt;, die einen String entgegennimmt und zurückgibt, lässt
sich nun sehr einfach ein PL/SQL-Mapping erstellen.
&lt;pre&gt;&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; set_twitter_status(p_new_status &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;
&lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;language&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;java&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'UpdateStatus.updateStatus(java.lang.String) return java.lang.String'&lt;/span&gt;;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Schritt 5: Privilegienvergabe&lt;/b&gt;&lt;/div&gt;
&lt;div lang="de"&gt;
Ein Twitter-Posting wird über das Netzwerk abgesetzt - das darf ein "normaler" Datenbankuser mit
Java erstmal nicht. Damit die obige Java-Klasse auch tatsächlich funktioniert, muss der Datenbankuser
Privilegien zum Netzwerkzugriff und zum Einstellen des Proxy-Servers (falls nötig) erhalten. Das 
erledigt man wie folgt - das Skript muss als DBA gestartet werden.
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;begin&lt;/span&gt;
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.util.PropertyPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'http.proxyHost'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'read,write'&lt;/span&gt; 
  );
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.util.PropertyPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'http.proxyPort'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'read,write'&lt;/span&gt; 
  );
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.net.SocketPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'api.twitter.com:80'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'connect, resolve'&lt;/span&gt; 
  );
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt;;
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
&lt;b&gt;Abschluß&lt;/b&gt;&lt;/div&gt;
&lt;div lang="de"&gt;
Dann ist es fertig. Nun könnt Ihr testen ...
&lt;pre&gt;SQL&amp;gt; select set_twitter_status('another test at friday') from dual;

SET_TWITTER_STATUS('ANOTHERTESTATFRIDAY')
------------------------------------------------------------------------
another test at friday

1 Zeile wurde ausgewählt.
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="de"&gt;
Wenn Ihr euch die Twitter-Seite eures Accounts anseht, solltet Ihr das Posting nun
sehen ... und von hier aus ist eine Automatisierung kein Thema mehr - ob man nun
per Scheduler-Job regelmäßig etwas twittert, eine APEX-Anwendung zum Planen der Tweets
erstellt oder andere Dinge tut - mit den Mitteln der Datenbank kann dies nun beliebig
genutzt werden. Eine einfaches Beispiel ist demnach eine APEX-Anwendung mit einem Formular
auf eine Tabelle. Im Formular kann man Tweets und eine Zeitpunkt eintragen, zu dem der
Tweet gepostet werden soll. Ein DBMS_SCHEDULER-Job läuft dann regelmäßig los und postet
automatisch alle "fälligen" Tweets. Und natürlich kann man mit &lt;b&gt;twitter4j&lt;/b&gt; noch mehr tun als nur Status-Updates
abzusetzen, aber wie man bspw. die &lt;i&gt;Home-Timeline&lt;/i&gt; abruft, dazu mache ich am besten
ein eigenes Blog Posting. Viel Spaß auf jeden Fall beim Ausprobieren ...&lt;/div&gt;

&lt;div lang="en" style="display: none;"&gt;
My teammates and me are using the twitter account
&lt;a href="http://twitter.com/oraclebudb" target="_blank"&gt;@oraclebudb&lt;/a&gt;, to post interesting
news about the Oracle database (Events in german language, Releases and more) for a german
audience. So if you are a german reader and interested in regular updates about the
Oracle database, follow  &lt;a href="http://twitter.com/oraclebudb" target="_blank"&gt;@oraclebudb&lt;/a&gt;.
English readers might follow  &lt;a href="http://twitter.com/oracledatabase" target="_blank"&gt;@oracledatabase&lt;/a&gt;.&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
But sometimes one wants to schedule a tweet - perhaps for tomorrow at 10:00am. If one
wants to use Twitter for regular updates about something (think about floodwater levels for
a river) some kind of automation or scheduling is needed - manual tweets are not possible. 
So the question is: How to implement this? I'd like to do it with APEX, the Oracle database
and PL/SQL. So I asked Mr. Google how to do this and I got some PL/SQL fragments which I could
not manage to work on my system. But I saw that the "OAuth" mechanism which Twitter uses
for authenticating is something which I cannot implement in 5 minutes in PL/SQL.&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Java developers have  the very popular  &lt;a href="http://twitter4j.org/en/index.html" target="_blank"&gt;twitter4j&lt;/a&gt;.
library - and since the Oracle database can run Java Stored Procures I decided not to
reinvent the wheel and to use things already there (XE-Users: Sorry). The following
posting describes how to do automatic tweets from the Oracle database using the
Twitter4j library and some Java and PL/SQL coding with the "own" twitter account; the
library allows also authorization for other Twitter accounts - but this is not
described here.&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Step  1: Register your application on "dev.twitter.com"&lt;/b&gt;:&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Log into &lt;a href="http://dev.twitter.com/" target="_blank"&gt;dev.twitter.com&lt;/a&gt;
with your Twitter account. In the menu in the upper right corner (where you can see your
Twitter username) navigate to &lt;b&gt;My Applications&lt;/b&gt; and click on 
&lt;b&gt;Create a new Application&lt;/b&gt;. Then fill in the form. You need a name, a description
and a Website URL (which don't need to work for now). The callback URL is not needed - after
that manage the CAPTCA and your application is registered.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-EUbydMg1LC4/TnMeBD-xPsI/AAAAAAAAAH4/VKXn6aYNb0c/s1600/img01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="189" src="http://3.bp.blogspot.com/-EUbydMg1LC4/TnMeBD-xPsI/AAAAAAAAAH4/VKXn6aYNb0c/s320/img01.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;i&gt;Register your application&lt;/i&gt; &lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
You now see the key pair (&lt;i&gt;Consumer Key&lt;/i&gt; and &lt;i&gt;Consumer Secret&lt;/i&gt;) for your
application. We will need that later on.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-IxCYFlxYZmA/TnMeBPDwT7I/AAAAAAAAAIA/1PzMC-2jVew/s1600/img02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="218" src="http://2.bp.blogspot.com/-IxCYFlxYZmA/TnMeBPDwT7I/AAAAAAAAAIA/1PzMC-2jVew/s320/img02.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;i&gt; The application has been registered.&lt;/i&gt; &lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Now navigate to the &lt;b&gt;Settings&lt;/b&gt; tab and adjust the Privileges of your
Application. It will need
&lt;b&gt;Read and Write&lt;/b&gt; privileges, since a tweet is a "Write".
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-I67plIM6yBY/TnMeBU7TCHI/AAAAAAAAAII/eBx4UeCco-I/s1600/img03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="175" src="http://2.bp.blogspot.com/-I67plIM6yBY/TnMeBU7TCHI/AAAAAAAAAII/eBx4UeCco-I/s320/img03.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;i&gt;Grant "Read and Write" privileges to the application&lt;/i&gt; &lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Then go back to the &lt;b&gt;Details&lt;/b&gt; tab and navigate down to the button named
&lt;b&gt;Create My Access Token&lt;/b&gt; - this will generate the keys for your account.
(&lt;i&gt;Access Token&lt;/i&gt; and &lt;i&gt;Access Token Secret&lt;/i&gt;). Our application has to
create a signature using the two application keys as well as the two account keys - but
the Twitter4j library will do the necessary stuff.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-cRvb8MddPTk/TnMeBpP0acI/AAAAAAAAAIQ/m7XUIaQb0ZI/s1600/img04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="224" src="http://4.bp.blogspot.com/-cRvb8MddPTk/TnMeBpP0acI/AAAAAAAAAIQ/m7XUIaQb0ZI/s320/img04.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Generated "Access Token" and "Access Token Secret"&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Now you're done with registering the application. We can now start the implementation
in the Oracle database.&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Step 2: Load the "twitter4j" library into the database.&lt;/b&gt;&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Download &lt;b&gt;twitter4j&lt;/b&gt; from &lt;a href="http://www.twitter4j.org/" target="_blank"&gt;twitter4j.org&lt;/a&gt;.
Twitter4j is Open Source software and it uses the Apache License. So you are free to use
for either commercial or non-commercial usage without a fee. Unpack the ZIP archive into
a folder of your choice - it's best to place it directly on the database server.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-JDCUZ2165c4/TnMeBioS0gI/AAAAAAAAAIY/aZvWFNm0jU0/s1600/img05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="241" src="http://2.bp.blogspot.com/-JDCUZ2165c4/TnMeBioS0gI/AAAAAAAAAIY/aZvWFNm0jU0/s320/img05.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;i&gt;Contents of the downloaded ZIP archive&lt;/i&gt; &lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The java libraries are located in the subfolder &lt;b&gt;lib&lt;/b&gt;. For simple status updates (tweets)
the archive &lt;b&gt;twitter4j-core-2.2.4.jar&lt;/b&gt; is sufficient. Load it into the Oracle database as follows.
&lt;pre&gt;$ loadjava -user {dbuser}/{dbpassword} -o -r -v twitter4j-core-2.2.4.jar
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
You will see some error messages at the end of the loading process, which you can ignore.
&lt;pre&gt;skipping : resource META-INF/maven/org.twitter4j/twitter4j-core/pom.xml
skipping : resource META-INF/maven/org.twitter4j/twitter4j-core/pom.properties
The following operations failed
    class twitter4j/internal/logging/SLF4JLogger: resolution
    class twitter4j/internal/logging/SLF4JLoggerFactory: resolution
exiting  : Failures occurred during processing
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Step 3: Create a java method doing a status update&lt;/b&gt;&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
It would be a lot of work to map all the API methods to PL/SQL procedures and functions. There
are many methods and most of the have java objects in their signature. It's better to implement
the needed operations as Java methods with simple signatures and finally map those java methods
to PL/SQL. So the following code creates a simple java method "updateStatus" which can be 
mapped to PL/SQL very easily. This java code has been created based on the twitter4j examples, which
are also part of the downloaded archive. Note the placeholders for the key pairs from &lt;b&gt;dev.twitter.com&lt;/b&gt;
in the call of &lt;b&gt;setOAuthAccessToken&lt;/b&gt; which need to be replaced. The calls to &lt;b&gt;System.setProperty&lt;/b&gt; 
in the previous lines also contain placeholders for the proxy server and port, which also need to be adjusted to
your environment.
&lt;pre&gt;create or replace and compile java source named TwitterStatusUpdate as
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.conf.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; twitter4j.auth.*;

&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.io.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.util.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; oracle.jdbc.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; oracle.sql.*;
&lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; java.sql.*;

&lt;span style="color: seagreen;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt; UpdateStatus {
  &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt; Twitter twitter = &lt;span style="color: magenta;"&gt;null&lt;/span&gt;;

  &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt;  {
    System.setProperty(&lt;span style="color: magenta;"&gt;"http.proxyHost"&lt;/span&gt;, &lt;span style="color: magenta;"&gt;"&lt;i&gt;{Proxy server, if required}&lt;/i&gt;"&lt;/span&gt;);
    System.setProperty(&lt;span style="color: magenta;"&gt;"http.proxyPort"&lt;/span&gt;, &lt;span style="color: magenta;"&gt;"&lt;i&gt;{Proxy server port, if required}&lt;/i&gt;"&lt;/span&gt;);
  
    ConfigurationBuilder confbuilder  = &lt;span style="color: #804040;"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/span&gt; ConfigurationBuilder(); 
    confbuilder.setOAuthAccessToken(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Access token from dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthAccessTokenSecret(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Access token secret from dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthConsumerKey(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Consumer key from dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;) 
    .setOAuthConsumerSecret(&lt;span style="color: magenta;"&gt;"&lt;i&gt;{Consumer secret from dev.twitter.com}&lt;/i&gt;"&lt;/span&gt;); 
    twitter = &lt;span style="color: #804040;"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/span&gt; TwitterFactory(confbuilder.build()).getInstance(); 
  }

  &lt;span style="color: seagreen;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/span&gt; String updateStatus(String newStatus) &lt;span style="color: seagreen;"&gt;&lt;b&gt;throws&lt;/b&gt;&lt;/span&gt; Exception {
    Status status = twitter.updateStatus(newStatus);
    &lt;span style="color: #804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; status.getText();
  }
}
/
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Step 4: Create the PL/SQL wrapper&lt;/b&gt;&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
The created Java method "updateStatus" just takes and returns a java string. The mapping to SQL and
PL/SQL is, as already stated, very easy: 
&lt;pre&gt;&lt;span style="color: teal;"&gt;create&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;replace&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; set_twitter_status(p_new_status &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;) &lt;span style="color: #804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; &lt;span style="color: seagreen;"&gt;&lt;b&gt;varchar2&lt;/b&gt;&lt;/span&gt;
&lt;span style="color: #804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;language&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;java&lt;/b&gt;&lt;/span&gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/span&gt; &lt;span style="color: magenta;"&gt;'UpdateStatus.updateStatus(java.lang.String) return java.lang.String'&lt;/span&gt;;
&lt;span style="color: #804040;"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/span&gt;
sho err
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Step 5: Grant privileges&lt;/b&gt;&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Doing a tweet is a network request. A "normal" database user does not have privileges
to execute network operations in Java. To get the above java class actually working the
database schema needs java privileges to set the proxy server (if needed) and to do
the network operation. The following SQL script, which has to be executed with DBA privileges,
does the job.
&lt;pre&gt;&lt;span style="color: slateblue;"&gt;begin&lt;/span&gt;
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.util.PropertyPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'http.proxyHost'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'read,write'&lt;/span&gt; 
  );
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.util.PropertyPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'http.proxyPort'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'read,write'&lt;/span&gt; 
  );
  dbms_java.grant_permission( 
    &lt;span style="color: magenta;"&gt;'{DB-SCHEMA}'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'SYS:java.net.SocketPermission'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'api.twitter.com:80'&lt;/span&gt;, &lt;span style="color: magenta;"&gt;'connect, resolve'&lt;/span&gt; 
  );
&lt;span style="color: slateblue;"&gt;end&lt;/span&gt;;
/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
&lt;b&gt;Final testing&lt;/b&gt;&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
And then you are done. Try it ...
&lt;pre&gt;SQL&amp;gt; select set_twitter_status('another test at friday') from dual;

SET_TWITTER_STATUS('ANOTHERTESTATFRIDAY')
------------------------------------------------------------------------
another test at friday

1 row selected.
&lt;/pre&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Point your browser to your twitter page - you should see that posing - done by SQL in
the Oracle database. From this point we can use this procedure as any other one. 
Creating a DBMS_SCHEDULER job is as easy as creating an APEX application from which
tweets are being posted. A simple example is an APEX application with a form on a table
where the user can enter a tweet and a timestamp at which to post the tweet. A DBMS_SCHEDULER
job runs in regular intervals an posts all tweets due. The twitter4j API allows much
more operations ... we could query the &lt;i&gt;Home Timeline&lt;/i&gt; and pass it back to the
SQL - but this is another story ... for another blog posting ...&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-2501414756131811256?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/NFZiMziqmjI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/NFZiMziqmjI/twitter-postings-mit-der-datenbank-sql.html</link><author>noreply@blogger.com (Carsten Czarski)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-EUbydMg1LC4/TnMeBD-xPsI/AAAAAAAAAH4/VKXn6aYNb0c/s72-c/img01.png" height="72" width="72" /><thr:total>0</thr:total><georss:featurename>München, Deutschland</georss:featurename><georss:point>48.1391265 11.5801863</georss:point><georss:box>47.969588 11.2643293 48.308665000000005 11.896043299999999</georss:box><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/09/twitter-postings-mit-der-datenbank-sql.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-176350039734377461</guid><pubDate>Fri, 02 Sep 2011 08:18:00 +0000</pubDate><atom:updated>2011-09-05T15:44:32.446+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">community</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">dbms_xplan</category><title>Ausführungspläne mit DBMS_XPLAN</title><description>&lt;div lang="de"&gt;Heute wollte ich eigentlich ein Blog-Posting über die verschiedenen Möglichkeiten von &lt;b&gt;DBMS_XPLAN&lt;/b&gt; bringen ... das kann ja wesentlich mehr als &lt;b&gt;DBMS_XPLAN.DISPLAY()&lt;/b&gt;. Es ist allein schon lohnenswert, sich die verschiedenen Varianten des Parameters &lt;b&gt;FORMAT&lt;/b&gt; anzusehen. Allerdings haben meine Kollegen, die die &lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/apex/index.html" target="_blank"&gt;DBA Community-Seite&lt;/a&gt; betreiben, hierzu schon einiges geschrieben ... und man soll das Rad nicht neu erfinden. Daher verweise ich heute einfach nur auf den entsprechenden &lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/dbadmin/tipps/dbms_xplan/index.html" target="_blank"&gt;Community-Tipp&lt;/a&gt;.  &lt;/div&gt;&lt;div lang="de"&gt;Viel Spaß beim Lesen!&lt;/div&gt;&lt;div lang="en" style="display: none;"&gt;My intention for today was a Blog Posting about the  &lt;b&gt;DBMS_XPLAN&lt;/b&gt; package - this package can do much more than just &lt;b&gt;DBMS_XPLAN.DISPLAY()&lt;/b&gt;. For instance - looking at the variants of the &lt;b&lt;FORMAT&lt;/b&gt; argument is worthful for its own. But the collegues maintaining the &lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/apex/index.html" target="_blank"&gt;german DBA Community pages&lt;/a&gt; have done a lot of work on this, and I don't want to reinvent the wheel. German readers might just continue reading the &lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/dbadmin/tipps/dbms_xplan/index.html" target="_blank"&gt;Community How To on "Execution Plans"&lt;/a&gt;; english readers might try &lt;a href="http://translate.google.com/translate?sl=de&amp;tl=en&amp;js=n&amp;prev=_t&amp;hl=de&amp;ie=UTF-8&amp;layout=2&amp;eotf=1&amp;u=http%3A%2F%2Fwww.oracle.com%2Fwebfolder%2Ftechnetwork%2Fde%2Fcommunity%2Fdbadmin%2Ftipps%2Fdbms_xplan%2Findex.html" target="_blank"&gt;the "Google-Translate" version&lt;/a&gt;. &lt;/div&gt;&lt;div lang="en" style="display: none"&gt;Have fun!&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-176350039734377461?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/VzunbyYd9Pc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/VzunbyYd9Pc/ausfuhrungsplane-mit-dbmsxplan.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>1</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/09/ausfuhrungsplane-mit-dbmsxplan.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-1191902608750809537</guid><pubDate>Mon, 01 Aug 2011 08:10:00 +0000</pubDate><atom:updated>2011-08-01T09:19:33.262+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">UTL_HTTP</category><category domain="http://www.blogger.com/atom/ns#">httpuritype</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">browser</category><title>Der Browser in eurer Datenbank: HTTPURITYPE</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;The simple browser in your database: HTTPURITYPE&lt;/div&gt;
&lt;div lang="de"&gt;
 Wenn es darum geht, HTTP-Zugriffe aus der Datenbank heraus zu machen, ist das Paket
 UTL_HTTP natürlich das Mittel der Wahl - damit kann ein Browser komplett imitiert werden;
 vom Setzen der HTTP Header Felder oder von Cookies bis hin zu den HTTP Methoden GET und POST
 ist alles drin, was man braucht.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
  When it's about doing HTTP requests with PL/SQL - there's only one answer: UTL_HTTP. UTL_HTTP
  allows you to mimick a web browser completely in the database - one can set cookies, HTTP headers,
  do GET and POST requests and much more.
&lt;/div&gt;
&lt;div lang="de"&gt;
 In vielen Fällen braucht man das alles aber nicht - es muss einfach nur etwas per
 HTTP abgerufen werden. Und für genau diese Fälle gibt es die ganz einfache Variante: HTTPURITYPE - das
 kann man nutzen wie eine SQL-Funktion und es macht die ganze Arbeit auf einmal.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
  But in most cases these cool stuff is just not needed - all we want to do is a
  simple, plain HTTP request - no cookies, no special HTTP headers; nothing. And yes: There
  is a simple variant: HTTPURITYPE can be used like a SQL function and it does the whole
  work in one shot.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
select httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default') from dual
/

HTTPURITYPE('HTTP://SQL-PLSQL-DE.BLOGSPOT.COM/FEEDS/POSTS/DEFAULT')(URL)
--------------------------------------------------------------------------------
HTTPURITYPE('sql-plsql-de.blogspot.com/feeds/posts/default')

1 row selected.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Da passiert erstmal noch nix ... Los geht's, wenn Ihr den Content selbst mit
 GETBLOB(), GETCLOB() oder GETXML() abruft. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 Not much at the first glance. To have the database actually do the HTTP request you
 need to add one of the methods GETXML(), GETBLOB() or GETCLOB() ...
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
select httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default').getxml() from dual
/

ERROR:
ORA-29273: HTTP-Anforderung nicht erfolgreich
ORA-06512: in "SYS.UTL_HTTP", Zeile 1819
ORA-12543: TNS: Ziel-Host ist nicht erreichbar
ORA-06512: in "SYS.HTTPURITYPE", Zeile 34
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Alles klar, dann setzen wir noch den Proxy ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 Ok, ok ... go ahead and set the proxy server ...
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
begin
  utl_http.set_proxy('{proxy-host}:{proxy-port}');
end;
/

select httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default').getxml() from dual
/

HTTPURITYPE('HTTP://SQL-PLSQL-DE.BLOGSPOT.COM/FEEDS/POSTS/DEFAULT').GETXML()
--------------------------------------------------------------------------------
&amp;lt;?xml version="1.0" encoding="CP850"?&amp;gt;
&amp;lt;?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?&amp;gt;

&amp;lt;?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.co
m/~d/styles/itemcontent.css"?&amp;gt;
&amp;lt;rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/
spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:thr="htt
&amp;lt;/
&lt;/textarea&gt;
&lt;div lang="de"&gt;
  Voilá. HTTPURITYPE kann den Code wirklich ganz massiv
  vereinfachen - und wenn eine einfache Lösung ausreicht, dann soll man diese ja auch
  nutzen. Und als kleinen Exkurs kann man das Beispiel ja noch fortsetzen, indem man das
  XML auch direkt zerlegt ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
  And that's it - HTTPURITYPE is a great code simplification when it's about
  HTTP and PL/SQL. And we could continue this example and start to shred the XML we got
  back ...
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
with xml as (
  select httpuritype('http://sql-plsql-de.blogspot.com/feeds/posts/default').getxml() as doc
  from dual
)
select 
  t.titel,
  t.pubdate,
  t.link
from xml, xmltable(
  'for $i in //item return $i'
  passing xml.doc
  columns 
    titel   varchar2(100) path '/item/title/text()',
    pubdate varchar2(35)  path '/item/pubDate/text()',
    link    varchar2(500) path '/item/link/text()'
) t
/

TITEL                          PUBDATE                             LINK
------------------------------ ----------------------------------- ------------------------------
DELETE löscht ... und das ist  Mon, 18 Jul 2011 09:00:00 +0000     http://sql-plsql-de.blogspot.c
es, oder ...?                                                      om/2011/07/delete-loscht-und-d
                                                                   as-ist-es-oder.html

Schon gewusst ...? Multi Table Mon, 04 Jul 2011 11:46:00 +0000     http://sql-plsql-de.blogspot.c
 Insert                                                            om/2011/07/schon-gewusst-multi
                                                                   -table-insert.html

Kleine Statistikvorlesung: Mit Fri, 10 Jun 2011 09:11:00 +0000     http://sql-plsql-de.blogspot.c
 der Datenbank                                                     om/2011/06/kleine-statistikvor
&lt;/textarea&gt;
&lt;div lang="de"&gt;
  Einen RSS-Feed abholen und direkt zerlegen - mit nur einer SQL-Abfrage. Einfacher geht es nun
  wirklich nicht.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 Fetching an RSS feed and parsing it into a database table with just one SQL query - there is no simpler
 way ...
&lt;/div&gt;
&lt;div lang="de"&gt;
 Ach ja ... fast hätte ich das vergessen. Ab Oracle11g braucht Ihr noch zusätzliche Netzwerk-Privilegien,
 damit Ihr aus der Datenbank überhaupt herauskommt: Mit dem PL/SQL-Paket &lt;b&gt;DBMS_NETWORK_ACL_ADMIN&lt;/b&gt;
 müsst Ihr uerem Datenbankuser für die einzelnen Netzwerkziele freischalten. Wie das geht, ist in
 &lt;a href="http://sql-plsql-de.blogspot.com/2008/11/mehr-sicherheit-in-oracle11g-plsql.html"
    target="_blank"&gt;diesem Blog-Posting&lt;/a&gt; beschrieben.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 And (last but not lease) one important point: On Oracle11g (or higher) you need special
 networking privileges - EXECUTE on UTL_HTTP is not sufficient. Using the package &lt;b&gt;DBMS_NETWORK_ACL_ADMIN&lt;/b&gt;
 the DBA needs to enable the individual network "targets" for a specific database user. The
  &lt;a href="http://sql-plsql-de.blogspot.com/2008/11/mehr-sicherheit-in-oracle11g-plsql.html"
    target="_blank"&gt;blog posting&lt;/a&gt; describes the process.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-1191902608750809537?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/4tvSg6ElnMc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/4tvSg6ElnMc/der-browser-in-eurer-datenbank.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/08/der-browser-in-eurer-datenbank.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-228678808043232502</guid><pubDate>Fri, 29 Jul 2011 07:27:00 +0000</pubDate><atom:updated>2011-07-29T08:33:54.008+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ols_regression</category><title>Kleine Statistikvorlesung ... Fortsetzung auf einem neuen Blog</title><description>&lt;div style="display: none" lang="en"&gt;This posting is about a german only posting in another blog and therefore german only.&lt;/div&gt;
&lt;div lang="de"&gt;
Vor kurzem hatte ich ja das Blog Posting zum Thema &lt;a href="http://sql-plsql-de.blogspot.com/2011/06/kleine-statistikvorlesung-mit-der.html" target="_blank"&gt;Kleine Statistikvorlesung mit der Oracle-Datenbank&lt;/a&gt;, in dem ich die einfache lineare Regression gezeigt habe. In der Praxis ist aber öfter die anspruchsvollere multiple Regression mit mehreren Variablen gefordert, wozu es erstmal keine einfache SQL-Funktion gibt.
&lt;/div&gt;
&lt;div lang="de"&gt;
Aber die Datenbank kann es doch! Wie immer, eigentlich. &lt;b&gt;Thomas Uhren&lt;/b&gt; beschreibt &lt;a href="http://ora-sql-plsql.blogspot.com/"&gt;in seinem Blog&lt;/a&gt;, wie man das mit &lt;a href="http://ora-sql-plsql.blogspot.com/2011/07/multiple-regression-mit-olsregression.html"&gt;dem PL/SQL-Paket OLS_REGRESSION&lt;/a&gt; hinbekommen kann. Auf jeden Fall mal reinschauen. Viel Spaß beim Lesen.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-228678808043232502?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/RADtYiYMwEg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/RADtYiYMwEg/kleine-statistikvorlesung-fortsetzung.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/07/kleine-statistikvorlesung-fortsetzung.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-3233473695203425097</guid><pubDate>Mon, 18 Jul 2011 09:00:00 +0000</pubDate><atom:updated>2011-07-18T10:01:41.466+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">delete</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>DELETE löscht ... und das ist es, oder ...?</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;DELETE deletes ... that's it ...?&lt;/div&gt;
&lt;div lang="de"&gt;
 Ein SQL &lt;b&gt;DELETE&lt;/b&gt; löscht Zeilen von einer Tabelle - das ist bekannt. Und ein DELETE hat 
 eine WHERE-Klausel, die festlegt, welche Zeilen gelöscht werden sollen - das ist auch
 bekannt. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 A SQL DELETE statement deletes rows from a table - that is nothing new. And a DELETE also
 has a WHERE clause which determines the rows to delete from the table - this is also no
 news.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
delete from emp where sal &amp;gt; 2000
/

6 rows deleted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Doch was ist, wenn ich die Zeilen, die gelöscht werden sollen, nur durch einen
 Join mit einer anderen Tabelle ermitteln kann?  Als Beispiel möchte ich alle Mitarbeiter
 löschen, die in &lt;b&gt;DALLAS&lt;/b&gt; arbeiten. Das steht in der &lt;b&gt;EMP&lt;/b&gt;-Tabelle aber nicht drin - ich
 muss in die &lt;b&gt;DEPT&lt;/b&gt;-Tabelle gucken. Aus der soll aber nichts gelöscht werden ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 But what if I need to look into another table, to determine the rows to be deleted? 
 As an example, I would like to delete all rows representing
 employees based in &lt;b&gt;DALLAS&lt;/b&gt;. This information is not contained in the &lt;b&gt;EMP&lt;/b&gt; table. I need
 to look into &lt;b&gt;DEPT&lt;/b&gt; - but I do not want to delete anything from &lt;b&gt;DEPT&lt;/b&gt; ...
 &lt;/div&gt;
&lt;div lang="de"&gt;
 Es wird selten gemacht, aber man kann bei SQL DML-Kommandos anstelle einer
 Tabelle oder View (zur Wirkung von DML auf Views gibt es schon 
 &lt;a href="http://sql-plsql-de.blogspot.com/2009/07/views-und-dml-operationen-updatable.html"
    target="_blank"&gt;ein Blog-Posting&lt;/a&gt;) auch
 eine SQL-Abfrage verwenden. Ein einfaches Beispiel: Anstelle der Tabelle &lt;b&gt;EMP&lt;/b&gt; 
 setze ich ein SELECT ein.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 It's not used very frequently - but you can use a SQL query in a SQL DML statement instead of a 
 table or view (
 regarding views and DML I already had 
 &lt;a href="http://sql-plsql-de.blogspot.com/2009/07/views-und-dml-operationen-updatable.html"
    target="_blank"&gt;a blog posting in 2010 Blog-Posting&lt;/a&gt;). A simple example: I'll
 replace the table &lt;b&gt;EMP&lt;/b&gt; with a SQL query.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
delete from (select * from emp) where sal &amp;gt; 2000
/

6 rows deleted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Das funktioniert genauso. Im Grunde genommen gilt von nun an das gleiche wie für
 &lt;a href="http://sql-plsql-de.blogspot.com/2009/07/views-und-dml-operationen-updatable.html" 
    target="_blank"&gt;DML-Kommandos auf Views&lt;/a&gt;.  Solange ein DML-Kommando auf eine View
 ohne INSTEAD OF Trigger funktioniert, kann man die View-Abfrage auch direkt ins DML aufnehmen.
 Also können wir die o.g. Aufgabenstellung wie folgt lösen:
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 This works - so we can try to use more complex subqueries in our DELETE statement. 
 Oracle, basically, applies the same rules as for using Views in DML statements - so 
 if a DML statement works on a view, (without an INSTEAD OF trigger) it will also work with
 the view query directly embedded into the DML command. So we can solve the initial
 problem as follows:
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
delete from (
  select empno from emp e join dept d on (e.deptno = d.deptno)
  where d.loc = 'DALLAS'
)
/

5 rows deleted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Wenn ich das SQL wie oben formuliere, könnte man ja die Frage stellen,
 ob nicht aus beiden Tabellen Zeilen gelöscht werden - man verwendet ja auch beide Tabellen
 in der SQL-Abfrage. Hier ist Oracle aber recht eindeutig - zunächst löscht Oracle grundsätzlich nur aus
 &lt;i&gt;einer&lt;/i&gt; Basistabelle Zeilen (&lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17120/views001.htm#i1006232" target="_blank"&gt;siehe Dokumentation: &lt;i&gt;General Rule&lt;/i&gt;&lt;/a&gt;). Dann
 stellt sich aber die Frage: &lt;i&gt;Wie&lt;/i&gt; entscheidet Oracle, aus welche Tabelle die Zeilen gelöscht
 werden sollen - warum nimmt Oracle die &lt;b&gt;EMP&lt;/b&gt;-Tabelle und nicht die &lt;b&gt;DEPT&lt;/b&gt;-Tabelle?
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt; 
 But now one question arises: If I have a SQL like the example above: from which 
 table will Oracle delete rows? The SQL query references the &lt;b&gt;EMP&lt;/b&gt; table 
 as well as &lt;b&gt;DEPT&lt;/b&gt;. So will
 Oracle delete rows from &lt;b&gt;EMP&lt;/b&gt; ... or from &lt;b&gt;DEPT&lt;/b&gt; ... or from &lt;i&gt;both&lt;/i&gt; ...?
 As a general rule, Oracle will delete rows from &lt;i&gt;only one&lt;/i&gt; base table (&lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17120/views001.htm#i1006232" target="_blank"&gt;see the documentation: &lt;i&gt;General Rule&lt;/i&gt;&lt;/a&gt;). 
 But how does Oracle decide, from which table ...?
&lt;/div&gt; 
&lt;div lang="de"&gt;
 Hier kommt jetzt das Konzept der &lt;i&gt;Key-Preserved Table&lt;/i&gt; ins Spiel. In einem Join
 sind die Tabellen &lt;i&gt;Key-Preserved&lt;/i&gt;, die Ihre Schlüssel auch im Ergebnis des
 Joins behalten. Der obige Join ist so definiert, dass alle Zeilen der Tabelle &lt;b&gt;EMP&lt;/b&gt; 
 zurückgeliefert werden und die &lt;b&gt;DEPTNO&lt;/b&gt; dupliziert wird. Also 
 ist &lt;b&gt;EMPNO&lt;/b&gt; auch im Join-Ergebnis immer noch eindeutig. Für die Tabelle
 &lt;b&gt;DEPT&lt;/b&gt; sieht es anders aus - deren Schlüssel DEPTNO ist im Join-Ergebnis nicht mehr
 eindeutig. Wichtig ist, dass sich diese Eigenschaft nicht nach der tatsächlichen
 Ergebnismenge des Joins richtet, sondern nach dem konkreten Join und der Tabellendefinition
 im Datenbankschema. Daher gibt es in diesem Beispiel genau eine &lt;i&gt;Key-Preserved Table&lt;/i&gt; und
 aus der werden die Zeilen gelöscht.  Mehr zum Thema Key-Preserved Tables findet sich (wie immer)
 &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17120/views001.htm#ADMIN11783"
    target="_blank"&gt;in der Dokumentation&lt;/a&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Now we need to look at the concept of a &lt;i&gt;Key-Preserved Table&lt;/i&gt;. In a join,
 the tables which &lt;i&gt;keep&lt;/i&gt; their unique key in the join result, are &lt;i&gt;Key-Preserved&lt;/i&gt;. In our
 example we have a join, which keeps all the rows from &lt;b&gt;EMP&lt;/b&gt; and which looks up
 values from &lt;b&gt;DEPT&lt;/b&gt;. So in the result the "key" &lt;b&gt;EMP.EMPNO&lt;/b&gt; is being &lt;i&gt;preserved&lt;/i&gt; 
 and "key" &lt;b&gt;DEPT.DEPTNO&lt;/b&gt; is lost (values were duplicated). So the table &lt;b&gt;EMP&lt;/b&gt; is 
 key-preserved in that join.  Note
 that this does &lt;i&gt;not&lt;/i&gt; depend on the actual result set data, but on the join itself and 
 the table definition
 in the database schema. So Oracle will delete rows from &lt;b&gt;EMP&lt;/b&gt; and not from &lt;b&gt;DEPT&lt;/b&gt;.
 More about Key-Preserved Tables can be found in the 
 &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e17120/views001.htm#ADMIN11783"
    target="_blank"&gt;documentation&lt;/a&gt;.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Nun sind auch andere Beispiele denkbar: ich möchte alle Zeilen aus &lt;b&gt;DEPT&lt;/b&gt; löschen,
 zu denen es keine Einträge in &lt;b&gt;EMP&lt;/b&gt; gibt. Hierzu brauche ich noch nicht einmal einen 
 Join.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Another example - now without a join: I want to delete all rows from &lt;b&gt;DEPT&lt;/b&gt; 
 which habe no corresponding rows in &lt;b&gt;EMP&lt;/b&gt;.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
 delete from (
  select deptno 
  from dept 
  where deptno not in (select deptno from emp)
)
/

1 row deleted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Es bestätigt sich immer wieder: SQL ist eine unglaublich mächtige Sprache.
 Viele Dinge, die man prozedural recht aufwändig programmieren
 muss, lassen sich mit SQL sehr elegant erledigen ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 It proves all the time. SQL is a very powerful language - and many problems, which would
 require cumbersome procedural logic, can often be solved with simple, elegant SQL statements ...
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-3233473695203425097?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/07GozX57FRE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/07GozX57FRE/delete-loscht-und-das-ist-es-oder.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/07/delete-loscht-und-das-ist-es-oder.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-3795169014990778990</guid><pubDate>Mon, 04 Jul 2011 11:46:00 +0000</pubDate><atom:updated>2011-07-04T12:48:18.932+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">insert</category><title>Schon gewusst ...? Multi Table Insert</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Did you know ..? Multi Table Insert&lt;/div&gt;
&lt;div lang="de"&gt;
 Normalerweise macht man ein SQL INSERT in genau eine Tabelle - die Syntax ist ja auch
 INSERT INTO {TABLE}. Wusstet Ihr, dass man mit einem SQL INSERT jedoch auch in meherer
 Tabellen gleichzeitig einfügen kann. Und ich meine nun nicht das SQL INSERT in eine
 VIEW und das Verteilen per INSTEAD-OF Trigger (hierzu gab es schonmal ein &lt;a href="http://sql-plsql-de.blogspot.com/2009/07/views-und-dml-operationen-updatable.html" target="_blank"&gt;Blog Posting&lt;/a&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;A SQL INSERT normally does the INSERT operation in exactly
 one table. Did you know that you also can insert data into multiple tables at the same time. And
 I do &lt;i&gt;not&lt;/i&gt; mean creating a view with an INSTEAD OF Trigger (there already was a &lt;a href="http://sql-plsql-de.blogspot.com/2009/07/views-und-dml-operationen-updatable.html?lang=en" target="_blank"&gt;Blog Posting&lt;/a&gt; about that.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Nein, ich meine den sog. &lt;i&gt;Multi-Table-Insert&lt;/i&gt;. Dazu ein Beispiel. Zuerst erstellen 
 wir die Zieltabellen, die zugegebenermaßen recht einfach gestrickt sind, aber für ein einfaches
 Beispiel sollte das reichen ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;Today I'll talk about the &lt;i&gt;multi-table-insert&lt;/i&gt; feature of
 the Oracle database. This is best described with an example. First we will create some tables ...
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
create table emp10 as select empno, ename, job, hiredate, mgr, sal, comm from emp where 1=0
/

create table emp20 as select empno, ename, job, hiredate, mgr, sal, comm from emp where 1=0
/
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Und dann probieren wir unseren ersten &lt;i&gt;Multi Table Insert&lt;/i&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 And then we'll do our first &lt;i&gt;Multi Table Insert&lt;/i&gt;.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
insert all
  into emp10 values (empno, ename, job, hiredate, mgr, sal, comm)
  into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
select * from emp
/

28 rows inserted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
  Man sieht, dass danach beide Tabellen gefüllt sind - mit einem einzigen INSERT-Kommando. Doch
  das ist noch nicht alles. Wie man den Tabellennamen schon ansehen kann, möchten wir bestimmte
  Zeilen in bestimmte Tabellen haben ... und auch das geht mit dem Multi-Table-Insert.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 You'll see that both tables are being populated - with just &lt;i&gt;one&lt;/i&gt; SQL INSERT  command. But 
 this example was rather simple - As the table names indicate we want to have different rows
 from the source table into different target tables. That is no problem at all ...
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
insert all
  when deptno = 10 then 
    into emp10 values (empno, ename, job, hiredate, mgr, sal, comm)
  when deptno = 20 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
select * from emp
/

8 rows inserted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Und auch das funktioniert - abhängig von der DEPTNO gehen die Zeilen in unterschiedliche
 Tabellen. Das kann noch mit einer ELSE-Anweisung kombiniert werden ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 That also works. And we can add an &lt;b&gt;ELSE&lt;/b&gt; clause to handle "all others".
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
create table emp_other as select empno, ename, job from emp where 1=0
/

insert all
  when deptno = 10 then 
    into emp10 values (empno, ename, job, hiredate, mgr, sal, comm)
  when deptno = 20 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
  else
    -- Here are the "other" ones - only EMPNO, ENAME and JOB
    into emp_other values (empno, ename, job)
select * from emp
/

14 rows inserted.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
  Bislang wurden stets alle WHEN-Klauseln beachtet - die Klauseln selbst schließen
  sich ja schon gegenseitig aus. Anders sieht es hier aus ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 In these examples Oracle evaluated &lt;i&gt;all&lt;/i&gt; &lt;b&gt;WHEN&lt;/b&gt; clauses. Even when a row
 was processed - the other WHEN clauses were also evaluated. So far this did not make
 a difference, because the WHEN clauses were mutually exclusive. In the next example
 we'll have table rows matching multiple WHEN clauses.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
create table emp_highsal as select empno, ename, job, sal from emp where 1=0
/

insert all
  when sal &amp;gt; 3000 then 
    into emp_highsal values (empno, ename, job, sal)
  when deptno = 10 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
  when deptno = 20 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
  else
    -- Here are the "other" ones - only EMPNO, ENAME and JOB
    into emp_other values (empno, ename, job)
select * from emp
/

15 rows created.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
  &lt;b&gt;KING&lt;/b&gt; gehört zur DEPTNO &lt;b&gt;10&lt;/b&gt; und hat ein SAL größer als &lt;b&gt;3000&lt;/b&gt;. Er landet also
  sowohl in der Tabelle &lt;b&gt;EMP_HIGHSAL&lt;/b&gt;, als auch in &lt;b&gt;EMP10&lt;/b&gt;. 
  Unter Umständen sollen diejenigen Zeilen, die in &lt;b&gt;EMP_HIGHSAL&lt;/b&gt; eingefügt wurden,
  &lt;i&gt;nicht&lt;/i&gt; mehr weiter verarbeitet werden - es soll also nach der ersten passenden
  WHEN-Klausel aufgehört werden. Auch das geht - statt INSERT ALL schreiben wir dann
  INSERT FIRST. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 &lt;b&gt;KING&lt;/b&gt; belongs to DEPTNO &lt;b&gt;10&lt;/b&gt; as well as the SAL is greater then &lt;b&gt;3000&lt;/b&gt;. So the
 row is inserted in both &lt;b&gt;EMP_HIGHSAL&lt;/b&gt; and &lt;b&gt;EMP10&lt;/b&gt;. But there might be cases where
 the row may only be inserted into &lt;i&gt;one&lt;/i&gt; table - evaluation shoud stop after the first
 matching &lt;b&gt;WHEN&lt;/b&gt; clause. To achieve this we use &lt;b&gt;INSERT FIRST&lt;/b&gt; instead of &lt;b&gt;INSERT ALL&lt;/b&gt;.
&lt;/div&gt;
&lt;textarea name="code" class="sql"&gt;
insert first
  when sal &amp;gt; 3000 then 
    into emp_highsal values (empno, ename, job, sal)
  when deptno = 10 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
  when deptno = 20 then
    into emp20 values (empno, ename, job, hiredate, mgr, sal, comm)
  else
    -- Here are the "other" ones - only EMPNO, ENAME and JOB
    into emp_other values (empno, ename, job)
select * from emp
/

14 rows created.
&lt;/textarea&gt;
&lt;div lang="de"&gt;
 Die Tatsache, dass viele INSERTs in einem Kommando abgearbeitet werden,
 kann die Performance bei großen Datenmengen extrem beeinflussen - denn die 
 Quelldaten werden beim Multi-Table-Insert nur einmal durchgearbeitet - würde man
 einzelne INSERT-Anweisungen machen, würden die Daten für &lt;i&gt;jedes INSERT&lt;/i&gt; einmal
 durchgescannt.  Mehr Info in der Dokumentation: &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e16579/transform.htm#i1006530" target="_blank"&gt;http://download.oracle.com/docs/cd/E11882_01/server.112/e16579/transform.htm#i1006530&lt;/a&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Multi Table Inserts can impact performance significantly: If you have a very
 huge "source" dataset this is being scanned only once - Individual INSERT statements
 on the other hand would cause the database scan the source data once &lt;i&gt;for each&lt;/i&gt;
 INSERT statement. More information is available in the documentation: &lt;a href="http://download.oracle.com/docs/cd/E11882_01/server.112/e16579/transform.htm#i1006530" target="_blank"&gt;http://download.oracle.com/docs/cd/E11882_01/server.112/e16579/transform.htm#i1006530&lt;/a&gt;.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-3795169014990778990?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/68dpyBbJucw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/68dpyBbJucw/schon-gewusst-multi-table-insert.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/07/schon-gewusst-multi-table-insert.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-7111375234277280356</guid><pubDate>Fri, 10 Jun 2011 09:11:00 +0000</pubDate><atom:updated>2011-06-10T10:14:23.265+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">Function</category><category domain="http://www.blogger.com/atom/ns#">statistic</category><category domain="http://www.blogger.com/atom/ns#">regression</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Kleine Statistikvorlesung: Mit der Datenbank</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Statistics lesson ... with the database&lt;/div&gt;
&lt;div lang="de"&gt;
 Heute machen wir eine kleine Statistikvorlesung - mit der Oracle-Datenbank. Es geht um
 die klassische, einfache lineare Regression. Das geht mit ganz einfachen SQL-Funktionen. Gegeben
 sei eine Tabelle, welche die getätigten Umsätze und die Ausgaben für TV-Werbung enthält.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Today we'll have a tiny "statistics lesson" - with the Oracle Database. We'll do a simple
 linear regression, just by using SQL functions. Let's start with a simple table containing
 numbers for revenue and advertising cost by month.
&lt;/div&gt;
&lt;pre&gt;
MONAT      UMSATZ_EUR WERBUNG_TV_EUR
---------- ---------- --------------
2009/11        130000          14000
2009/12        140000          13200
2010/01        100000           9000
2010/02        103000           9500
2010/03        112000          10000
2010/04         90000          12000
2010/05         98000          13000
2010/06         70000           4000
2010/07        109010          12000
2010/08        120000          10000
2010/09        130000           9000
2010/10        150000          15000
2010/11        170000          18000
2010/12        200000          18000
2011/01                        10000
2011/02                        10200
2011/03                        15200
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Die Statistikaufgabe wäre nun, den Umsatz der ersten drei Monate in 2011 anhand der
 Ausgaben für TV-Werbung zu prognostizieren - eine schöne Statistikaufgabe. Und für diesen
 Fall brauchen wir gar keinen Export nach Excel oder in eine Statistiksoftware - das
 machen wir direkt mit SQL ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 The exercise is now to forecast the revenue for 2011 - based on the spendings for
 TV advertising. This is a "classic" statistics exercise. And we don't need to export the
 data to Excel or to another statistics software - we'll do the job with SQL ...
&lt;/div&gt;
&lt;div lang="de"&gt;
 Zunächst stellen wir mit der "Methode der kleinsten Quadrate" den "Betrag" und die
 Steigung der linearen Funktion fest:
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 First we calculate the intercept and slope of the regression function using the
 &lt;i&gt;"least squares method"&lt;/i&gt;:
&lt;/div&gt;
&lt;pre&gt;
select 
   &lt;span style="color: red"&gt;REGR_INTERCEPT(UMSATZ_EUR, WERBUNG_TV_EUR)&lt;/span&gt; as A,
   &lt;span style="color: red"&gt;REGR_SLOPE(UMSATZ_EUR, WERBUNG_TV_EUR)&lt;/span&gt;     as B
from verkauf
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Wenn man das dann in eine &lt;i&gt;Inline View&lt;/i&gt; packt (&lt;b&gt;WITH&lt;/b&gt;-Klausel), dann kann man
 Analyse und Prognose direkt mit einer SQL-Abfrage machen ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Then we put this into an &lt;i&gt;inline view&lt;/i&gt; (&lt;b&gt;WITH&lt;/b&gt; clause) - so that we can
 do the analysis as well as the forecast in one SQL query ...
&lt;/div&gt;
&lt;pre&gt;
with regr_koeffizienten as (
 select 
   REGR_INTERCEPT(UMSATZ_EUR, WERBUNG_TV_EUR) as A,
   REGR_SLOPE(UMSATZ_EUR, WERBUNG_TV_EUR)     as B
 from verkauf
)
select 
  monat,
  umsatz_eur,
  werbung_tv_eur,
  a + b * WERBUNG_TV_EUR as UMSATZ_PROGNOSE
from VERKAUF, REGR_KOEFFIZIENTEN
/

MONAT      UMSATZ_EUR WERBUNG_TV_EUR UMSATZ_PROGNOSE
---------- ---------- -------------- ---------------
2009/11        130000          14000          138784
2009/12        140000          13200          132751
2010/01        100000           9000          101076
2010/02        103000           9500          104847
2010/03        112000          10000          108618
2010/04         90000          12000          123701
2010/05         98000          13000          131243
2010/06         70000           4000           63368
2010/07        109010          12000          123701
2010/08        120000          10000          108618
2010/09        130000           9000          101076
2010/10        150000          15000          146326
2010/11        170000          18000          168950
2010/12        200000          18000          168950
2011/01                        10000          108618
2011/02                        10200          110126
2011/03                        15200          147834
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Stellt man das dann in APEX mit Hilfe eines Diagramms dar, ergibt sich
 ein schönes, quasi klassisches Statistikbild mit tatsächlichen und
 prognostizierten Daten. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Then we could create an APEX application showing those numbers in 
 a nice chart.
&lt;/div&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-15XiQVx4UdM/TfHgTj1bW4I/AAAAAAAAAHw/9lck7dxWx78/s1600/Snap1.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 226px;" src="http://1.bp.blogspot.com/-15XiQVx4UdM/TfHgTj1bW4I/AAAAAAAAAHw/9lck7dxWx78/s320/Snap1.png" alt="" id="BLOGGER_PHOTO_ID_5616516836949187458" border="0" /&gt;&lt;/a&gt;
&lt;div lang="de"&gt;
 Man sieht sehr schön: Die Datenbank kann eine ganze Menge - und auch für
 diese einfachen Fälle gibt es Anwendungsmöglichkeiten. Die Datenbank kann
 seit 11g sogar die komplexere multiple Regression mit mehreren unabhängigen
 Variablen - das ist dann aber Bestandteil der &lt;i&gt;Data Mining Option&lt;/i&gt;, die
 man separat lizensieren muss. Wäre ein Fall für ein anderes Blog-Posting.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 It's still true: the Oracle database can do more than most of us think. And many
 tasks are more than simple. The database is even capable to do the more complex
 linear regression with multiple input variables - but this is then part of the
 &lt;i&gt;Data Mining Option&lt;/i&gt; which requires a separate license. That might be 
 topic of another blog posting.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-7111375234277280356?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/BQOaxHGe_fA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/BQOaxHGe_fA/kleine-statistikvorlesung-mit-der.html</link><author>noreply@blogger.com (Carsten Czarski)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-15XiQVx4UdM/TfHgTj1bW4I/AAAAAAAAAHw/9lck7dxWx78/s72-c/Snap1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/06/kleine-statistikvorlesung-mit-der.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-1542743378116617111</guid><pubDate>Mon, 06 Jun 2011 12:30:00 +0000</pubDate><atom:updated>2011-06-06T13:36:21.593+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">datenbank</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">treffen</category><title>Fundgrube Standard-Edition - und nicht nur das: DOAG SIG Development am 9. Juni</title><description>&lt;div lang="de"&gt;So .. der Urlaub ist rum und man ist zurück im Oracle-Leben. Ein technisches Posting habe ich heute noch nicht (das kommt später), aber ich kann wenigstens was ankündigen. Am &lt;b&gt;9. Juni&lt;/b&gt; (das ist am Donnerstag) bin ich mit zwei Vorträgen auf
der &lt;a href="http://mydoag.doag.org/termine/termine.php?tid=417441" target="_blank"&gt;DOAG SIG Development&lt;/a&gt; vertreten. Zum einen spreche ich über die "Fundgrube" Oracle Standard Edition (die vielen DB-Features und deren sinnvolle Kombination ist ja mein Lieblingsthema) und zum anderen spreche ich kurz über den neuen SQL Developer 3.0.
&lt;/div&gt;
&lt;div lang="de"&gt;Naja - und viel wichtiger ist natürlich der Austausch und die Diskussion in der Community. Insofern hoffe ich auf zahlreiche Teilnehmer, gute Diskussionen und ... veilleicht sieht man sich ja.&lt;/div&gt;
&lt;div lang="en" style="display: none"&gt;This posting is about an event in german language and therefore in german only.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-1542743378116617111?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/pDThB-Aaan8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/pDThB-Aaan8/fundgrube-standard-edition-und-nicht.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/06/fundgrube-standard-edition-und-nicht.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-4701412087240673333</guid><pubDate>Fri, 20 May 2011 13:30:00 +0000</pubDate><atom:updated>2011-05-20T14:36:30.699+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">workshop</category><title>APEX Hands-On Workshop am 7. Juni in Jena</title><description>&lt;div lang="de"&gt;
Am 7. Juni veranstalten meine Kollegen &lt;b&gt;Karin Patenge&lt;/b&gt; und &lt;b&gt;Michal Soszynski&lt;/b&gt; einen APEX Hands On Workshop - in Zusammenarbeit mit der DOAG Regionalgruppe Thüringen. Also die Gelegenheit für APEX-Einsteiger im Raum Jena. Inhalte sind:
&lt;ul&gt;
&lt;li&gt;Die Oracle Datenbank als Entwicklungswerkzeug&lt;/li&gt;
&lt;li&gt;Arbeiten mit APEX Workspaces&lt;/li&gt;
&lt;li&gt;Von der Tabelle zur Applikation&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Import von Tabellendaten&lt;/li&gt;
&lt;li&gt;Erstellen einer Anwendung&lt;/li&gt;
&lt;li&gt;Ausführen einer Anwendung&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Erweitern und Ändern von Anwendungen&lt;/li&gt;
&lt;li&gt;Berechtigungskonzepte in APEX&lt;/li&gt;
&lt;li&gt;Das Layout von APEX-Anwendungen&lt;/li&gt;
&lt;/ul&gt;
Wer Interesse hat, also am besten gleich anmelden - Mehr Info und Anmeldedetails hier:&lt;br/&gt;
&lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/apex/event/workshop/APEX_HandsOnWorkshop_Jena_20110607.pdf"&gt;http://www.oracle.com/webfolder/technetwork/de/community/apex/event/workshop/APEX_HandsOnWorkshop_Jena_20110607.pdf&lt;/a&gt;
&lt;/div&gt;
&lt;div lang="en" style="display: none"&gt;This posting is about an event in german language and therefore in german only.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-4701412087240673333?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/jqy0XKYA1Fc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/jqy0XKYA1Fc/apex-hands-on-workshop-am-7-juni-in.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/05/apex-hands-on-workshop-am-7-juni-in.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-288552500833195687</guid><pubDate>Wed, 20 Apr 2011 08:26:00 +0000</pubDate><atom:updated>2011-04-20T09:26:28.651+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sqlplus</category><category domain="http://www.blogger.com/atom/ns#">kalender</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">Skript</category><title>Ein wenig Spielerei: Monatskalender in SQL Plus!</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Playing around a bit: Monthly calendar in SQL*Plus&lt;/div&gt;
&lt;div lang="de"&gt;
 Heute habe ich etwas, was wohl auch ein wenig in die Kategorie "Spielereien" gehört,
 aber die muss es ja auch geben. 
 Zuletzt hatte ich mal ein paar Minuten und dachte mir, dass ein SQL-Skript zum
 Generieren eines Monatskalenders doch ganz nett wäre - die Grundversion mit
 der &lt;b&gt;PIVOT&lt;/b&gt;-Klausel war schnell erstellt - dann fehlte nur noch der Feinschliff.
 Und hier ist es.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 My today's blog posting might be something for the toybox - but we also need those
 things. Last week I had some spare minutes in which I was playing around with the
 &lt;b&gt;SQL PIVOT&lt;/b&gt; clause introduced in Oracle11g. So I created a monthly calendar as 
 a SQL script. Here we go.
&lt;/div&gt;
&lt;pre&gt;
ol monat format a15
&lt;font color="#804040"&gt;&lt;b&gt;set&lt;/b&gt;&lt;/font&gt; pages &lt;font color="#ff00ff"&gt;20&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;set&lt;/b&gt;&lt;/font&gt; verify off

&lt;font color="#6a5acd"&gt;with&lt;/font&gt; dates &lt;font color="#6a5acd"&gt;as&lt;/font&gt; (
  &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt;  to_date(&lt;font color="#ff00ff"&gt;'01&amp;amp;1'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;) + (&lt;font color="#6a5acd"&gt;level&lt;/font&gt; - &lt;font color="#ff00ff"&gt;1&lt;/font&gt;) the_date &lt;font color="#6a5acd"&gt;from&lt;/font&gt; dual
  &lt;font color="#6a5acd"&gt;connect&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; &lt;font color="#6a5acd"&gt;level&lt;/font&gt; &amp;lt; trunc((add_months(to_date(&lt;font color="#ff00ff"&gt;'01&amp;amp;2'&lt;/font&gt;,&lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;),&lt;font color="#ff00ff"&gt;1&lt;/font&gt;) - &lt;font color="#ff00ff"&gt;1&lt;/font&gt;) - to_date(&lt;font color="#ff00ff"&gt;'01&amp;amp;1'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;)) + &lt;font color="#ff00ff"&gt;2&lt;/font&gt; 
) 
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; monat, &lt;font color="#ff00ff"&gt;&amp;quot; MO &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; DI &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; MI &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; DO &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; FR &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; SA &amp;quot;&lt;/font&gt;, &lt;font color="#ff00ff"&gt;&amp;quot; SO &amp;quot;&lt;/font&gt;, ww KW 
&lt;font color="#6a5acd"&gt;from&lt;/font&gt; (
  &lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; 
    rtrim(to_char(the_date, &lt;font color="#ff00ff"&gt;'MONTH'&lt;/font&gt; ), &lt;font color="#ff00ff"&gt;'nls_date_language=german'&lt;/font&gt;)  monat 
   ,case 
      when to_char(the_date, &lt;font color="#ff00ff"&gt;'IW'&lt;/font&gt;) &amp;gt; &lt;font color="#ff00ff"&gt;50&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; to_char(the_date, &lt;font color="#ff00ff"&gt;'MM'&lt;/font&gt;) = &lt;font color="#ff00ff"&gt;'01'&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
        to_char(the_date, &lt;font color="#ff00ff"&gt;'YYYY'&lt;/font&gt;) - &lt;font color="#ff00ff"&gt;1&lt;/font&gt;||to_char(the_date, &lt;font color="#ff00ff"&gt;'IW'&lt;/font&gt;)
      &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
        to_char(the_date, &lt;font color="#ff00ff"&gt;'YYYYIW'&lt;/font&gt;)
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; yyyyww
   ,to_char(the_date, &lt;font color="#ff00ff"&gt;'yyyyMM'&lt;/font&gt; ) m 
   ,case when trunc(the_date) = trunc(&lt;font color="#804040"&gt;&lt;b&gt;sysdate&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
      &lt;font color="#ff00ff"&gt;'*'&lt;/font&gt; || to_char(the_date, &lt;font color="#ff00ff"&gt;'DD'&lt;/font&gt;) || &lt;font color="#ff00ff"&gt;'*'&lt;/font&gt; 
    &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
      &lt;font color="#ff00ff"&gt;' '&lt;/font&gt; || to_char(the_date, &lt;font color="#ff00ff"&gt;'DD'&lt;/font&gt;) || &lt;font color="#ff00ff"&gt;' '&lt;/font&gt;
    &lt;font color="#6a5acd"&gt;end&lt;/font&gt; dd
   ,rtrim(upper(to_char(the_date, &lt;font color="#ff00ff"&gt;'DY'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'nls_date_language=''german'''&lt;/font&gt; )))  d 
   ,to_char(the_date, &lt;font color="#ff00ff"&gt;'IW'&lt;/font&gt;) ww
  &lt;font color="#6a5acd"&gt;from&lt;/font&gt; dates &lt;font color="#6a5acd"&gt;where&lt;/font&gt; the_date &lt;font color="#804040"&gt;&lt;b&gt;between&lt;/b&gt;&lt;/font&gt; to_date(&lt;font color="#ff00ff"&gt;'01&amp;amp;1'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;) &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; add_months(to_date(&lt;font color="#ff00ff"&gt;'01&amp;amp;2'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;),&lt;font color="#ff00ff"&gt;1&lt;/font&gt;) - &lt;font color="#ff00ff"&gt;1&lt;/font&gt;
) pivot (
  min(dd) &lt;font color="#6a5acd"&gt;for&lt;/font&gt; d &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; (
    &lt;font color="#ff00ff"&gt;'MO'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; MO &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'DI'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; DI &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'MI'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; MI &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'DO'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; DO &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'FR'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; FR &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'SA'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; SA &amp;quot;&lt;/font&gt;,
    &lt;font color="#ff00ff"&gt;'SO'&lt;/font&gt; &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#ff00ff"&gt;&amp;quot; SO &amp;quot;&lt;/font&gt; 
  )
)
&lt;font color="#6a5acd"&gt;order&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; yyyyww, m
/

undefine &lt;font color="#ff00ff"&gt;1&lt;/font&gt;
undefine &lt;font color="#ff00ff"&gt;2&lt;/font&gt;
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Aufrufen geht dann so.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;Use it as follows ...&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; @kal 042011 052011

MONAT            MO   DI   MI   DO   FR   SA   SO  KW
--------------- ---- ---- ---- ---- ---- ---- ---- --
APRIL                                01   02   03  13
APRIL            04   05   06   07   08   09   10  14
APRIL            11   12   13   14   15   16   17  15
APRIL           *18*  19   20   21   22   23   24  16
APRIL            25   26   27   28   29   30       17
MAI                                            01  17
MAI              02   03   04   05   06   07   08  18
MAI              09   10   11   12   13   14   15  19
MAI              16   17   18   19   20   21   22  20
MAI              23   24   25   26   27   28   29  21
MAI              30   31                           22
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Bei der schnellen Terminplanung vielleicht ganz nützlich - nehmt's ansonsten als
 Beispiel für "Kunst mit SQL Plus". Bei mir liegt es neben einigen anderen
 Skripten im Verzeichnis, auf das die Umgebungsvariable &lt;b&gt;SQLPATH&lt;/b&gt; zeigt; damit habe
 ich es immer im Zugriff.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Perhaps it is useful, perhaps it's just SQL*Plus arts.  I placed it in the &lt;b&gt;SQLPATH&lt;/b&gt; folder
 where it is always accessible. Have fun.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-288552500833195687?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/7oPEYKnc_m8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/7oPEYKnc_m8/ein-wenig-spielerei-monatskalender-in.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/04/ein-wenig-spielerei-monatskalender-in.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-6312437472000553105</guid><pubDate>Mon, 11 Apr 2011 08:16:00 +0000</pubDate><atom:updated>2011-04-19T11:33:51.489+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">event</category><category domain="http://www.blogger.com/atom/ns#">community</category><category domain="http://www.blogger.com/atom/ns#">apex</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">cloud computing</category><title>Im Zeichen des Cloud Computing - Events "APEX Cloud im Mai"</title><description>&lt;div lang="en" style="display: none"&gt;This post is about an event in german language and therefore in german only.&lt;/div&gt;
&lt;div lang="de"&gt;Cloud Computing ist in aller Munde. Nahezu täglich kann man über neue Produkte und  Ideen zum Thema Cloud Computing lesen. Auch an mir geht das Thema nicht vorbei ...&lt;/div&gt;
&lt;div lang="de"&gt;Wenn man sich (wie ich) längere Zeit mit &lt;a href="http://www.oracle.com/webfolder/technetwork/de/community/apex/index.html" target="_blank"&gt;APEX&lt;/a&gt; beschäftigt und sich dann das Cloud Computing näher ansieht, kommt man irgendwie zum Schluß, dass &lt;b&gt;APEX das seit 2003 schon macht!&lt;/b&gt;. Denn 
APEX ist, wie man am öffentlichen Demoserver apex.oracle.com erkennen kann, hervorragend für das Hosting ausgelegt. Dann liegt doch die Frage nahe, wie man ein solches "APEX-Hosting" im eigenen Unternehmen realisieren könnte. 
&lt;/div&gt;
&lt;div lang="de"&gt;
Und genau damit wollen wir uns auf einer Veranstaltung im Mai näher beschäftigen.
Gemeinsam mit der MT AG aus Ratingen und Muniqsoft aus München stellen wir in Düsseldorf, Hamburg und München vor, wie man "Cloud Computing mit APEX" sofort umsetzen kann - &lt;b&gt;APEX-Hosting im eigenen Unternehmen&lt;/b&gt;. Denn mehr als eine APEX-Installation braucht man im ersten Schritt nicht -&gt; bereits dann hat man eine Entwicklerplattform "as a service" (PaaS). Natürlich gibt es auch danach noch etwas zu tun - was genau, das könnt Ihr auf der Veranstaltung erfahren.
&lt;/div&gt;
&lt;div lang="de"&gt;
Also, &lt;b&gt;schaut mal rein&lt;/b&gt; - die Veranstaltung beginnt um 12:00 mit Imbiß und Networking und dann starten wir mit der &lt;a href="http://www.tinyurl.com/apexcloudde" target="_blank"&gt;Agenda&lt;/a&gt;. 
&lt;ul&gt;
&lt;li&gt;&lt;b&gt; 3. Mai in Düsseldorf&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;10. Mai in Hamburg&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;18. Mai in München&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-6312437472000553105?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/oUGdkVP1i-c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/oUGdkVP1i-c/im-zeichen-des-cloud-computing-events.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>0</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/04/im-zeichen-des-cloud-computing-events.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-6116436827008459709</guid><pubDate>Mon, 04 Apr 2011 09:54:00 +0000</pubDate><atom:updated>2011-04-04T10:55:14.787+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">11.2</category><category domain="http://www.blogger.com/atom/ns#">oraclexe</category><category domain="http://www.blogger.com/atom/ns#">beta</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>OracleXE 11.2 (Beta) verfügbar!</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;OracleXE 11.2 (Beta) available&lt;/div&gt;
&lt;div lang="de"&gt;
 Heute gibt es ein ganz kurzes Blog-Posting: Ich wurde ja nun schon oft danach gefragt, konnte aber 
 nie eine genaue Auskunft geben. Heute kann ich es: &lt;b&gt;OracleXE 11.2 ist als Betaversion verfügbar!&lt;/b&gt;. Ihr
 könnt es &lt;a href="http://www.oracle.com/technetwork/database/express-edition/11gxe-beta-download-302519.html"
 target="_blank"&gt;aus dem OTN&lt;/a&gt; herunterladen. Viel Spaß beim Ausprobieren ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Today's blog posting is a rather short one. I was often asked for that in the past, but I was not able
 to give an exact answer. But today I can. &lt;b&gt;OracleXE 11.2 (Beta) is available!&lt;/b&gt;. It is 
  &lt;a href="http://www.oracle.com/technetwork/database/express-edition/11gxe-beta-download-302519.html"
 target="_blank"&gt;downloadable from OTN&lt;/a&gt;. Have fun!
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-6116436827008459709?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/AtrjpZHeT1Y" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/AtrjpZHeT1Y/oraclexe-112-beta-verfugbar.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/04/oraclexe-112-beta-verfugbar.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-7544741910870093604</guid><pubDate>Thu, 24 Mar 2011 10:04:00 +0000</pubDate><atom:updated>2011-03-25T09:41:27.232+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">table functions</category><category domain="http://www.blogger.com/atom/ns#">data cartridge</category><category domain="http://www.blogger.com/atom/ns#">statistic</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">optimizer</category><category domain="http://www.blogger.com/atom/ns#">odci</category><title>Table Functions, der Optimizer und Statistiken ...</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Table Functions, the Optimizer and Statistics ...&lt;/div&gt;
&lt;div lang="de"&gt;
 Heute möchte ich mich mal dem Thema &lt;i&gt;Table Functions&lt;/i&gt; widmen - ich werde aber nicht schreiben,
 wie man eine Table Function bauen kann, sondern vielmehr, wie man dem Query Opimizer ein wenig 
 Information über die Table Function geben kann - wichtig wäre vor allem, dass der Optimizer weiss,
 wieviele Zeilen die Table-Function zurückgeben wird, denn das hat Einfluß auf seine Entscheidungen. So 
 richtet sich die Join-Strategie doch erheblich nach der Anzahl Zeilen in den beteiligten Tabellen.
 Wir beginnen mit einem Beispiel - eine sehr einfache Table Function ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Today I'd like to write about &lt;i&gt;Table Functions&lt;/i&gt;. But this posting will not be about 
 writing these (there is enough information available) - this posting is about how we can tell
 the &lt;i&gt;Query Optimizer&lt;/i&gt; a bit about our table function. An important information would be 
 how many rows the actual table function call will return - this would impact the optimizer
 decisions for e.g. the join strategy. But let's take the topic step by step. We'll start with 
 a very simple table function example ... 
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;type&lt;/font&gt; tf_t &lt;font color="#6a5acd"&gt;as&lt;/font&gt; object(
  col1       &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
);
/

&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;type&lt;/font&gt; tf_ct &lt;font color="#6a5acd"&gt;as&lt;/font&gt; &lt;font color="#6a5acd"&gt;table&lt;/font&gt; &lt;font color="#6a5acd"&gt;of&lt;/font&gt; tf_t
/ 

&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;function&lt;/font&gt; tf (p_cnt &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;)
&lt;font color="#6a5acd"&gt;return&lt;/font&gt; tf_ct pipelined &lt;font color="#6a5acd"&gt;as&lt;/font&gt;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
  &lt;font color="#6a5acd"&gt;for&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;1&lt;/font&gt;..p_cnt &lt;font color="#6a5acd"&gt;loop&lt;/font&gt;
    pipe &lt;font color="#6a5acd"&gt;row&lt;/font&gt; (tf_t(i*&lt;font color="#ff00ff"&gt;2&lt;/font&gt;));
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;loop&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt;;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
/
sho err

SQL&amp;gt; select * from table(tf(10));

      COL1
----------
         2
         4
         6
         8
        10
         :
&lt;/pre&gt;
&lt;div lang="de"&gt;
 So weit so gut - nun werfen wir mal einen Blick auf den Ausführungsplan dieser einfachen Abfrage ... und
 danach erstellen wir den Ausführungsplan nochmal mit dem Argument &lt;b&gt;100000&lt;/b&gt;. Also einen Ausführungsplan
 für &lt;b&gt;10&lt;/b&gt; zurückgegebene Zeilen und einen für &lt;b&gt;100000&lt;/b&gt; zurückgegebene Zeilen ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 So far, so good. Now we'll see what the query optimizer thinks about our function. We'll look into
 the execution plan for a invokation with "&lt;b&gt;10&lt;/b&gt;" as well as for "&lt;b&gt;100000&lt;/b&gt;" as parameter. 
 So the table function
 will return &lt;b&gt;10&lt;/b&gt; rows in the first and &lt;b&gt;100000&lt;/b&gt; rows in the second case.
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; explain plan for 
  2  select * from table(tf(10))
  3  /

SQL&amp;gt; select * from table(dbms_xplan.display())
  2  /

------------------------------------------------------------------------------------------
| Id  | Operation                         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |  &lt;b style="color:red"&gt;8168&lt;/b&gt; | 16336 |    29   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| TF   |  8168 | 16336 |    29   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

SQL&amp;gt; explain plan for 
  2  select * from table(tf(100000))
  3  /

SQL&amp;gt; select * from table(dbms_xplan.display())
  2  /

------------------------------------------------------------------------------------------
| Id  | Operation                         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |  &lt;b style="color:red"&gt;8168&lt;/b&gt; | 16336 |    29   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| TF   |  8168 | 16336 |    29   (0)| 00:00:01 |
------------------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Egal, was Ihr als Parameter angebt: die Anzahl Zeilen, die der Optimizer als Ergebnismenge
 der Table Function annimmt, ist immer gleich. Woher soll er es auch wissen? Es gibt eben
 hier keine Tabelle mit Statistiken. 
 Aber: Die Datenbank erlaubt durchaus, dem Optimizer diese Information zu geben. Das ist auch
 in der &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm" target="_blank"&gt;Dokumentation zum Extensible Optimizer Interface&lt;/a&gt; beschrieben. Das ist übrigens Teil des &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/toc.htm" target="_blank"&gt;Data Cartridge Developers Guide&lt;/a&gt;, einem 
meiner Meinung nach hochinteressanten Handbuch.
 Wir müssen demnach einen neuen Objekttypen implementieren. Und dieser Objekttyp muss zwei Funktionen
 enthalten: &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm#CHEDBEFB" target="_blank"&gt;ODCIGetInterfaces&lt;/a&gt; und &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm#CHEDHGGI" target="_blank"&gt;ODCIStatsTableFunction&lt;/a&gt;. Also brauchen wir zuerst den Object Type als solchen ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 The plan always looks the same, regardless of the given table function argument. Anyway: how should the
 optimizer know? There is not table and so there are no statistics. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 &lt;b&gt;But&lt;/b&gt;, the Oracle database allows to privide information for the query optimizer. This is documented
 in the  &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm" target="_blank"&gt;Extensible Optimizer Interface&lt;/a&gt;, which is part of the &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/toc.htm" target="_blank"&gt;Data Cartridge Developers Guide&lt;/a&gt; (IMHO one of the most interesting documentation handbooks). So we have to implement another object type for the "communication" with the optimizer. And
 this object type must contain two functions: &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm#CHEDBEFB" target="_blank"&gt;ODCIGetInterfaces&lt;/a&gt; and &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/ext_opt_ref.htm#CHEDHGGI" target="_blank"&gt;ODCIStatsTableFunction&lt;/a&gt;. So we start the the type declaration ...
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;CREATE&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;TYPE&lt;/font&gt; tfstats &lt;font color="#6a5acd"&gt;as&lt;/font&gt; object (
  dummy &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,                          &lt;font color="#0000ff"&gt;-- object types need attributes - here is one.&lt;/font&gt;
  static &lt;font color="#6a5acd"&gt;FUNCTION&lt;/font&gt; ODCIGetInterfaces(
    ifclist  &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; ODCIObjectList
  ) &lt;font color="#6a5acd"&gt;RETURN&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;NUMBER&lt;/b&gt;&lt;/font&gt;,
  STATIC &lt;font color="#6a5acd"&gt;FUNCTION&lt;/font&gt; ODCIStatsTableFunction(
   func      &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt;  SYS.ODCIFuncInfo, 
   outStats  &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; SYS.ODCITabFuncStats, 
   argDesc   &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt;  SYS.ODCIArgDescList, 
   argument  &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;                   &lt;font color="#0000ff"&gt;-- list all table function arguments here&lt;/font&gt;
  ) &lt;font color="#6a5acd"&gt;RETURN&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;NUMBER&lt;/b&gt;&lt;/font&gt;
);
/
sho err
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Das war einfach - nun kommt die konkrete Implementierung. Für unser Beispiel ist die
 aber nicht besonders schwierig. Der Parameter der Table Function gibt die Anzahl Zeilen ja an;
 also geben wir ihn einfach wieder zurück. Genau dieses Detail ist in der Praxis mit Sicherheit
 am schwierigsten, denn aufwändige Berechnungen und Abfragen sind hier fehl am Platz - man muss
 mit möglichst wenig Aufwand eine Abschätzung finden ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 ... and then we continue with the actual implementation. Our example is very simple. The table function
 arguments determines exactly the amount of returned rows. So we simply return the argument as 
 the optimizer information in &lt;b&gt;ODCIStatsTableFunction&lt;/b&gt;. In practice this will be the most
 difficult part of the task. Complex and expensive calculations or queries are not appropriate
 here (note that this will be called when the optimizer generated the execution plan). So you will
 have to find a good approximation with as less efforts as possible ...
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;type&lt;/font&gt; body tfstats &lt;font color="#6a5acd"&gt;as&lt;/font&gt;
  static &lt;font color="#6a5acd"&gt;FUNCTION&lt;/font&gt; ODCIGetInterfaces(
    ifclist  &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; ODCIObjectList
  ) &lt;font color="#6a5acd"&gt;RETURN&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;NUMBER&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    &lt;font color="#0000ff"&gt;-- Always return SYS.ODCISTATS2 here&lt;/font&gt;
    ifclist := ODCIObjectList(ODCIObject(&lt;font color="#ff00ff"&gt;'SYS'&lt;/font&gt;,&lt;font color="#ff00ff"&gt;'ODCISTATS2'&lt;/font&gt;));
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt;;

  STATIC &lt;font color="#6a5acd"&gt;FUNCTION&lt;/font&gt; ODCIStatsTableFunction(
    func      &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; SYS.ODCIFuncInfo, 
    outStats &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; SYS.ODCITabFuncStats, 
    argDesc   &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; SYS.ODCIArgDescList, 
    argument  &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;NUMBER&lt;/b&gt;&lt;/font&gt; 
  ) &lt;font color="#6a5acd"&gt;RETURN&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;NUMBER&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
  &lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
    outStats := SYS.ODCITabFuncStats(argument);
    &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
/
sho err 
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Nun ist der Objekttyp implementiert - fehlt noch die Verbindung zur konkreten Table Function. Und das
 geht so.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Now, as the implementation is complete, we need to associate this with the table function. The following
 call will "tell" the optimizer where to look for statistics information regarding a particular table function.
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; ASSOCIATE STATISTICS WITH FUNCTIONS tf USING tfstats;
&lt;/pre&gt;
&lt;div lang="de"&gt;
Dann schauen wir uns die obigen Ausführungspläne nochmals an ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 That's it - let's look into the execution plan ...
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; explain plan for 
  2  select * from table(tf(10))
  3  /

SQL&amp;gt; select * from table(dbms_xplan.display())
  2  /

------------------------------------------------------------------------------------------
| Id  | Operation                         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |    10 |    20 |    29   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| TF   |    10 |    20 |    29   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

SQL&amp;gt; explain plan for 
  2  select * from table(tf(100000))
  3  /

SQL&amp;gt; select * from table(dbms_xplan.display())
  2  /

--------------------------------------------------------------------------------------------
| Id  | Operation                         | Name | Rows   |  Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      | 100000 | 200000 |    29   (0)| 00:00:01 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| TF   | 100000 | 200000 |    29   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Folgt nun noch ein Test, was der Optimizer daraus macht. Ich habe für mein Beispiel den Session-Parameter
 &lt;b&gt;OPTIMIZER_INDEX_COST_ADJ&lt;/b&gt; auf "1" gestellt, damit Indexzugriffe "billig" sind und der Optimizer schneller auf 
 Nested Loops umschaltet ... Und den Ausführungsplan berechne ich nun mal für folgende Query:
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Now I'd like to see what the optimizer does with that information. For the following example 
 I set  &lt;b&gt;OPTIMIZER_INDEX_COST_ADJ&lt;/b&gt; to "1" - that makes index access "cheap" and the optimizer
 will tend to the "nested loops" join stategy faster. And now I'll generate the execution plan
 for the following query ...
&lt;/div&gt;
&lt;pre&gt;
explain plan &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; 
&lt;font color="#008080"&gt;select&lt;/font&gt; s.prod_id
&lt;font color="#008080"&gt;from&lt;/font&gt; sh.sales s, &lt;font color="#2e8b57"&gt;&lt;b&gt;table&lt;/b&gt;&lt;/font&gt;(tf(&lt;font color="#804040"&gt;&lt;b&gt;&lt;i&gt;{argument}&lt;/i&gt;&lt;/b&gt;&lt;/font&gt;)) t
&lt;font color="#008080"&gt;where&lt;/font&gt; t.col1 &lt;font color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt; s.prod_id
&lt;font color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Ohne dieses Verfahren sieht der Ausführungsplan stets gleich aus. Der Optimizer geht von den
 oben schon dargestellten ca. 8000 Zeilen aus und entscheidet sich wie folgt.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Without our approach the optimizer always thinks that the table function will return 
 about 8000 rows. So the execution plan always looks the same:
&lt;/div&gt;
&lt;pre&gt;
-----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                |   104M|   596M|   620  (91)| 00:00:08 |
|*  1 |  HASH JOIN                         |                |   104M|   596M|   620  (91)| 00:00:08 |
|   2 |   COLLECTION ITERATOR PICKLER FETCH| TF             |  &lt;b style="color: red"&gt;8168 | 16336&lt;/b&gt; |    29   (0)| 00:00:01 |
|   3 |   PARTITION RANGE ALL              |                |   918K|  3589K|    29   (0)| 00:00:01 |
|   4 |    BITMAP CONVERSION TO ROWIDS     |                |   918K|  3589K|    29   (0)| 00:00:01 |
|   5 |     BITMAP INDEX FAST FULL SCAN    | SALES_PROD_BIX |       |       |            |          |
-----------------------------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Mit dem Verfahren (und dem Parameter &lt;b&gt;OPTIMIZER_INDEX_COST_ADJ = 1&lt;/b&gt; sieht der Plan mit 
 dem Parameter 100000 in der Table Function so aus ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 With the additional information the optimizer has the choice - and it uses it. When the
 table function returns many rows (here: &lt;b&gt;100000&lt;/b&gt;) the join strategy is &lt;b&gt;HASH JOIN&lt;/b&gt; ... 
&lt;/div&gt;
&lt;pre&gt;
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                |  1276M|  7302M|       |  7677  (90)| 00:01:33 |
|*  1 |  &lt;b style="color: red"&gt;HASH JOIN&lt;/b&gt;                         |                |  1276M|  7302M|  1368K|  7677  (90)| 00:01:33 |
|   2 |   COLLECTION ITERATOR PICKLER FETCH| TF             |   &lt;b style="color: red"&gt;100K&lt;/b&gt;|   195K|       |    29   (0)| 00:00:01 |
|   3 |   PARTITION RANGE ALL              |                |   918K|  3589K|       |     1   (0)| 00:00:01 |
|   4 |    BITMAP CONVERSION TO ROWIDS     |                |   918K|  3589K|       |     1   (0)| 00:00:01 |
|   5 |     BITMAP INDEX FULL SCAN         | SALES_PROD_BIX |       |       |       |            |          |
-------------------------------------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;div lang="de"&gt;
 ... und mit dem Parameter 20 so.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 ... and for less rows (here: &lt;b&gt;20&lt;/b&gt;) the optimizer decides to do &lt;b&gt;NESTED LOOPS&lt;/b&gt;.
&lt;/div&gt;
&lt;pre&gt;
-----------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |                |   255K|  1495K|    35   (0)| 00:00:01 |
|   1 |  &lt;b style="color: red"&gt;NESTED LOOPS&lt;/b&gt;                      |                |   255K|  1495K|    35   (0)| 00:00:01 |
|   2 |   COLLECTION ITERATOR PICKLER FETCH| TF             |    &lt;b style="color: red"&gt;20&lt;/b&gt; |    40 |    29   (0)| 00:00:01 |
|   3 |   PARTITION RANGE ALL              |                | 12762 | 51048 |    35   (0)| 00:00:01 |
|   4 |    BITMAP CONVERSION TO ROWIDS     |                | 12762 | 51048 |    35   (0)| 00:00:01 |
|*  5 |     BITMAP INDEX SINGLE VALUE      | SALES_PROD_BIX |       |       |            |          |
-------------------------------------------------------------------------------------------------------------
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Das finde ich eine ganz interessante Möglichkeit - Wenn Table Functions stark schwankende Ergebnismengen
 liefern &lt;i&gt;und&lt;/i&gt; sich diese einfach abschätzen lassen, dann ist das eine recht interessante Herangehensweise ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Probably it is not applicably for each and every table function; but
 if a table function returns different amounts of rows and the amount of rows can be estimated easily ... 
 this might be an interesting approach.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-7544741910870093604?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/nDbx-0OziBk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/nDbx-0OziBk/table-functions-der-optimizer-und.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/03/table-functions-der-optimizer-und.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-4571526460581475561</guid><pubDate>Tue, 08 Mar 2011 09:48:00 +0000</pubDate><atom:updated>2011-03-08T10:49:34.901+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">aggregat</category><category domain="http://www.blogger.com/atom/ns#">group by</category><category domain="http://www.blogger.com/atom/ns#">product</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>Noch ein Szenario mit "User Defined Aggregates"</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Another scenario for user-defined-aggregates&lt;/div&gt;
&lt;div lang="de"&gt;
 Im &lt;a href="/2011/02/sql-aggregatsfunktion-product-fehlt.html"&gt;vorletzten Blog Posting&lt;/a&gt; hatte ich ja vorgestellt, wie man sich eigene Aggregatsfunktionen mit den &lt;i&gt;User Defined Aggregates&lt;/i&gt; bauen kann. Heute greife ich das Thema nochmals auf, denn diese Funktionen haben mehr denkbare Einsatzgebiete, als man sich denken mag ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 In the &lt;a href="/2011/02/sql-aggregatsfunktion-product-fehlt.html?lang=en"&gt;previous but one blog posting&lt;/a&gt; 
 I talked about &lt;i&gt;user defined aggregates&lt;/i&gt;. Today I will again write about this topic ... since 
 those functions are applicable in more situations than you might think.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Wenn man die &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/aggr_functions.htm#CECJAAJG"&gt;Dokumentation&lt;/a&gt; liest, scheint es, als ob User Defined Aggregates nur einzelne skalare Werte aggregieren können - aber bei genauerer
 Betrachtung ist das nicht der Fall - man kann über den Umweg eines Objekttypen auch ganze "Datasets" aggregieren
 lassen. Als Beispiel habe ich das mal mit einem "Sparbuch" probiert - auf diesem Sparkonto gibt es Ein- 
 und Auszahlungen - und mit einer Aggregatsfunktion sollen die Zinsen berechnet werden. Die hängen neben dem
 Betrag der Transaktion auch von deren Datum ab.
 Zuerst brauchen wir also unsere Tabelle für die Konten ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 When reading the &lt;a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10765/aggr_functions.htm#CECJAAJG"&gt;documentation&lt;/a&gt; and creating some example functions it seems that user defined aggregates can only aggregate
 scalar values. But this is not true - with the utilization of &lt;i&gt;object types&lt;/i&gt; we can aggregate even complex datasets. To illustrate this I have created the example of a savings account. On this account we have transactions (debit and credit). And now (at the end of the year) we have to calculate interest. And the interest depends on the transactions' amount as well as on its date. So, we create the transaction table first.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;table&lt;/font&gt; tab_buchungen(
 id       &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
 konto    &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
 datum    &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;,
 betrag   &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
)
/

&lt;font color="#804040"&gt;&lt;b&gt;alter&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;session&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;set&lt;/b&gt;&lt;/font&gt; nls_date_format=&lt;font color="#ff00ff"&gt;'DD.MM.YYYY'&lt;/font&gt;
/

&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * Konto I&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;

&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;1&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'01.01.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;500&lt;/font&gt;);  

&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;2&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'09.01.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;1500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;3&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'15.02.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;-912&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;4&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'25.03.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;2500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;5&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'18.05.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;2000&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;6&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'27.07.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;-1500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;7&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'03.08.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;850&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;8&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'19.10.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;1350&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;9&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4711&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'28.11.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;-2000&lt;/font&gt;);


&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * Konto II&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;

&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;10&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'01.01.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;500&lt;/font&gt;);

&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;11&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'09.02.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;1500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;12&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'28.02.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;-912&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;13&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'25.03.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;2500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;14&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'18.04.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;2000&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;15&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'19.04.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;5000&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;16&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'27.05.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;-3500&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;17&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'04.06.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;100&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;18&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'03.08.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;152&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;19&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'19.10.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;950&lt;/font&gt;);
&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;20&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4712&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'28.11.2010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4000&lt;/font&gt;);


&lt;font color="#0000ff"&gt;/*&lt;/font&gt;
&lt;font color="#0000ff"&gt; * Konto III&lt;/font&gt;
&lt;font color="#0000ff"&gt; */&lt;/font&gt;

&lt;font color="#804040"&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;into&lt;/font&gt; tab_buchungen &lt;font color="#6a5acd"&gt;values&lt;/font&gt; (&lt;font color="#ff00ff"&gt;21&lt;/font&gt;, &lt;font color="#ff00ff"&gt;4713&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'31.12.2009'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;5000&lt;/font&gt;);


&lt;font color="#804040"&gt;&lt;b&gt;commit&lt;/b&gt;&lt;/font&gt;
/
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Für die Zinsberechnung nehmen wir die Zinszahlen-Methode. Wer genaueres wissen möchte, schaut 
 am besten im &lt;a href="http://de.wikipedia.org/wiki/Zinszahlen"&gt;Wikipedia-Artikel&lt;/a&gt; nach. Die
 Aggregatsfunktion muss also während der Iteration die Zinszahlen "aggregieren" und zum
 Abschluß aus der Zinszahl die Zinsen rechnen.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 To calculate intrerest we use the "interest number" method (&lt;a href="http://de.wikipedia.org/wiki/Zinszahlen" target="_blank"&gt;german wikipedia article here - did not found an english one&lt;/a&gt;). The interest number
 aggregates the information about the transaction amount and date. From the interest number we
 can then calculate the amount of interest.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Um die Zinszahlen rechnen zu können, braucht man pro Transaktion eben den Betrag und das
 Datum, also zwei Werte. Das User Defined Aggregate kann aber nur einen Parameter entgegennehmen - später
 auf einer Spalte arbeiten. Diesen Gegensatz lösen wir auf, indem wir die beiden Werte in einen
 Objekttypen kapseln - den  Objekttypen verwenden wir quasi als "Transportobjekt". 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 So we need the transaction amount and date in order to calculate the interest number - so we need
 two values. The user defined aggregate allows only one parameter. We solve this situation by encapsulating
  the two values in one object type as a "transport object".
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;type&lt;/font&gt; t_buchung &lt;font color="#6a5acd"&gt;as&lt;/font&gt; object(
  buchungsdatum        &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;,
  betrag               &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
)
/
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Als nächstes brauchen wir noch globale Daten wie den Zinssatz und das Abrechnungsdatum (meist der
 31.12., könnte natürlich aber auch jedes andere sein. Da diese Angaben für alle Tabellenzeilen
 gleich sind, packen wir sie in ein PL/SQL-Paket - direkt erstellt mit &lt;i&gt;get-&lt;/i&gt; und &lt;i&gt;set-&lt;/i&gt;Methoden.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Next we'll need some global data applicable for all table rows. This is the interest rate as well
 as the calculation date. Most often this will be the 31st of December - but any date is possible. To
 hold those global values we'll use a PL/SQL package. The following code creates it as well as 
 some &lt;i&gt;get-&lt;/i&gt; and &lt;i&gt;set-&lt;/i&gt; methods.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace package pkg_zinsen &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
 &lt;font color="#6a5acd"&gt;function&lt;/font&gt; get_zinssatz &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;procedure&lt;/font&gt; set_zinssatz(p_zinssatz &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;);
 &lt;font color="#6a5acd"&gt;function&lt;/font&gt; get_abrechnungsdatum &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;procedure&lt;/font&gt; set_abrechnungsdatum (p_datum &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;);
&lt;font color="#6a5acd"&gt;end&lt;/font&gt; pkg_zinsen;
/

&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace package body pkg_zinsen &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
 g_zinssatz &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;;
 g_datum    &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;;

 &lt;font color="#6a5acd"&gt;function&lt;/font&gt; get_zinssatz &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt; &lt;font color="#6a5acd"&gt;begin&lt;/font&gt; &lt;font color="#6a5acd"&gt;return&lt;/font&gt; g_zinssatz; &lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;procedure&lt;/font&gt; set_zinssatz(p_zinssatz &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;is&lt;/font&gt; &lt;font color="#6a5acd"&gt;begin&lt;/font&gt; g_zinssatz := p_zinssatz; &lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;function&lt;/font&gt; get_abrechnungsdatum &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt; &lt;font color="#6a5acd"&gt;begin&lt;/font&gt; &lt;font color="#6a5acd"&gt;return&lt;/font&gt; g_datum; &lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;procedure&lt;/font&gt; set_abrechnungsdatum (p_datum &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;date&lt;/b&gt;&lt;/font&gt;) &lt;font color="#6a5acd"&gt;is&lt;/font&gt; 
 &lt;font color="#6a5acd"&gt;begin&lt;/font&gt; 
  g_datum := p_datum; 
  &lt;font color="#6a5acd"&gt;if&lt;/font&gt; extract(DAY &lt;font color="#6a5acd"&gt;from&lt;/font&gt; g_datum) = &lt;font color="#ff00ff"&gt;31&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
    g_datum := to_date(&lt;font color="#ff00ff"&gt;'30'&lt;/font&gt;||to_char(g_datum, &lt;font color="#ff00ff"&gt;'MMYYYY'&lt;/font&gt;), &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;);
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;if&lt;/font&gt; to_char(g_datum, &lt;font color="#ff00ff"&gt;'DDMM'&lt;/font&gt;) = &lt;font color="#ff00ff"&gt;'2802'&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; to_char(g_datum, &lt;font color="#ff00ff"&gt;'DDMM'&lt;/font&gt;) = &lt;font color="#ff00ff"&gt;'2902'&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
    g_datum := to_date(&lt;font color="#ff00ff"&gt;'30'&lt;/font&gt;||to_char(g_datum, &lt;font color="#ff00ff"&gt;'MMYYYY'&lt;/font&gt;), &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;);
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
 &lt;font color="#6a5acd"&gt;end&lt;/font&gt; set_abrechnungsdatum;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt; pkg_zinsen;
/
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Nun kommt dann die Implementierung der Aggregatsfunktion - achtet auf die Verwendung des Objekttypen
 &lt;b&gt;T_BUCHUNG&lt;/b&gt;. Die Funktion bekommt daher für jede Iteration eben nicht einen skalaren, sondern
 dadurch gleich zwei Werte übergeben. Die anderen Daten nimmt sie aus dem PL/SQL-Paket und hat somit
 alle Informationen beisammen. In der &lt;b&gt;ODCIAggregateIterate&lt;/b&gt;-Methode werden die Zinszahlen
 berechnet und in der &lt;b&gt;ODCIAggregateTerminate&lt;/b&gt; werden die Zinsen ermittelt.Ist ein Zinssatz von
 &lt;b&gt;0%&lt;/b&gt; angegeben, werden die Zinszahlen selbst zurückgegeben.  Wie im Bankwesen
 üblich, wird ein Monat stets mit 30 Tagen gerechnet. 
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Now comes the user defined aggregate implementation. Note that the type &lt;b&gt;BUCHUNG_T&lt;/b&gt; is used
 in the &lt;b&gt;ODCIAggregateIterate&lt;/b&gt; method - so the method gets the amount as well as the date.
 The "global" data as the calculation date and the interest rate is being retrieved from the
 PL/SQL package. The &lt;b&gt;ODCIAggregateIterate&lt;/b&gt; method aggregates the interest numbers and the
 &lt;b&gt;ODCIAggregateTerminate&lt;/b&gt; method finally calculates interest using the aggregated interest
 number. If the interest rate is set to zero the function will return the interest number itself.
 And - as usual in the financial industry -  every month has 30 days.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;type&lt;/font&gt; agg_zinsen_t &lt;font color="#6a5acd"&gt;as&lt;/font&gt; object(
  v_agg_zinsen &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,

  static &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateInitialize(
    sctx &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t
  ) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateIterate(
    self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, value &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; t_buchung
  ) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateTerminate(
    self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, returnValue &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;, flags &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
  ) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateMerge(
    self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, ctx2 &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_zinsen_t
  ) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
 );
/
sho err

&lt;font color="#804040"&gt;&lt;b&gt;create&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;type&lt;/font&gt; body agg_zinsen_t &lt;font color="#6a5acd"&gt;is&lt;/font&gt;

static &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateInitialize(sctx &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t)
&lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
  sctx := agg_zinsen_t(&lt;font color="#ff00ff"&gt;0&lt;/font&gt;);
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;

member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateIterate(
  self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, 
  value &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; t_buchung
) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
  v_daysm &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;; 
  v_daysd &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;; 
  v_daysy &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;; 
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
  v_daysy := (extract(YEAR &lt;font color="#6a5acd"&gt;from&lt;/font&gt; pkg_zinsen.get_abrechnungsdatum) - extract(YEAR &lt;font color="#6a5acd"&gt;from&lt;/font&gt; value.buchungsdatum)) * &lt;font color="#ff00ff"&gt;360&lt;/font&gt;;
  v_daysm := (extract(MONTH &lt;font color="#6a5acd"&gt;from&lt;/font&gt; pkg_zinsen.get_abrechnungsdatum) - extract(MONTH &lt;font color="#6a5acd"&gt;from&lt;/font&gt; value.buchungsdatum)) * &lt;font color="#ff00ff"&gt;30&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;if&lt;/font&gt; to_char(value.buchungsdatum, &lt;font color="#ff00ff"&gt;'DD'&lt;/font&gt;) = &lt;font color="#ff00ff"&gt;'31'&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; to_char(value.buchungsdatum, &lt;font color="#ff00ff"&gt;'DDMM'&lt;/font&gt;) &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; (&lt;font color="#ff00ff"&gt;'2802'&lt;/font&gt;,&lt;font color="#ff00ff"&gt;'2902'&lt;/font&gt;) &lt;font color="#6a5acd"&gt;then&lt;/font&gt;
    v_daysd := &lt;font color="#ff00ff"&gt;30&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
    v_daysd := extract(DAY &lt;font color="#6a5acd"&gt;from&lt;/font&gt; value.buchungsdatum);
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
  v_daysd := extract(DAY &lt;font color="#6a5acd"&gt;from&lt;/font&gt; pkg_zinsen.get_abrechnungsdatum) - v_daysd;
  self.v_agg_zinsen := self.v_agg_zinsen + round((value.betrag * (v_daysy + v_daysd + v_daysm) / &lt;font color="#ff00ff"&gt;100&lt;/font&gt;)); 
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;

member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateTerminate(
  self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, 
  returnValue &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;, 
  flags &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
  &lt;font color="#6a5acd"&gt;if&lt;/font&gt; pkg_zinsen.get_zinssatz = &lt;font color="#ff00ff"&gt;0&lt;/font&gt; &lt;font color="#6a5acd"&gt;then&lt;/font&gt; 
    returnValue := self.v_agg_zinsen;
  &lt;font color="#6a5acd"&gt;else&lt;/font&gt; 
    returnValue := self.v_agg_zinsen / (&lt;font color="#ff00ff"&gt;360&lt;/font&gt; / pkg_zinsen.get_zinssatz);
  &lt;font color="#6a5acd"&gt;end&lt;/font&gt; &lt;font color="#6a5acd"&gt;if&lt;/font&gt;;
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;

member &lt;font color="#6a5acd"&gt;function&lt;/font&gt; ODCIAggregateMerge(self &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_zinsen_t, ctx2 &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_zinsen_t) &lt;font color="#6a5acd"&gt;return&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#6a5acd"&gt;is&lt;/font&gt;
&lt;font color="#6a5acd"&gt;begin&lt;/font&gt;
  self.v_agg_zinsen := self.v_agg_zinsen + ctx2.v_agg_zinsen;
  &lt;font color="#6a5acd"&gt;return&lt;/font&gt; ODCIConst.Success;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
&lt;font color="#6a5acd"&gt;end&lt;/font&gt;;
/
sho err
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Nun kommt die Einrichtung der Aggregatsfunktion an sich - die auf der eben eingespielten Implementierung
 basiert - wiederum nimmt sie keinen skalaren Datentypen entgegen, sondern &lt;b&gt;BUCHUNG_T&lt;/b&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
Then we crate the top-level aggregate function based on the above implementation. Again, the
input parameter is of type &lt;b&gt;BUCHUNG_T&lt;/b&gt;.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;CREATE&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; replace &lt;font color="#6a5acd"&gt;FUNCTION&lt;/font&gt; agg_zinsen (input t_buchung) &lt;font color="#6a5acd"&gt;RETURN&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
PARALLEL_ENABLE AGGREGATE &lt;font color="#6a5acd"&gt;USING&lt;/font&gt; agg_zinsen_t;
/
sho err
&lt;/pre&gt;
&lt;div lang="de"&gt;
Und das war's - nun kann man testen. Zuerst setzen wir die globalen Parameter im PL/SQL-Paket.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 And that's it. Now you can test the function. First set the "global" values ...
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
begin
 pkg_zinsen.set_abrechnungsdatum(to_date(&lt;font color="#ff00ff"&gt;'31122010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;));
 pkg_zinsen.set_zinssatz(&lt;font color="#ff00ff"&gt;1.5&lt;/font&gt;);
end;
/
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Und dann können wir die Zinsen eines Kontos abrechnen - mit nichts als einer SQL-Abfrage. Achtet darauf,
 dass Ihr syntaktisch zuerst ein &lt;b&gt;BUCHUNG_T&lt;/b&gt;-Objekt mit Buchungsdatum und Betrag erzeugt und dieses
 dann an die Aggregatsfunktion übergebt.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 And then you can calculate the interest amount with just a SQL query. Note that you (syntactically) 
 first create a &lt;b&gt;BUCHUNG_T&lt;/b&gt; object using the transaction date and amount. This object is passed
 to the aggregate function.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; konto, agg_zinsen(t_buchung (datum, betrag)) zinsen &lt;font color="#6a5acd"&gt;from&lt;/font&gt; tab_buchungen
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; konto
/

     KONTO     ZINSEN
---------- ----------
      4711 61,5666667
      4712      96,95
      4713         75
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Ein Zinssatz von &lt;b&gt;0%&lt;/b&gt; gibt die Zinszahl direkt zurück.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Set the interest rate to zero - and you will get the interest numbers.
&lt;/div&gt;
&lt;pre style="max-height: 300px; overflow-y: scroll; background-color: #eeeeee; border: 1px solid black;"&gt;
begin
 pkg_zinsen.set_abrechnungsdatum(to_date(&lt;font color="#ff00ff"&gt;'31122010'&lt;/font&gt;, &lt;font color="#ff00ff"&gt;'DDMMYYYY'&lt;/font&gt;));
 pkg_zinsen.set_zinssatz(&lt;font color="#ff00ff"&gt;0&lt;/font&gt;);
end;
/

&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt; konto, agg_zinsen(t_buchung (datum, betrag)) zinsen &lt;font color="#6a5acd"&gt;from&lt;/font&gt; tab_buchungen
&lt;font color="#6a5acd"&gt;group&lt;/font&gt; &lt;font color="#6a5acd"&gt;by&lt;/font&gt; konto
/

     KONTO     ZINSEN
---------- ----------
      4711      14776
      4712      23268
      4713      18000
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Es lassen sich also auch komplexere Dinge mit Benutzerdefinierten Aggregaten erledigen. Interessant
 sind hier viele Aufgaben aus der Finanzmathematik - Neben der einfachen Zinsrechnung ist auch jede
 Form der Renditeermittlung interessant. Und wenn es als Aggregatsfunktion bereitsteht, erhöhen sich
 die Nutzungsmöglichkeiten nochmals massiv - denn die Funktion steht per SQL-Abfrage bereit.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 So we have seen that user defined aggregates can also do a bit more complex things: Financial
 math might be an interesting application area. Yield calculation might also be done with
 a user defined aggregate. The good but about a user defined aggregate is that the implemented 
 functionality is being leveraged to the SQL layer - a simple SQL query with a GROUP BY or an
 analytic clause then does the trick.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-4571526460581475561?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/56ROec2lJ4Q" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/56ROec2lJ4Q/noch-ein-szenario-mit-user-defined.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/03/noch-ein-szenario-mit-user-defined.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-550189480578408898</guid><pubDate>Wed, 23 Feb 2011 12:21:00 +0000</pubDate><atom:updated>2011-02-23T13:22:09.376+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">FILE_TYPE</category><category domain="http://www.blogger.com/atom/ns#">BLOB</category><category domain="http://www.blogger.com/atom/ns#">doag</category><category domain="http://www.blogger.com/atom/ns#">unload</category><category domain="http://www.blogger.com/atom/ns#">FILE_PKG</category><title>BLOBs ins Dateisystem "entladen" - nur mit einer "SQL Abfrage"</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;"unload" a bunch of BLOBs to a filesystem folder &lt;/div&gt;
&lt;div lang="de"&gt;
 Wolltet Ihr schonmal eine Tabelle mit BLOBs in ein Verzeichnis "ausladen" ... wobei jeder BLOB
 in eine eigene Datei geschrieben werden soll ...?
 Bei mir war es heute wieder mal soweit ... und natürlich hätte man dazu ein wenig PL/SQL-Code mit UTL_FILE schreiben können - ich wollte es aber schnell haben. Also habe ich &lt;a href="http://plsqlexecoscomm.sourceforge.net" target="_blank"&gt;mein Package für Betriebssystem-Kommandos und Dateisystem-Zugriffe&lt;/a&gt; genommen. Meine Tabelle sah so aus ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Did you ever have the situation where you wanted to "unload" a table with BLOBs into a folder of the local filesystem - as a individual file for each BLOB. Today I had to do so ... and of course - we could write some PL/SQL code using UTL_FILE - but I did not have that much time. So I took my &lt;a href="http://plsqlexecoscomm.sourceforge.net" target="_blank"&gt;package for operating system commands and filesystem access&lt;/a&gt; and used that. My table looked as follows ...
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; desc target_table
 Name                                      Null?    Typ
 ----------------------------------------- -------- ------------------------
 ID                                                 NUMBER
 FILENAME                                           VARCHAR2(4000)
 FILECONTENT                                        BLOB
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Das "Entladen" konnte ich mit einem einfachen SQL SELECT machen:
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 And this SQL "query" did the trick ...
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; select 
  2  filename, 
  3  file_pkg.get_file('/home/oracle/test/'||filename).make_file().append_to_file(filecontent) bytes_written 
  4 from target_table;

FILENAME                                           BYTES_WRITTEN
-------------------------------------------------- -------------
2010-003a_yahoo_quote.html                                  3305
2010-003b-bestdbproject.html                                1433
2010-007_charset_nls_iana.html                              3125
2010-009_emalert_rss.html                                  17047
2010-009_emalert_rss_01.png                               171007
2010-009_emalert_rss_02.png                                38661
2010-009_emalert_rss_03.png                               141388
2010-010_blob-remote.html                                  14636
2010-011_imp_dataonly.html                                  3471
2010-012_recursive-table-functions.html                     4916
2010-013_romannumber.html                                   1153
2010-014-doag-sig-spatial.html                              1025
2010-015-dbms-applicationinfo.html                          7539
2010-016-addmonths.html                                     3842
2010-017-zip.html                                          29251
:                                                              :

50 rows selected.

Elaped: 00:00:00.17
&lt;/pre&gt;
&lt;div lang="de"&gt;
  Danach sah das Verzeichnis &lt;b&gt;/home/oracle/test&lt;/b&gt; so aus ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 The filesystem folder looked like this afterwards ...
&lt;/div&gt;
&lt;pre&gt;
[oracle@sccloud038 test]$ &lt;b&gt;ls -lah&lt;/b&gt;
total 752K
drwxr-xr-x 2 oracle oinstall 4.0K Feb 23 13:13 .
drwxr-xr-x 3 oracle oinstall 4.0K Feb 23 13:12 ..
-rw-r--r-- 1 oracle oinstall 2.8K Feb 23 13:13 2010-001a_apex-plugins.html
-rw-r--r-- 1 oracle oinstall 8.9K Feb 23 13:13 2010-001_dbms_datapump_exp.html
-rw-r--r-- 1 oracle oinstall 3.6K Feb 23 13:13 2010-002a_oscomm_0.9.html
-rw-r--r-- 1 oracle oinstall 8.0K Feb 23 13:13 2010-002_dbms_datapump_imp.html
-rw-r--r-- 1 oracle oinstall 3.3K Feb 23 13:13 2010-003a_yahoo_quote.html
-rw-r--r-- 1 oracle oinstall 1.4K Feb 23 13:13 2010-003b-bestdbproject.html
-rw-r--r-- 1 oracle oinstall  12K Feb 23 13:13 2010-003_dbms_stat_funcs.html
-rw-r--r-- 1 oracle oinstall 7.7K Feb 23 13:13 2010-004_miniskript_lo.html
-rw-r--r-- 1 oracle oinstall  11K Feb 23 13:13 2010-005_resumable.html
-rw-r--r-- 1 oracle oinstall 6.5K Feb 23 13:13 2010-006_video.html
-rw-r--r-- 1 oracle oinstall 3.1K Feb 23 13:13 2010-007_charset_nls_iana.html
-rw-r--r-- 1 oracle oinstall  29K Feb 23 13:13 2010-008-recursive_with.html
-rw-r--r-- 1 oracle oinstall 167K Feb 23 13:13 2010-009_emalert_rss_01.png
&lt;/pre&gt;
&lt;div lang="de"&gt;
  Ist doch nett, oder ...? Alles im allem habe ich für das Schreiben dieses Postings mehr Zeit gebraucht ...
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
  Creating this blog posting actually took more time than doing this piece of work ...
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-550189480578408898?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/FyEirEy5Bwk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/FyEirEy5Bwk/blobs-ins-dateisystem-entladen-nur-mit.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>2</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/02/blobs-ins-dateisystem-entladen-nur-mit.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3592984248764138907.post-563305384971915920</guid><pubDate>Fri, 11 Feb 2011 08:58:00 +0000</pubDate><atom:updated>2011-02-11T09:59:02.225+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sql</category><category domain="http://www.blogger.com/atom/ns#">aggregat</category><category domain="http://www.blogger.com/atom/ns#">group by</category><category domain="http://www.blogger.com/atom/ns#">product</category><category domain="http://www.blogger.com/atom/ns#">doag</category><title>SQL-Aggregatsfunktion "PRODUCT" fehlt ...? Kein Problem - wir bauen sie selbst!</title><description>&lt;div lang="en" style="display: none; color:#cc6600"&gt;Aggregate function for PRODUCT ...? No problem!&lt;/div&gt;
&lt;div lang="de"&gt;
 Auf einer Veranstaltung in München, während es um das Thema &lt;i&gt;Analytische Funktionen&lt;/i&gt; ging, fragte
 mich jemand nach einer Aggregatsfunktion für die Bildung eines Produktes - also nicht das Aufsummieren
 der Werte wie bei SUM, sondern das multiplizieren - und in der Tat: eine solche Funktion gibt es in
 Oracle nicht.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 Some days ago, at an event in Munich (the topic was about &lt;i&gt;analytic functions&lt;/i&gt; I was asked
 whether there is an aggregation function for a "product" - that means not summing up all the values,
 but multiplying them. And indeed: such a function is not available within Oracle.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Nun kann man das mit PL/SQL natürlich auf einfachste Weise nachprogrammieren - aber eine solche
 Funktion lässt sich nicht in SQL-Abfragen mit GROUP BY nutzen. Berechnungen für Datengruppen
 in einer Tabelle müssen dann mühsam mit PL/SQL nachgebildet werden.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 OK ... no problem ... this is an easy task for a PL/SQL developer. But wait: An own function
 could not be used in SQL GROUP BY clauses. If I wanted to calculate products for groups
 of table rows I'd have to implement this all by myself.
&lt;/div&gt;
&lt;div lang="de"&gt;
 Aber das muss nicht sein. Es ist kaum bekannt, aber man kann eigene Aggregatsfunktionen in der
 Datenbank hinterlegen. Das habe ich in einem &lt;a href="http://sql-plsql-de.blogspot.com/2007/03/group-by-wird-zusammen-mit.html"&gt;sehr frühen Blog-Posting schonmal genutzt&lt;/a&gt;: Mit
 der dort beschriebenen &lt;b&gt;LIST&lt;/b&gt;-Funktion kann man VARCHAR2-Spalten auch von vor Oracle11g
 zusammenfassen (in Oracle11g gibt es mit &lt;b&gt;LISTAGG&lt;/b&gt; ja eine eingebaute Funktion). Um ein
 User Defined Aggregate zu bauen, muss man eine Schnittstelle ausprogrammieren. Und hier ist
 der Code für &lt;b&gt;AGG_PRODUCT&lt;/b&gt;.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 But there are &lt;i&gt;user defined aggregates&lt;/i&gt;: Virtually nobody seems to know them but
 they are so powerful. I already used this technology in an old &lt;a href="http://sql-plsql-de.blogspot.com/2007/03/group-by-wird-zusammen-mit.html"&gt;blog posting&lt;/a&gt;: The &lt;b&gt;LIST&lt;/b&gt; function aggregates
 VARCHAR2 values - in 10g and before (In Oracle11g the built-in function &lt;b&gt;LISTAGG&lt;/b&gt; was introduced).
 To create an user defined aggregate, an interface must be implemented. This interface 
 has cumbersome function names but is very simple to implement. Here we go for &lt;b&gt;AGG_PRODUCT&lt;/b&gt;.
&lt;/div&gt;
&lt;pre&gt;
&lt;font color="#008080"&gt;drop&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; agg_product;
&lt;font color="#008080"&gt;drop&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt; agg_product_t;

&lt;font color="#008080"&gt;create&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt; agg_product_t &lt;font color="#804040"&gt;&lt;b&gt;as&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;object&lt;/b&gt;&lt;/font&gt;(
  v_agg_product &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,

  &lt;font color="#804040"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateInitialize(
    sctx &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t
  ) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  &lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateIterate(
    &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t, &lt;font color="#008080"&gt;value&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
  ) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  &lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateTerminate(
    &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_product_t, returnValue &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;, flags &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
  ) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;,
  &lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateMerge(
    &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t, ctx2 &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_product_t
  ) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
 );
&lt;font color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;
sho err

&lt;font color="#008080"&gt;create&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;replace&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/font&gt; agg_product_t &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt;

&lt;font color="#804040"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateInitialize(sctx &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t)
&lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/font&gt;
  sctx &lt;font color="#804040"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/font&gt; agg_product_t(&lt;font color="#ff00ff"&gt;1&lt;/font&gt;);
  &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ODCIConst.Success;
&lt;font color="#804040"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/font&gt;;

&lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateIterate(
  &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t, 
  &lt;font color="#008080"&gt;value&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/font&gt;
  &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product&lt;font color="#804040"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;*&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;nvl&lt;/font&gt;(&lt;font color="#008080"&gt;value&lt;/font&gt;, &lt;font color="#ff00ff"&gt;1&lt;/font&gt;);
  &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ODCIConst.Success;
&lt;font color="#804040"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/font&gt;;

&lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateTerminate(
  &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_product_t, 
  returnValue &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;, 
  flags &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/font&gt;
  returnValue &lt;font color="#804040"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product;
  &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ODCIConst.Success;
&lt;font color="#804040"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/font&gt;;

&lt;font color="#804040"&gt;&lt;b&gt;member&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/font&gt; ODCIAggregateMerge(&lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;OUT&lt;/b&gt;&lt;/font&gt; agg_product_t, ctx2 &lt;font color="#804040"&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/font&gt; agg_product_t) &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;begin&lt;/b&gt;&lt;/font&gt;
  &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;not&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;
    &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
  &lt;font color="#804040"&gt;&lt;b&gt;elsif&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;not&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;not&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;
    &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;*&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product;
  &lt;font color="#804040"&gt;&lt;b&gt;elsif&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;not&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;
    &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;:=&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;*&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;1&lt;/font&gt;;
  &lt;font color="#804040"&gt;&lt;b&gt;elsif&lt;/b&gt;&lt;/font&gt; ctx2.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;self&lt;/b&gt;&lt;/font&gt;.v_agg_product &lt;font color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font color="#ff00ff"&gt;null&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;
    &lt;font color="#ff00ff"&gt;null&lt;/font&gt;;
  &lt;font color="#804040"&gt;&lt;b&gt;end if&lt;/b&gt;&lt;/font&gt;;
  &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ODCIConst.Success;
&lt;font color="#804040"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/font&gt;;
&lt;font color="#804040"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/font&gt;;
&lt;font color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;
sho err

&lt;font color="#008080"&gt;CREATE&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;replace&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;FUNCTION&lt;/b&gt;&lt;/font&gt; agg_product (input &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;) &lt;font color="#804040"&gt;&lt;b&gt;RETURN&lt;/b&gt;&lt;/font&gt; &lt;font color="#2e8b57"&gt;&lt;b&gt;number&lt;/b&gt;&lt;/font&gt;
&lt;font color="#804040"&gt;&lt;b&gt;PARALLEL_ENABLE&lt;/b&gt;&lt;/font&gt; AGGREGATE &lt;font color="#804040"&gt;&lt;b&gt;USING&lt;/b&gt;&lt;/font&gt; agg_product_t;
&lt;font color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;
sho err
&lt;/pre&gt;
&lt;div lang="de"&gt;
  Die Funktion könnt Ihr danach sofort verwenden.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 You can use the new function immediately.
&lt;/div&gt;
&lt;pre&gt;
SQL&amp;gt; select deptno, agg_product(sal) product_sal from emp
  2  group by deptno

    DEPTNO PRODUCT_SAL
---------- ------------------------------
        10 15925000000
        20 23562000000000000
        30 10153125000000000000
&lt;/pre&gt;
&lt;div lang="de"&gt;
  Auch als &lt;i&gt;analytische Funktion&lt;/i&gt; kann sie verwendet werden.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 It can also be used as an &lt;i&gt;analytic function&lt;/i&gt;. This is very powerful.
&lt;/div&gt;
&lt;pre&gt;
select 
  ename, 
  agg_product(sal) over (order by sal desc rows between unbounded preceding and current row) product_sal 
from emp;

ENAME          PRODUCT_SAL
---------- ---------------
KING                  5000
FORD              15000000
SCOTT          45000000000
JONES      133875000000000
BLAKE      3,815437500E+17
CLARK      9,347821875E+20
:                        :
&lt;/pre&gt;
&lt;div lang="de"&gt;
 Das geht mit einer normalen PL/SQL-Funktion nun wirklich nicht; die ganze analytische "Power" 
 von SQL kann so ausgenutzt werden. Nicht jeder braucht wirklich eine AGG_PRODUCT-Funktion; aber 
 wenn Ihr Aggregate mit eigenen Funktionen bilden müsst, sind die &lt;i&gt;User Defined Aggregates&lt;/i&gt;
 auf jeden Fall einen Blick wert.
&lt;/div&gt;
&lt;div lang="en" style="display: none;"&gt;
 A user defined aggregate has a big advantage over a plain PL/SQL function. Foremost it
 can be used in SQL GROUP BY and analytic clauses. All the analytic power of SQL can be
 used with your own code for aggregations. 
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3592984248764138907-563305384971915920?l=sql-plsql-de.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SqlUndPlsqlInOracle/~4/m8QvXG4j68U" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/SqlUndPlsqlInOracle/~3/m8QvXG4j68U/sql-aggregatsfunktion-product-fehlt.html</link><author>noreply@blogger.com (Carsten Czarski)</author><thr:total>3</thr:total><feedburner:origLink>http://sql-plsql-de.blogspot.com/2011/02/sql-aggregatsfunktion-product-fehlt.html</feedburner:origLink></item></channel></rss>

