Skip to Main Content
 
Titelbild Muniqsoft Training

Search Results

Oracle Tipp Text

APEX Region Display Selector Status auswerten

Bereich:APEX, Version: ab APEX 5.0, Letzte Überarbeitung: 19.12.2019

Keywords:APEX Region Display Selector

In einem meiner letzten APEX Kurse kam die Frage auf, wie kann man ermitteln, welche der Regionen duch den Region Display Selector ausgewählt wurde. Das ist zum Glück sehr leicht:

  • Wir brauchen eine Seite mit mindestens 2 Regionen (Region A und B)
  • Eine Region Display Selector Region
  • Eine Textfeld Item in der Region Display Selector Region (nicht in Region a oder B !) mit Namen P1_REGION_ID
  • und den folgenden Javascript (jQuery) Code im Page Propertie: Javascript / Execute When Page Loads:

$('.apex-rds').data('onRegionChange', function(mode, activeTab) {
apex.item( "P1_REGION_ID" ).setValue( activeTab.href, null, true )
});


Wenn mann nun wissen möchte welche Region ausgewählt wurde, sieht man nach der Auswahl die Nummer im Textfeld. Die kann man sich notieren und ggf eine Aktion damit verbinden.
Bei uns kamen z.B. folgende Werte raus:

  • #R6572207236661919
  • #R1415854210228239
  • #SHOW_ALL

Natürlich können Sie, wenn die Nummern bekannt sind, das Text-Feld in Hidden umändern...
 



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


LISTAGG Alternative mit CLOB Datentyp (und damit 128TB Maximallänge)

Bereich:PL/SQL:SQL, Version: ab RDBMS 10.x:RDBMS 12.x:RDBMS 19.3:RDBMS 21.1, Letzte Überarbeitung: 11.01.2021

Keywords:listagg clob

Wer kennt es nicht, immer wenn man mal listagg benötigt, reciht der Speicherplatz nicht, weil listagg maximal 32767 Bytes zurückgeben kann.

Mit einem kleinen Trick klappt es auch mit CLOB als Rückggaabetyp. Dazu verwenden wir die XML Funktion XMLELEMENT.
Keine Angst, sie müssen kein XML dazu beherschen:-)

Wir haben das ganze in eine WITH Funktion gekappselt, für den Fall, dass Sie kein CREATE PROCEDURE RECHT haben.
Die Funktion hat bis zu 3 Parameter,
column_name ist der Name der Spalte, die zusammengefasst werden soll
table_name ist der Name der Tabelle, in der die Spalte enthalten ist
where_cond ist Optional und beinhaltet eine Filterklausel Default 1=1 also alles)
order_by Optional kann auch ein Sortierreihenfolge bei der Ausgabe definiert werden (Default: Sortiert nach der Ausgabespalte)
delimiter ist auch Optional und gibt das Trennzeichen zwischen der Ausgabe der Spaltenwerte an (Default ',' )

WITH
FUNCTION listagg_clob (
column_name IN VARCHAR2,
table_name  IN VARCHAR2,
where_cond  IN VARCHAR2 DEFAULT NULL,
order_by    IN VARCHAR2 DEFAULT NULL,
delimiter   IN VARCHAR2 DEFAULT ',')
RETURN CLOB
IS
ret_clob CLOB;
BEGIN
EXECUTE IMMEDIATE q'!select replace(replace(XmlAgg(
                  XmlElement("a", !' || column_name ||')
                  order by ' ||nvl(order_by,'1') ||
                  q'!)
                  .getClobVal(),
              '<a>', ''),
            '</a>','!'|| delimiter ||q'!') as aggname
   from !' || table_name || q'!
  where  !' || nvl(where_cond,' 1=1') INTO ret_clob;
RETURN ret_clob;
END;
SELECT listagg_clob('table_name','all_tables') FROM dual;



Wenn Sie das Ganze als eigenständige Funktion anlegen möchten:

CREATE OR REPLACE FUNCTION listagg_clob (
column_name IN VARCHAR2,
table_name  IN VARCHAR2,
where_cond  IN VARCHAR2 DEFAULT NULL,
order_by    IN VARCHAR2 DEFAULT NULL,
delimiter   IN VARCHAR2 DEFAULT ',')
RETURN CLOB
IS
ret_clob CLOB;
BEGIN
EXECUTE IMMEDIATE q'!select replace(replace(XmlAgg(
                  XmlElement("a", !' || column_name ||')
                  order by ' ||nvl(order_by,'1') ||
                  q'!)
                  .getClobVal(),
              '<a>', ''),
            '</a>','!'|| delimiter ||q'!') as aggname
   from !' || table_name || q'!
  where  !' || nvl(where_cond,' 1=1') INTO ret_clob;
RETURN ret_clob;
END;
/
 


Testcases:

SELECT listagg_clob('table_name','all_tables')
FROM dual;
SELECT listagg_clob('table_name','all_tables',order_by=>'table_name desc nulls last')
FROM dual;

SELECT length(listagg_clob(q'!owner||'.'||table_name!','all_tables', where_cond=>q'!table_name<>'MARCO'!'))
FROM dual;
=>60962

SELECT listagg_clob('table_name','all_tables',order_by=>'table_name desc nulls last', delimiter=>':')
FROM dual;
 


Damit können Sie nun (fast) unbegrenzt die Werte einer Spalte zusammenfassen und weiterverarbeiten.



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


Oracle APEX Variablen im Oracle Trigger auslesen

Bereich:APEX:PL/SQL, Version: ab APEX 18.1, Letzte Überarbeitung: 12.01.2021

Keywords:Oracle Apex Trigger Variablen

Wenn man in seiner Oracle Datenbank Trigger zu Audit-Zwecken verwendet, ist man erstaunt, das als Apex Benutzer nicht der Anmeldebenutzer sondern ANONYMOUS oder APEX_PUBLIC_USER erscheint.

Das Problem kann man natürlich mit ein paar PL/SQL Objekten lösen.:-)
 

GRANT CREATE ANY CONTEXT TO scott;
DROP CONTEXT APEX_ENV;


Etwas unbekannt ist das Oracle Objekt Context, mit dem die Funktion sys_context erweitert werden kann.
Die Funktion sys_context besteht aus zwei Parametern:
Parameter 1: userenv
Parameter 2: ca 60 Stück u.a. OS_OSER, SESSION_USER, ...
Wir können die Funktionen nun erweitern, indem wir den ersten Parameter ändern auf apex_env
 

CREATE OR REPLACE CONTEXT apex_env
USING apex_env
/


Die Context Funktion benötigt zum Auffruf immer ein Package, das wir hiermit anlegen:

CREATE OR REPLACE PACKAGE apex_env
IS
 PROCEDURE set_context(
 p_variable IN VARCHAR2,
 p_value    IN VARCHAR2);
END;
/

CREATE OR REPLACE PACKAGE BODY apex_env IS
  PROCEDURE set_context(
    p_variable IN VARCHAR2,
    p_value    IN VARCHAR2) IS
  BEGIN
    dbms_session.set_context('apex_env',p_variable, p_value);
  END set_context;
END apex_env;
/

 

CREATE PUBLIC SYNONYM apex_env for apex_env;
GRANT EXECUTE ON my_login_package TO scott;


Führen wir einen Testcase durch und setzen den Context manuell:

BEGIN
apex_env.set_context('APP_USER','Marco');
apex_env.set_context('APP_PAGE_ID',123);
apex_env.set_context('APP_ID',100);
apex_env.set_context('APP_SESSION',123454678);
END;
/


Nun können wir den Context wieder auslesen:
 

SELECT
sys_context('apex_env','APP_USER') as APP_USER,
sys_context('apex_env','APP_PAGE_ID') as APP_PAGE_ID,
sys_context('apex_env','APP_ID') as APP_ID,
sys_context('apex_env','APP_SESSION') as APP_SESSION
FROM dual;


Jetzt erstellen wir uns eine Audit-Tabelle, in der stehen soll, welcher APEX Benutzer auf welcher Seite, in welcher APP mit welcher Session ID
die Änderung durchgeführt hat.

CREATE TABLE emp_audit (
empno        INT,
app_user     VARCHAR2(30),
app_page_id  INT,
app_id       INT,
app_session  INT);


und der passende Trigger dazu:

CREATE OR REPLACE TRIGGER EMP_TRG
BEFORE DELETE OR INSERT OR UPDATE ON EMP
FOR EACH ROW
BEGIN
  INSERT INTO emp_audit (empno,app_user,app_page_id,app_id,app_session)
  VALUES (nvl(:new.empno,:old.empno),
    sys_context('apex_env','APP_USER'),
    sys_context('apex_env','APP_PAGE_ID'),
    sys_context('apex_env','APP_ID'),
    sys_context('apex_env','APP_SESSION'));
END;
/


Jetzt brauchen wir nur noch den kleinen Testblock in unsere APEX-App einbauen:
Gehen Sie dazu auf: Edit Application Properties / Security und dort auf Database Session.
Im Bereich "Initialization PL/SQL Code" geben Sie dort ein:

BEGIN
apex_env.set_context('APP_USER',:APP_USER);
apex_env.set_context('APP_PAGE_ID',:APP_PAGE_ID);
apex_env.set_context('APP_ID',:APP_ID);
apex_env.set_context('APP_SESSION',:APP_SESSION);
END;
/


Weitere Tipps und Tricks erfahren Sie in einem unserer APEX oder PL/SQL Kurse (auch als Video-Streaming)



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


Oracle ORDS Check Skript für gängigste Webserver 404 Fehler

Bereich:ORDS, Version: ab ORDS 21.2, Letzte Überarbeitung: 05.05.2020

Keywords:ORDS Check Skript für Fehler 404

Nachdem ich schon mehere Tage mit der Suche nach Fehlern im Oracle ORDS mit APEX verbracht habe, war es mal Zeit ein Prüf-Skript zu schreiben.

Das Prüfskript prüft einige der gängigsten Probleme die einen Web Fehler 404 erzeugen.

Das Skript fragt Sie die folgenden Parameter:
Pfad des webapss Ordner (meist /opt/tomcat*[/latest] )
Name des ORDS meist "ords". Das ist der Name, der in der Datei ords.war verwendet wird.
Zusätzlich werden die Passwörter für die Accounts APEX_PUBLIC_USER, ORDS_PUBLIC_USER, APEX_REST_PUBLIC_USER
gefragt und eine Anmeldung an der Datenbank durchgeführt. Fehler, wie Account Locked oder Passwort falsch werden dadurch gefunden.
 

Der letzte Check-Teil prüft die 4 XML Config-Dateien. Diese waren bei unseren Installationen teilweise nicht vollständig angelegt worden.

######################################################################################################
#!/bin/bash
# chmod u+x check_ords.sh
######################################################################################################

#export CONFIG_DIR=/opt/oracle/ords_conf
#export ORACLE_ORDS=ords

read -p 'Webserver webapps Ordner: [/opt/tomcat/latest]' -r WEB_DIR
WEB_DIR=${WEB_DIR:-/opt/tomcat/latest}
read -p 'Oracle ORDS Name: [ords]' -r ORACLE_ORDS
ORACLE_ORDS=${ORACLE_ORDS:-ords}
read -p 'Passwort APEX_PUBLIC_USER: ' -r -s APEX_PU
echo
read -p 'Passwort ORDS_PUBLIC_USER: ' -r -s ORDS_PU
echo
read -p 'Passwort APEX_REST_PUBLIC_USER: ' -r -s APEX_RPU

echo -e "\nCheck XML Config Files:"
export CONFIG_DIR=`cat $WEB_DIR/webapps/$ORACLE_ORDS/WEB-INF/web.xml | egrep "<param-value>/" | cut -c22-90 | sed -e 's/<\/param-value>//g'`
export ORACLE_HOSTNAME=`cat $CONFIG_DIR/$ORACLE_ORDS/defaults.xml | egrep "db\.hostname" | cut -c26-89 | sed -e 's/<\/entry>//g'`
export ORACLE_SERVICENAME=`cat $CONFIG_DIR/$ORACLE_ORDS/defaults.xml | egrep "db\.servicename" | cut -c29-89 | sed -e 's/<\/entry>//g'`
export ORACLE_PORT=`cat $CONFIG_DIR/$ORACLE_ORDS/defaults.xml | egrep "db\.port" | cut -c22-89 | sed -e 's/<\/entry>//g'`

echo "Found: Host=$ORACLE_HOSTNAME, Port=$ORACLE_PORT, Service=$ORACLE_SERVICENAME"
echo "Found: ORDS=$ORACLE_ORDS, Config_Dir=$CONFIG_DIR"

function check_account()
{
echo "Check: $1"
$ORACLE_HOME/bin/sqlplus -S -L $1/$2@$ORACLE_HOSTNAME:$ORACLE_PORT/$ORACLE_SERVICENAME<<EOF | egrep "ORA-"
EXIT
EOF
}

echo "# Checking Accounts ..."
check_account APEX_PUBLIC_USER $APEX_PU
check_account ORDS_PUBLIC_USER $ORDS_PU
check_account APEX_REST_PUBLIC_USER $APEX_RPU


function check_config_files()
{
if [ -f "$CONFIG_DIR/$ORACLE_ORDS/conf/$1" ]; then
    echo "OK: $1 `ls -al $CONFIG_DIR/$ORACLE_ORDS/conf/$1 |  awk '{ print  $1" "$3":"$4}'`"
else
    echo "$1 missing"
fi
}

echo "# Checking XML Config Files in $CONFIG_DIR/$ORACLE_ORDS/conf"
check_config_files apex.xml
check_config_files apex_al.xml
check_config_files apex_pu.xml
check_config_files apex_rt.xml

echo "# Optional Checks:"
echo "java -jar $ORACLE_ORDS.war validate"
echo "java -jar $ORACLE_ORDS.war validate --database apex"


Ich hoffe Sie können damit zukünftig Ihre Oracle ORDS Fehler finden ...



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


APEX 23.2 Installation mit minimaler Downtime

Bereich:APEX, Version: ab APEX 23.2:ORDS 23.2, Letzte Überarbeitung: 25.11.2023

Keywords:APEX 23.2 Installation mit minimaler Downtime

Lange haben wir darauf gewartet, nun ist es endlich verfügbar. Seit  November 2023 kann man Oracle APEX 23.2 herunterladen. Im folgenden Tipp beschreiben wir kurz, wie es installiert wird.

Sie können APEX in jede Oracle Personal, Standard, Enterprise oder Express Edition (XE oder FREE) Datenbank installieren ab Version 18c

0. Erstellen Sie ein funktionierendes Backupo des Workspace, der Workspace Files und aller APEX Applikationen.
Das haben wir bereits in einem anderen Tipp thematisiert.

1. Herunterladen des Zip Files
Download Oracle APEX 23.2

2. Auspacken des Zip Files

# unzip apex_23.2.zip


3. Neue Bilderverzeichnisse vorbereiten und evtl an den tomcat Benutzer anpassen (teilweise wird auch www-data verwendet)

# cp -R /u01/software/apex/images/ /var/www/html/i2
# chown -R tomcat:tomcat i2



4. Webserver oder EPG stoppen (als root oder sudo)

# systemctl stop tomcat



5. In den ausgepackten Installationsordner gehen und die Installation via sql*plus starten:

# cd /u01/software/apex/
# sqlplus / as sysdba
SQL> SELECT tablespace_name FROM dba_tablespaces; -- Suchen Sie sich einen passenden aus
SQL> SELECT distinct tablespace_name FROM dba_segments
     WHERE owner like 'APEX%'; -- Da war bisher installiert (wenn es schon eine alte Installation gab )
SQL> @apexins APEX_TBS APEX_TBS TEMP /i/


6. Während das Skript läuft (bei unseren Maschinen ca 30 Min) kann der Bilderordener gewechselt werden

# mv /var/www/html/i /var/www/html/i_231_old
# mv /var/www/html/i2 /var/www/html/i


7. Nachdem das APEX 20.1 Installationsskript fertig ist, die REST Schnittstelle aktualisieren.
Sie sollten dazu die Passwörter der Benutzer APEX_LISTENER und APEX_REST_PUBLIC_USER zu Hand haben :-)

SQL> @apex_rest_config


8. Webserver oder EPG starten (als root oder sudo)

# systemctl start tomcat
oder
SQL> EXEC dbms_xdb.sethttpport(8080); -- oder den Port aus Schritt 4 wieder verwenden


9. Passwort für den Internal Workspace Admin Nutzer ändern

SQL> @apxchpwd


Sie werden die folgenden Parameter gefragt:
Benutzername: [Schlau ist, ihn nicht ADMIN zu nennen !]
Email: [Ihre Email Adresse angeben ]
Passwort: [Nur einmal !, also bitte nicht vertippen :-) ]

Vergessen Sie zum Abschluß nicht, den Browser Cache zu leeren!

Neuerung für die Neuinstallation:
Es gibt ein neues Universalskript mit Namen: apxsilentins.sql
Es übernimmt automatisch die folgenden Schritte:
a, Installation von APEX (Skript apexins.sql)
b, Erstellung oder Upgrade des Instanz-Admin-Accounts (Skript: apxchpwd.sql)
c, APEX_PUBLIC_USER konigurieren
d, Anpassung der Network ACLs
e, Static File Support mittels REST (Skript: apex_rest_config.sql

Aufruf-Syntax:

SQL> @apxsilentins.sql tablespace_apex tablespace_files tablespace_temp images
      password_apex_pub_user password_apex_listener password_apex_rest_pub_user
      password_internal_admin


Parametererklärung:

  • tablespace_apex  Tablespace für die Installation des APEX Benutzers
  • tablespace_files   Tablespace für Uploaded Files
  • tablespace_temp  Sortiertablespace
  • images  Bildordner
  • password_apex_pub_user Passwort für apex_public_user
  • password_apex_listener  Passwort für apex_listener
  • password_apex_rest_pub_user Passwort für apex_rest_public_user
  • password_internal_admin Passwort für den Internal Admin Benutzer


Beispielaufruf:

SQL> @apxsilentins.sql SYSAUX SYSAUX TEMP /i/ Passw0rt!#1 Passw0rt!#2 Passw0rt!#3 Passw0rt!#4


Alternative für Produktiv-Umgebungen (mit absoluter Downtime von unter 1 Minute!):
1-3 siehe oben
4. Webserver nicht beenden !
5. Variablen für die Parameter vorbereiten

SQL> REM Wenn Sie Ihren Tablespace nicht mehr wissen:
SQL> SELECT tablespace_name FROM dba_tablespaces ORDER BY 1;

SQL> DEFINE tablespace_apex=SYSAUX
SQL> DEFINE tablespace_files=SYSAUX
SQL> DEFINE tablespace_temp=TEMP
SQL> DEFINE images=/i/

 

Minimale Downtime, während der Installation (unter 1 Minute )


6. Phase 1: Installation des Full Development (Lief bei uns: 2m 10s)

SQL> @apexins1.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.

Wenn nur die Runtime Version installiert werden soll:

SQL> @apxrtins1.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.


7. Phase 2: Entwicklung ab jetzt nicht mehr möglich, Endanwender können weiterarbeiten (Lief bei uns: 4m 20s)

SQL> SET define "&"
SQL> @apexins2.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.

Wenn nur die Runtime Version installiert werden soll:

SQL> SET define "&"
SQL> @apxrtins2.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.

 

In den 4 Minuten, wo das Skript läuft haben Sie Zeit die Bilder/CSS/Javascript Dateien in das passende Webserver Verzeichnis zu kopieren.
Nur überschreiben Sie damit ja das alte Image Verzeichnis und dass muss ja noch 5 Minuten leben

Trick: Kopieren Sie die Bilder in ein Verzeichnis i2

Bei Apache Tomcat wäre das (bei uns): 

/opt/tomcat/latest/webapps

Wenn der Apache Webserver als Reverse Proxy davor geschalten ist: 

/var/www/html

Prüfen Sie ob die Dateien gelesen werden können (Rechte und Eigentümer beachten!)

https://ihr_server/i/apex_version.txt

Sollte zurückliefern:

Application Express Version:  23.2
8. Webserver beenden

# systemctl stop tomcat


9. Phase 3: Endanwender können NICHT mehr weiterarbeiten (lief bei uns 0m 40s)

SQL> SET define "&"
SQL> @apexins3.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.

Wenn nur die Runtime Version installiert werden soll:

SQL> SET define "&"
SQL> @apxrtins3.sql &tablespace_apex. &tablespace_files. &tablespace_temp. &images.


Denken Sie nun daran die Bilverzeichnisse zu tauschen, also z.B.

# mv i i_old
# mv i2 i

 

BONUSTIPP:
Prüfen Sie, ob ACLS für die alte APEX Installation vorhanden sind, die gelöscht werden sollten:
Oracle APEX 23.2 migriert sogar die alten ACLS !!! Super !

SQL> select na.host,na.lower_port,na.upper_port,
nap.principal,nap.privilege,nap.end_date
from dba_network_acl_privileges nap, dba_network_acls na
where nap.acl=na.acl
and principal like 'APEX%'
order by principal;


Wenn Sie mit den Tests! erfolgreich durch sind, können Sie den alten Oracle APEX Benutzer löschen

SQL> DROP USER APEX_220200 CASCADE;


Und nun viel Spaß mit der schönen neuen APEX 23.2 Version. 

PS: Wir schulen Seit November 2023 schon mit der neuen Oracle APEX Version 23.2



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


Partitionierte Tabellen Beispiele in Postgres

Bereich:Postgres, Version: ab PG 13, Letzte Überarbeitung: 14.06.2021

Keywords:Postgres, Partitionierung

Postgres hat ja nun seit der Version 10 auch Partitionierung bei Tabellen im Einsatz und das natürlich wie immer kostenlos.
Derzeit werden die folgenden Partitionierungen unterstützt:

  • Range Partitionierung
  • List Partitionierung
  • Hash Partitionierung

Beispiel zu Range Partitionierung (ohne Primary Key):

CREATE TABLE emp (
    empno INT,
    ename VARCHAR(30),
    hiredate         date not null
) PARTITION BY RANGE (hiredate);

CREATE TABLE emp_p2016 PARTITION OF emp
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01');

CREATE TABLE emp_y2017 PARTITION OF emp
FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');

INSERT INTO emp (empno,ename,hiredate)
    VALUES (8000,'MARCO','2016-03-10');


Wenn Die Tabelle einen Primary beinhalten soll, muss die Partitionierungspalte im Key enthalten sein, sonst erhält man den Fehler:
FEHLER:  insufficient columns in PRIMARY KEY constraint definition
DETAIL:  PRIMARY KEY constraint on table "emp" lacks column "hiredate" which is part of the partition key.

CREATE TABLE emp (
    empno INT ,
    ename VARCHAR(30),
    hiredate         date not null,
    PRIMARY KEY(empno,hiredate)
) PARTITION BY RANGE (hiredate);


Beispiel zu LIst Partitionierung:

CREATE TABLE dept
( deptno  int,   
  dname   varchar(20),
  loc     varchar(20)  );

CREATE TABLE dept10 PARTITION OF dept FOR VALUES IN (10,12,14);
CREATE TABLE dept20 PARTITION OF dept FOR VALUES IN (20,22,24);
CREATE TABLE dept30 PARTITION OF dept FOR VALUES IN (30,32,34);
CREATE TABLE dept_def PARTITION OF dept DEFAULT;


In der optionalen Default Partition landen alle Einträge, die sonst in keine Partition passen.
Wenn Sie keine Default Partition besitzen und der Datensatz kann ich zugeordnet werden, bekommen Sie den Fehler:
FEHLER:  keine Partition von Relation »dept« für die Zeile gefunden
DETAIL:  Partitionierungsschlüssel der fehlgeschlagenen Zeile enthält (deptno) = (50).

Partitionen löschen:

DROP TABLE dept30;


Hash Partitionierung
Bei der Hash Partitionierung übernimmt Postgres die richtige Verteilung der Daten auf die Partitionen:

CREATE TABLE dept (
deptno         int primary key,
dname         VARCHAR(10),
loc         VARCHAR2(10)  )
partition by hash(deptno);

CREATE TABLE dept_1 PARTITION OF dept FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE dept_2 PARTITION OF dept FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE dept_3 PARTITION OF dept FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE dept_4 PARTITION OF dept FOR VALUES WITH (MODULUS 4, REMAINDER 3);

\d+ dept


Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:


Trigger Beispiele in Postgres

Bereich:Postgres, Version: ab PG 12, Letzte Überarbeitung: 25.03.2020

Keywords:Trigger, Postgres, Row Trigger, Statement Trigger

Bei Postgres wird im Gegensatz zu Oracle die Aufgabe in zwei Teile zerlegt:
1. Eine Funktion, die das Doing übernimmt
2. Einen Trigger, der bei einem Event die Funktion aufruft.
 

CREATE TRIGGER mytrig [BEFORE|AFTER|INSTEAD OF] event_name
ON mytable;
Beispiel: Insert, Update, Delete, Truncate Before Row Trigger
CREATE TRIGGER mytrig BEFORE
INSERT OR DELETE OR UPDATE OR TRUNCATE 
ON mytable
FOR EACH ROW
EXECUTE PROCEDURE myfunc();
Beispiel: Insert, Update, Delete, Truncate Instead of Row Trigger (zündet nur bei Änderungen an einer View)
CREATE TRIGGER mytrig INSTEAD OF
INSERT OR DELETE OR UPDATE OR TRUNCATE
ON myview
FOR EACH ROW
EXECUTE PROCEDURE mytrgfunc();
Beispiel für die Funktion, die der Trigger dann aufruft:
CREATE OR REPLACE FUNCTION mytrgfunc()
RETURNS TRIGGER AS $$
   BEGIN
      INSERT INTO AUDIT(new_col1, old_col2)
      VALUES (new.ID, old.ID);
      RETURN NEW;
   END;
$$ LANGUAGE plpgsql;


Welche Trigger gibt es in der DB?

SELECT * FROM pg_trigger;


oder für eine spezielle Tabelle:

SELECT tgname FROM pg_trigger, pg_class
WHERE tgrelid=pg_class.oid
AND relname='mytab';
Trigger bei Bedarf wieder löschen:
DROP TRIGGER trigger_name;


 



Weitere Interessente Artikel zum Thema:


Empfohlene Schulungen zum Thema:



    Oracle Fehler in Win 10 Benachrichtigungen

    Bereich:DBA, Version: ab RDBMS 12.x, Letzte Überarbeitung: 16.08.2024

    Keywords:Oracle Fehler, Win 10, Benachrichtigungen

    Nach 4 Monatiger Verspätung gegenüber der Linux Version war es am 20.2.2019 endlich so weit, das neue Oracle XE Release ist zum Download verfügbar.

    Folgende Limitierungen weist die Version 18c XE auf:

    • Maximal 12 GB an Daten können in den Tablespaces gespeichert werden
    • Maximal 1 Instanz pro Server
    • Maximal 2GB an Hauptspeicher sind nutzbar
    • Maximal 2 Cores werden genutzt
    • 3 Pluggable Datenbanken (PDB´s) können verwendet werden:
      • CDB$ROOT
      • PDB$SEED
      • XEPDB1

    Leider kann man bei der Erstinstallation nur die Pluggable Database Version installieren.

    Es gibt aber einen Trick, das wieder rückgängig zu machen:

    1. man installiert die Version laut den Default Vorgaben

    a, Auspacken der Datei OracleXE184_Win64.zip in einen eigenen Ordner.
    b, Starten der Datei setup.exe
    c, Weiter klicken
    d, Ich stimme zu ... klicken
    e, Pfad ändern oder weiter klicken
    f, Passwort für Benutzer SYS zweimal angeben
    g, Installieren klicken
    h, Bei der Rückfrage der Firewall die Kommunikation gestatten "Zugriff zulassen"
    i, ca. 20 Min später .. "Fertigstellen"

    Update vom 12.06.2019:
    Wenn Sie schnell sind (sie haben ca. 2 Minuten Zeit) können Sie die Installation der CDB Datenbank mit einem Trick abbrechen lassen. Gehen Sie dazu wie folgt vor:
    Bei Schritt (g) legt der Installer tausende Dateien ins Zielverzeichnis.
    Gehen Sie (sobald vorhanden) in die Datei <ORACLE_HOME>\dbhomeXE\assistants\dbca\templates\XE_Datbase.dbc
    Ersetzen Sie dort in Zeile 49 die Zeile

     <SourceDBName cdb="true">xe</SourceDBName>

    durch

     <SourceDBName cdb="false">xe</SourceDBName>

    der Installer bricht dann nach ca 3,3 Minuten ab und Sie können dann direkt eine NON-CDB Datenbank mittels dbca installieren. Sie sparen dadurch ca 20 Minuten ein!

    Alternative: Silent Installation
    Bei der Oracle Silent Installation können Sie alle relevanten Parameter bereits in einer Datei hinterlegen, die Installation kommt dann ohne weitere Interaktion aus.

    Die Datei heisst XEInstall.rsp und wird im Zip File mitgeliefert.
    Die Datei könnte dann z.B so editiert werden:

    #c:\temp\OracleXE184_Win64\setup.exe /s /v"RSP_FILE=c:\temp\OracleXE184_Win64\XEInstall.rsp" /v"/L*v c:\temp\OracleXE184_Win64\setup.log" /v"/qn"
    #Do not leave any parameter with empty value
    #Install Directory location, username can be replaced with current user
    INSTALLDIR=C:\oracle\product\18.0.0\
    #Database password, All users are set with this password, Remove the value once installation is complete
    PASSWORD=sys2019#
    #If listener port is set to 0, available port will be allocated starting from 1521 automatically
    LISTENER_PORT=0
    #If EM express port is set to 0, available port will be used starting from 5550 automatically
    EMEXPRESS_PORT=0
    #Specify char set of the database
    CHAR_SET=AL32UTF8

    Der Aufruf lautet dann in einem DOS-Fenster (mit Administrationsrechten)

    SET ORA_INSTALL_TMP=c:\temp\OracleXE184_Win64

    %ORA_INSTALL_TMP%\setup.exe /s /v"RSP_FILE=%ORA_INSTALL_TMP%\XEInstall.rsp" /v"/L*v %ORA_INSTALL_TMP%\setup.log" /v"/qn"

    Achtung Sie bekommen den Prompt sofort zurück und man denkt die Installation hat nicht geklappt. Jedoch können Sie im Logfile den Installations Fortschritt der Oracle XE 18c Datenbank schön beobachten:-)

    In einer der letzten Zeilen im Logfile sieht man dann den Aufruf des DBCA :

    INFO: cmd.exe /c "c:\oracle\product\18.0.0\dbhomeXE\bin\dbca.bat -silent -createDatabase -gdbName XE -templateName XE_Database.dbc -characterSet AL32UTF8 -createAsContainerDatabase true -numberOfPDBs 1 -pdbName XEPDB1 -sid XE -emConfiguration DBEXPRESS -emExpressPort 5500 -sampleSchema true -initParams sga_target=1536M,pga_aggregate_target=512M -customScripts c:\oracle\product\18.0.0\dbhomeXE\assistants\dbca\postdb_creation.sql -oui_internal -maskPasswords FALSE"

    Die Vorlagen-Datei XE_DB_Muso.dbc sieht dabei so aus:

    <?xml version = '1.0'?>
    <DatabaseTemplate name="XE DB Muniqsoft 2020" description=" " version="18.0.0.0.0">
       <CommonAttributes>
          <option name="OMS" value="true" includeInPDBs="true"/>
          <option name="JSERVER" value="true" includeInPDBs="true"/>
          <option name="SPATIAL" value="false" includeInPDBs="true"/>
          <option name="IMEDIA" value="false" includeInPDBs="true"/>
          <option name="ORACLE_TEXT" value="true" includeInPDBs="true">
             <tablespace id="SYSAUX"/>
          </option>
          <option name="SAMPLE_SCHEMA" value="false" includeInPDBs="false"/>
          <option name="CWMLITE" value="true" includeInPDBs="true">
             <tablespace id="SYSAUX"/>
          </option>
          <option name="APEX" value="false" includeInPDBs="false"/>
          <option name="DV" value="true" includeInPDBs="true"/>
          <option name="NET_EXTENSIONS" value="true" includeInPDBs="true"/>
       </CommonAttributes>
       <Variables/>
       <CustomScripts Execute="false"/>
       <InitParamAttributes>
          <InitParams>
             <initParam name="db_name" value="xe"/>
             <initParam name="dispatchers" value="(PROTOCOL=TCP) (SERVICE={SID}XDB)"/>
             <initParam name="audit_file_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\adump"/>
             <initParam name="compatible" value="18.0.0"/>
             <initParam name="remote_login_passwordfile" value="EXCLUSIVE"/>
             <initParam name="undo_tablespace" value="UNDOTBS1"/>
             <initParam name="control_files" value="(&quot;{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\control01.ctl&quot;, &quot;{ORACLE_BASE}\fast_recovery_area\{DB_UNIQUE_NAME}\control02.ctl&quot;)"/>
             <initParam name="diagnostic_dest" value="{ORACLE_BASE}"/>
             <initParam name="audit_trail" value="db"/>
             <initParam name="db_block_size" value="8" unit="KB"/>
             <initParam name="open_cursors" value="600"/>
          </InitParams>
          <MiscParams>
             <databaseType>MULTIPURPOSE</databaseType>
             <maxUserConn>20</maxUserConn>
             <percentageMemTOSGA>40</percentageMemTOSGA>
             <customSGA>true</customSGA>
             <dataVaultEnabled>false</dataVaultEnabled>
             <archiveLogMode>true</archiveLogMode>
             <initParamFileName>{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\pfile\init.ora</initParamFileName>
          </MiscParams>
          <SPfile useSPFile="true">{ORACLE_HOME}\database\spfile{SID}.ora</SPfile>
       </InitParamAttributes>
       <StorageAttributes>
          <DataFiles>
             <Location>{ORACLE_HOME}\assistants\dbca\templates\XE_Seed_Database.dfb</Location>
             <SourceDBName cdb="false">xe</SourceDBName>
             <Name id="3" Tablespace="SYSAUX" Contents="PERMANENT" Size="400" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_SYSAUX01.DBF</Name>
             <Name id="1" Tablespace="SYSTEM" Contents="PERMANENT" Size="820" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_SYSTEM01.DBF</Name>
             <Name id="4" Tablespace="UNDOTBS1" Contents="UNDO" Size="25" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_UNDOTBS01.DBF</Name>
             <Name id="7" Tablespace="USERS" Contents="PERMANENT" Size="5" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_USERS01.DBF</Name>
          </DataFiles>
          <TempFiles>
             <Name id="1" Tablespace="TEMP" Contents="TEMPORARY" Size="20" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\TEMP01.DBF</Name>
          </TempFiles>
          <ControlfileAttributes id="Controlfile">
             <maxDatafiles>100</maxDatafiles>
             <maxLogfiles>16</maxLogfiles>
             <maxLogMembers>3</maxLogMembers>
             <maxLogHistory>1</maxLogHistory>
             <maxInstances>8</maxInstances>
             <image name="control01.ctl" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
             <image name="control02.ctl" filepath="{ORACLE_BASE}\fast_recovery_area\{DB_UNIQUE_NAME}\"/>
          </ControlfileAttributes>
          <RedoLogGroupAttributes id="1">
             <reuse>false</reuse>
             <fileSize unit="MB">256</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="xe_redo01.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
          </RedoLogGroupAttributes>
          <RedoLogGroupAttributes id="2">
             <reuse>false</reuse>
             <fileSize unit="MB">256</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="xe_redo02.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
          </RedoLogGroupAttributes>
          <RedoLogGroupAttributes id="3">
             <reuse>false</reuse>
             <fileSize unit="MB">256</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="xe_redo03.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/>
          </RedoLogGroupAttributes>
       </StorageAttributes>
    </DatabaseTemplate>

     

    2. nun startet man den DBCA als Administrator! und löscht die installierte Datenbank Version XE
    a, "Datenbank löschen"
    b, Kennwort für SYS eintragen und "Weiter"
    c, "Weiter"
    d, "Fertig stellen"
    e, "Ja"
    3. Danach kann man die XE Version erneut installieren (als NON CDB)
    Update vom 12.6.2019. Seit neuestem, wird nur noch ein CDB Template mit ausgeliefert. Wir konnten durch kopieren des Templates in den Template Ordner weiterhin
    eine NON CDB Datenbank erstellen.
    a, "Datenbank erstellen"
    b, Globaler Datenbankname: XE
    [ ] Als Containerdatenbank erstellen ABWÄHLEN.
    Beachten Sie aber, dass die Speichergrößen von PGA und SGA 2 GB nicht übersteigen dürfen. Der Installer prüft das nicht und fällt erst bei 70% der Installation auf die Nase und man kann von vorne beginnen. Deswegen nehmen wir die "Erweiterte Konfiguration" "Weiter"
    c, Weiter
    d, Globaler Datenbankname: XE.<ihre-Domain>
    SID: XE
    e, Weiter
    f, Fast Recovery Area Größe nach eigenen Wünschen anpassen (Min 8GB)
    [x] Archivierung aktivieren
    g, Listenerauswahl Weiter
    h, Database Vault und Label Security nicht anwählen => Weiter
    i, SGA 1500MB, PGA 500MB, Prozesse auf 200 setzen
    j, EM "Weiter"
    k, Passwörter eintragen und Weiter
    l, Datenbank erstellen und/oder ein Skript zur Erstellung erzeugen. "Fertigstellen"

    Hier wäre unsere Vorlage, das ganze ein Template einzuspielen:

    <?xml version = '1.0'?>
    <DatabaseTemplate name="XE 18C NONCDB" description="XE 18c ohne Container Datenbank" version="18.0.0.0.0">
       <CommonAttributes>
          <option name="OMS" value="true" includeInPDBs="true"/>
          <option name="JSERVER" value="true" includeInPDBs="true"/>
          <option name="SPATIAL" value="true" includeInPDBs="true"/>
          <option name="IMEDIA" value="true" includeInPDBs="true"/>
          <option name="ORACLE_TEXT" value="true" includeInPDBs="true">
             <tablespace id="SYSAUX"/>
          </option>
          <option name="SAMPLE_SCHEMA" value="false" includeInPDBs="false"/>
          <option name="CWMLITE" value="true" includeInPDBs="true">
             <tablespace id="SYSAUX"/>
          </option>
          <option name="APEX" value="false" includeInPDBs="false"/>
          <option name="DV" value="true" includeInPDBs="true"/>
          <option name="NET_EXTENSIONS" value="true" includeInPDBs="true"/>
       </CommonAttributes>
       <Variables/>
       <CustomScripts Execute="false"/>
       <InitParamAttributes>
          <InitParams>
             <initParam name="db_name" value="xe"/>
             <initParam name="db_domain" value="ad.muniqsoft-training.de"/>
             <initParam name="dispatchers" value="(PROTOCOL=TCP) (SERVICE=xeXDB)"/>
             <initParam name="audit_file_dest" value="c:\oracle\product\18.0.0\admin\xe\adump"/>
             <initParam name="compatible" value="18.0.0"/>
             <initParam name="remote_login_passwordfile" value="EXCLUSIVE"/>
             <initParam name="sga_target" value="1500" unit="MB"/>
             <initParam name="processes" value="640"/>
             <initParam name="local_listener" value="LISTENER_XE"/>
             <initParam name="undo_tablespace" value="UNDOTBS1"/>
             <initParam name="control_files" value="(&quot;c:\oracle\product\18.0.0\oradata\XE\control01.ctl&quot;, &quot;c:\oracle\product\18.0.0\fast_recovery_area\XE\control02.ctl&quot;)"/>
             <initParam name="diagnostic_dest" value="c:\oracle\product\18.0.0"/>
             <initParam name="db_recovery_file_dest" value="c:\oracle\product\18.0.0\fast_recovery_area\XE"/>
             <initParam name="audit_trail" value="db"/>
             <initParam name="log_archive_format" value="%t_%s_%r.dbf"/>
             <initParam name="nls_territory" value="GERMANY"/>
             <initParam name="db_block_size" value="8192"/>
             <initParam name="open_cursors" value="300"/>
             <initParam name="nls_language" value="GERMAN"/>
             <initParam name="db_recovery_file_dest_size" value="8576" unit="MB"/>
             <initParam name="pga_aggregate_target" value="500" unit="MB"/>
          </InitParams>
          <MiscParams>
             <databaseType>MULTIPURPOSE</databaseType>
             <maxUserConn>20</maxUserConn>
             <percentageMemTOSGA>40</percentageMemTOSGA>
             <customSGA>false</customSGA>
             <dataVaultEnabled>false</dataVaultEnabled>
             <characterSet>AL32UTF8</characterSet>
             <nationalCharacterSet>AL16UTF16</nationalCharacterSet>
             <archiveLogMode>true</archiveLogMode>
             <initParamFileName>{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\pfile\init.ora</initParamFileName>
          </MiscParams>
          <SPfile useSPFile="true">{ORACLE_HOME}\database\spfile{SID}.ora</SPfile>
       </InitParamAttributes>
       <StorageAttributes>
          <DataFiles>
             <Location>{ORACLE_HOME}\assistants\dbca\templates\XE_Seed_Database.dfb</Location>
             <SourceDBName cdb="true">xe</SourceDBName>
             <Name id="3" Tablespace="SYSAUX" Contents="PERMANENT" Size="400" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\SYSAUX01.DBF</Name>
             <Name id="1" Tablespace="SYSTEM" Contents="PERMANENT" Size="820" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\SYSTEM01.DBF</Name>
             <Name id="4" Tablespace="UNDOTBS1" Contents="UNDO" Size="25" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\UNDOTBS01.DBF</Name>
             <Name id="7" Tablespace="USERS" Contents="PERMANENT" Size="5" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\USERS01.DBF</Name>
          </DataFiles>
          <TempFiles>
             <Name id="1" Tablespace="TEMP" Contents="TEMPORARY" Size="20" con_id="1">c:\oracle\product\18.0.0\oradata\XE\TEMP01.DBF</Name>
          </TempFiles>
          <ControlfileAttributes id="Controlfile">
             <maxDatafiles>100</maxDatafiles>
             <maxLogfiles>16</maxLogfiles>
             <maxLogMembers>3</maxLogMembers>
             <maxLogHistory>1</maxLogHistory>
             <maxInstances>8</maxInstances>
             <image name="control01.ctl" filepath="c:\oracle\product\18.0.0\oradata\XE\"/>
             <image name="control02.ctl" filepath="c:\oracle\product\18.0.0\fast_recovery_area\XE\"/>
          </ControlfileAttributes>
          <RedoLogGroupAttributes id="1">
             <reuse>false</reuse>
             <fileSize unit="KB">204800</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="redo01.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/>
          </RedoLogGroupAttributes>
          <RedoLogGroupAttributes id="2">
             <reuse>false</reuse>
             <fileSize unit="KB">204800</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="redo02.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/>
          </RedoLogGroupAttributes>
          <RedoLogGroupAttributes id="3">
             <reuse>false</reuse>
             <fileSize unit="KB">204800</fileSize>
             <Thread>1</Thread>
             <member ordinal="0" memberName="redo03.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/>
          </RedoLogGroupAttributes>
       </StorageAttributes>
    </DatabaseTemplate>

     

    Geschafft !

    Jetzt schauen wir mal, welche Version installiert wurde :-) ?

    select comp_name,version_full,status from dba_registry;

    COMP_NAMEVERSION_FULLSTATUS
    Oracle Database Catalog Views18.4.0.0.0VALID
    Oracle Database Packages and Types18.4.0.0.0VALID
    Oracle Real Application Clusters18.4.0.0.0OPTION OFF
    JServer JAVA Virtual Machine18.4.0.0.0VALID
    Oracle XDK18.4.0.0.0VALID
    Oracle Database Java Packages18.4.0.0.0VA


    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Hackerangriffe in APEX

    Bereich:APEX, Version: ab APEX 5, Letzte Überarbeitung: 20.04.2020

    Keywords:APEX Hackerangriffe

    Wenn man seine APEX Anwendung am ersten Tag im Internet frei verfügbar macht, wird man sich gleich über den großen Traffic auf dem Server freuen.
    Nur, wenn man nachdenkt, fällt einem beim Betrachten der Logfiles schnell auf, dass die meisten Zugriffe Hackerangriffe sind.
    Hier ein paar Auszüge aus unserem Apache Log-File

    (1)
    POST /wordpress/xmlrpc.php
    POST /wp/xmlrpc.php
    /blog/xmlrpc.php

    /?XDEBUG_SESSION_START=phpstorm
    /wp-login.php
    /index.php?s=/Index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=Hello
    /phpMyAdmin/scripts/setup.php

    (2)
    /oracle/f?p=SCHULUNG:1001::Oracle_ORDS_Installation_f%C3%BCr_APEX:::P1001_TIPPAUSWAHL:563'\"
    /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%27%20AnD%20sLeep%283%29%20ANd%20%271  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%27%26%26sLEEp%283%29%26%26%271  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%00%27%7C%7CSLeeP%283%29%26%26%271  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%27%20aND%20BeNChMaRK%282999999%2CMd5%28NoW%28%29%29%29%20AnD%20%271  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%27%26%26BeNChMaRK%282999999%2CmD5%28NOW%28%29%29%29%26%26%271  400
    /ords/f?p=SCHULUNG%3A1001%3A%3AOracle_ORDS_Installation_f%C3%BCr_APEX%3A%3A%3AP1001_TIPPAUSWAHL%3A563%27%20AnD%20sLeep%283%29%20ANd%20%270%27%3D%270  400
    /ords/f?p=SCHULUNG:1001::Oracle_ORDS_Installation_f%C3%BCr_APEX:::P1001_TIPPAUSWAHL:563%20and%201%3D1
    /ords/f?p=SCHULUNG:1001::Dynamic_Actions_f%C3%BCr_Reportspalten:::P1001_TIPPAUSWAHL:256999999.1 union
    /ords/f?p=SCHULUNG%3A61%3A17151203403405%3A%3ANO%3A%3A%3A
    /ords/f?p=11000%3A30%3A8476665195031

    (3)
    /ords/f?p=SCHULUNG:1001::Oracle_ORDS_Installation_f%C3%BCr_APEX:::P1001_TIPPAUSWAHL:563%22%20or%20(1,2)=(select*from(select%20name_const(CHAR(111,108,111,108,111,115,104,101,114),1),name_const(CHAR(111,108,111,108,111,115,104,101,114),1))a)%20--%20%22x%22=%22x HTTP/1.1" 301 493 "-" "-"

    (4)
    /arx/license.txt
    CONNECT ip.ws.126.net:443


    Schmunzeln mussten wir schon, wie 90% der Angriffe ablaufen. Ein großer Teil sind versucht php Attacken (1), die bei einer reinen APEX-Installation ins Leere laufen.

    Die Angriffsgruppe (2) versucht mit SQL-Injection einen Fuß in die (Datenbank-) Türe zu bekommen.

    Beim Angriff (3) waren wir auch verwundert, was die Funktion name_const denn bei Oracle macht. Relativ schnell stellte sich heraus, das ist gar keine Oracle Funktion, sondern gehört zu einer MySQL Datenbank und läuft damit ins leere... :-)

    Da sich die Angriffe sehr oft wiederholen (von anderen IP Adressen) gehen wir davon aus, dass es fertige Hacker-Kits gibt, die hier zum Einsatz kommen.

    So was können wir tun gegen diese Angriffe?
    1. Seine Hausaufgaben machen und alle Variablen/Items immer lieber einaml zu oft prüfen auf Länge, Datentyp und Logic.
    2. Prüfsummen in der URL aktivieren
    3. Apache/Nginx Logfiles regelmäßig auswerten
    4. Apache mod_security installieren
    5. Unseren APEX Security Kurs besuchen. Wir haben ihn um die Kapitel Apache und Nginx Security erweitert

    Wir haben uns noch eine weitere Abwehrroutine überlegt, ein Shell Script mit Namen blockip.
    Es hat die Aufruf-Parameter:

    blockip <ip> [-h -d -l -apache -nginx]
    -s <ip> [hours] Set IP on Blocked List [for x hours]
    -d <ip>|[all]     Drop [all] Blocked IP
    -l                Which IP are blocked
    -l -history       Which IP were blocked last
    -l -apache        Which IP would Blocked from Apache
    -l -nginx         Which IP would Blocked from nginx
    -apache           Block all Apache hacking IPs for 2 hours
    -apache -auto     Look for last 50 new Entries in Log (only Crontab)
    -nginx   Block all Nginx hacking IPs for 2 hours
    <ip> in aaa.bbb.ccc.ddd for example 185.172.4.126


    Es kann IP-Adressen blocken/entblocken manuell oder autmatisch, wenn es im Apache Logfile verdächtige Aktionen bemerkt. Bei uns läuft es via Crontab regelmäßig und sperrt die Hacker für 1 -x Stunden aus.
    Alle unsere APEX Schulungteilnehmer erhalten das Shell-Script von uns kostenlos auf Anfrage.

     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Oracle APEX Kalender Region mit Jahresauswahl

    Bereich:APEX, Version: ab APEX 19.2, Letzte Überarbeitung: 22.06.2022

    Keywords:Oracle Apex Calender Jahresauswahl nextyear prevyear

    Wollten Sie auch schon mal in einer APEX Kalender Region auch das Jahr und den Monat auswählen,
    und nicht mit dem Vor und Zurück Buttons 68 Monate wechseln?

    Hier werden Sie geholfen :-)

    Wir legen uns zwei Select List Items, eines für den Monat (:P1_MONAT) eines für die Jahresauswahl (:P1_JAHR)

    :P1_MONAT SQL Query

    select
    rownum d,
    to_char(to_number(rownum),'09') r -- Zahl muss zweistellig sein also z.B 09 !
    from dual
    connect by level<=12


    :P1_JAHR Query für aktuelles Jahr und die letzen 5 Jahre

    select
    to_char(sysdate +365 - 365*rownum,'YYYY') d,
    to_char(sysdate +365 - 365*rownum,'YYYY') r
    from dual
    connect by level<=6



    Unter Kalender Attribute:
    Calender Views: [ ] Navigation abwählen
    Das ist kein Muss, aber die Benutzer könnten mit den Vor und Zurück Buttons auch Navigieren und dann müsste man auch die Anzeige der beiden Select Listen aktualisieren!


    Unter Advanced / JavaScript Initialization Code

    function ( pOptions) {
        pOptions.titleFormat      = "[ Mein Kalender ]";                 
        pOptions.weekNumbers      = true;  
        pOptions.weekNumberCalculation = "ISO";                                   
        pOptions.weekNumberTitle  = "KW";    
        pOptions.defaultDate      = $v("P1_JAHR") + "-" + $v("P1_MONAT").trim() + "-01";    // bis APEX 21.1
        pOptions.initialDate      = $v("P1_JAHR") + "-" + $v("P1_MONAT").trim() + "-01";    // ab APEX 21.2  
        pOptions.dayNamesShort         = ["Sonntag", 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];              
        return pOptions;
    }


     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Postgres utl_file zum Lesen und Schreiben von Dateien

    Bereich:Postgres, Version: ab PG 13, Letzte Überarbeitung: 17.06.2021

    Keywords:Postgres PG/SQL Schreibprozedur

    In Vorbereitung für unseren neuen zweitägigen Kurs Oracle auf Postgres Migration, den wir ab Juli 2021 anbieten werden, ist mir aufgefallen, dass es weltweit wenige Beispiele zu Postgres utl_file Implementierung gibt.
    Zeit, das jetzt und hier nachzuholen ...:-)

    Vorbereitungen:
    Das "Package" (Postgres hat eigentlich gar keine Packages) utl_file ist leider nicht im Standardumfang einer Postgres Installation enthalten, man benötigt dazu die Extension ORAFCE,
    für das bereits viele Installationsanleitungen und eine gute Doku gibt.
    Nachdem also erfolgreich der nachfolgende Befehl (nach der Installation aller notwendigen Packages in Linux) in psql oder pgadmin ausgeführt wurde, können wir loslegen...
     

    CREATE EXTENSOPN ORAFCE


    Wir brauchen ein Verzeichnis mit dem wir arbeiten möchten. In unserem Beispiel verwenden wir das Verzeichnis /tmp. Dieses Arbeits-Verzeichnis tragen wir in eine Tabelle ein:
    Hinweis: Postgres hat keinen Directory Typ

    INSERT INTO utl_file.utl_file_dir values ('/tmp','tmp');


    Einfaches Beispiel (eine Zeile wird geschrieben):

    CREATE OR REPLACE PROCEDURE write_file(
    mydir     TEXT DEFAULT '/tmp',
    outfile   TEXT DEFAULT 'outfile.txt') AS $$
    DECLARE
    otf UTL_FILE.FILE_TYPE;
    BEGIN
    otf := UTL_FILE.FOPEN(mydir, outfile,'w');
    PERFORM UTL_FILE.PUT_LINE(otf,'Test:'||now(),TRUE);
    otf := UTL_FILE.FCLOSE(otf);
    END; $$ LANGUAGE plpgsql;

     

    call write_file('/tmp','x.x');
    \! cat /tmp/x.x


    Tabelle in Datei schreiben

    CREATE OR REPLACE PROCEDURE write_tab(
    mydir     TEXT DEFAULT '/tmp',
    outfile TEXT DEFAULT 'file.txt') AS $$
    DECLARE
    f UTL_FILE.FILE_TYPE;
    emp_curs CURSOR IS SELECT * FROM scott.emp;
    tz VARCHAR2(10):=';';
    BEGIN
    f := UTL_FILE.FOPEN(mydir, outfile,'w');
    FOR c IN emp_curs LOOP
    PERFORM UTL_FILE.PUT_LINE(f,
    c.empno||tz||c.ename||tz||c.job||tz||c.hiredate||tz||c.sal||tz||coalesce(c.comm::varchar2,'')||tz||c.deptno,TRUE);
    END LOOP;
    f := UTL_FILE.FCLOSE(f);
    END; $$ LANGUAGE plpgsql;

     

    call write_tab('/tmp','emp.txt');
    \! cat /tmp/emp.txt



    Daten aus Datei lesen

    CREATE OR REPLACE PROCEDURE read_file(
    mydir     TEXT DEFAULT '/tmp',
    infile TEXT DEFAULT 'file.txt') AS $$
    DECLARE
    f         UTL_FILE.FILE_TYPE;
    v_text     VARCHAR(32767);
    BEGIN
    f := UTL_FILE.FOPEN(mydir, infile,'r');

    LOOP
    BEGIN
        v_text := UTL_FILE.GET_LINE(f,256);
        RAISE NOTICE '%',v_text;
    EXCEPTION WHEN no_data_found THEN
        EXIT;
    END;
    END LOOP;
    f := UTL_FILE.FCLOSE(f);
    END; $$ LANGUAGE plpgsql;

     

    call read_file('/tmp','emp.txt');


     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Installation von Oracle 21c

    Bereich:DBA, Version: ab RDBMS 21.1, Letzte Überarbeitung: 01.09.2021

    Keywords:Oracle, Datenbank, 21c

    Seit August 2021 ist nun Oracle 21c verfügbar. Im folgenden möchten wir kurz die Installation erläutern.
    Durchgeführt wird das ganze auf einem Oracle Linux 8.4 Server.
    Zuerst aktualisieren wir die Paketquellen:

    yum update -y && yum upgrade -y


    Danach sollte geprüft werden ob der Server einen gültigen FQDN Eintrag in der Hosts File (/etc/hosts) besitzt
     

    <IP-address>  <fully-qualified-machine-name>  <machine-name>


    Als Beispiel der Eintrag auf unserem Server
     

    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    172.30.30.170 oracle-21c oracle-21c.prod.muniqsoft-training.de


    Natürlich muss auch der korrekte Hostname in der Datei /etc/hostnames gesetzt sein.

    oracle-21c.prod.muniqsoft-training.local


    Der nächste wichtige Schritt wäre das Ändern von SELinux Flags auf permissive. Ändern Sie also unter /etc/selinux/config
    folgendes ab:
     

    SELINUX=enforcing


    auf
     

    SELINUX=permssive


    Jetzt starten Sie entweder den Server neu oder setzen es mittels 
     

    setenforce Permissive


    für den Livebetrieb auf Permissive.

    Nachdem dies erfolgreich abgeschlossen wurde, installieren wir folgendes Package:

    mittels dnf:

    dnf install oracle-database-preinstall-21c


    oder mittels yum:

    yum install oracle-database-preinstall-21c


    Dies installiert für uns alle Packages die für eine reibungslose Installation einer Oracle 21c Datenbank benötigt werden.

    Nachdem wir das Package erfolgreich installiert haben, müssen wir nun das RPM File
    für die Datenbank noch auf den Server herunterladen oder kopieren.
    Das geht einfach über die Oracle Download Seite.

    Dort findet man unter Oracle Database 21c, den Punkt "RPM".

    Wenn man die Datei auf den Server kopiert bzw. heruntergeladen hat, muss man sie
    eigentlich nur noch mit dem Paketmanager seiner Wahl installieren.

    Dazu führen Sie folgenden Befehl aus:

    yum -y localinstall oracle-database-ee-21-*.rpm


    Der letzte Schritt ist das konfigurieren der Datenbank

    Dazu rufen Sie folgendes Skript auf:

    /etc/init.d/oracledb_ORCLCDB-21c configure


    Nun ist die Datenbank fertig installiert.

    Man sollte nun noch eine .bash_profile mit folgendem Inhalt für den Nutzer oracle anlegen:

    export TERM=vt220
    export EDITOR=vi
    export PS1="[\u@\h:\w]>"

    export DISPLAY=:0.0
    export ORACLE_BASE=/opt/oracle
    export ORACLE_HOME=$ORACLE_BASE/product/21c/dbhome_1
    export ORACLE_SID=ORCLCDB
    export ORACLE_TERM=vt220
    export ORA_NLS10=$ORACLE_HOME/nls/data
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib
    export NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252
    export PATH=$ORACLE_HOME/bin:$PATH:/usr/sbin:/usr/ccs/bin

    alias cdo="cd $ORACLE_HOME; pwd"
    alias cdd="cd $ORACLE_BASE/oradata"
    alias cda="cd $ORACLE_BASE/diag/rdbms/$ORACLE_SID/$ORACLE_SID/trace; pwd"
    alias cdn="cd $ORACLE_HOME/network/admin; pwd"
    alias cde="cd $ORACLE_BASE/admin/$ORACLE_SID/dpdump"
    alias sp="$ORACLE_HOME/bin/sqlplus '/ as sysdba'"
    alias l="ls -l"
    alias ll="ls -la"
    alias ipconfig="/sbin/ifconfig | grep Bcast"
    echo Folgende Einstellungen wurden gesetzt:
    env | grep ORA


    Wenn man sich nun erneut mit dem Oracle Nutzer anmeldet oder mittels

    source ~/.bash_profile

    die Datei neu lädt kann man sich auch mit dem Befehl "sqlplus / as sysdba" direkt an der Datenbank anmelden.



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Flashback Funktionen in Postgres

    Bereich:Postgres, Version: ab PG 13, Letzte Überarbeitung: 02.08.2021

    Keywords:Postgres, Flashback

    Leider hat Postgres keine eingebaute Flashback Funktion. Für Flashback Database könnte man sich als Alternative ein Komplettbackup der DB erstellen (z.B. mittels pg_basebackup)
    Im Fehlerfall würde man dann mit einem zeitbasierten Recovery wieder auf den gewünschten Zeitpunkt zuückstellen.

    Wir möchten uns heute jedoch eine Alternative für Flashback Transaktion mittels eines Update und Delete Trigger basteln:


    Beispieltabelle erstellen:

    CREATE TABLE scott.emp (
        empno     numeric CONSTRAINT PK_EMP PRIMARY KEY,
        ename     character varying(10),
        job     character varying(9),
        mgr     numeric,
        hiredate date,
        sal     numeric(7,2),
        comm     numeric(7,2),
        deptno     numeric(2,0));

    INSERT INTO scott.emp VALUES(7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20);
    INSERT INTO scott.emp VALUES(7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30);
    INSERT INTO scott.emp VALUES(7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30);
    INSERT INTO scott.emp VALUES(7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20);
    INSERT INTO scott.emp VALUES(7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30);
    INSERT INTO scott.emp VALUES(7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30);
    INSERT INTO scott.emp VALUES(7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10);
    INSERT INTO scott.emp VALUES(7788,'SCOTT','ANALYST',7566,to_date('13-6-1987','dd-mm-yyyy'),3000,NULL,20);
    INSERT INTO scott.emp VALUES(7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10);
    INSERT INTO scott.emp VALUES(7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30);
    INSERT INTO scott.emp VALUES(7876,'ADAMS','CLERK',7788,to_date('13-6-1987','dd-mm-yyyy'),1100,NULL,20);
    INSERT INTO scott.emp VALUES(7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30);
    INSERT INTO scott.emp VALUES(7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20);
    INSERT INTO scott.emp VALUES(7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10);
    CREATE TABLE scott.emp_flashback AS SELECT * FROM scott.emp
    WHERE 1=2;


    Für die Flashbacktabelle werden drei weitere Spalten hinzugefügt

    ALTER TABLE scott.emp_flashback
    ADD column xid INT,
    ADD column zeit TIMESTAMP,
    ADD column aktion char(1);


    Ein Trigger in Postgres verwendet immer eine seperate Procedure oder Function:

    CREATE OR REPLACE PROCEDURE emp_trg_proc()
    AS $$ DECLARE
    dml_type CHAR(1);
    BEGIN
    CASE TG_OP          
       WHEN 'UPDATE' THEN
          dml_type:='U';
       ELSE
          dml_type:='D';
       END CASE;
    INSERT INTO scott.emp_flashback(empno,ename,job,mgr,hiredate,sal,comm,deptno,xid,zeit,aktion)
    VALUES (old.empno,old.ename,old.job,old.mgr,old.hiredate,old.sal,old.comm,old.deptno,txid_current(),now(),dml_type);
    END $$ LANGUAGE plpgsql;


    Nun wird der Trigger erstellt:

    CREATE TRIGGER emp_trg
    AFTER UPDATE OR DELETE
    ON scott.emp
    FOR EACH ROW
    EXECUTE PROCEDURE emp_trg_proc();


    Hinweis: Wenn Sie einen Trigger wieder löschen möchten, verwendet man folgende Syntax:

    DROP TRIGGER emp_trg ON scott.emp;


    Beispieltransaktion:

    update scott.emp set sal=sal+1 where deptno=10;


    Prüfen der Flashback-Tabelle:

    select empno,sal,zeit from scott.emp_flashback;


    Jetzt kommt der spannende Teil: Welchen Wert hatt eine Gehalt zu einem bestimmten Zeitpunkt in der Vergangenheit mittels unserer selbst gebauten Flashback Funktion:

    with flash as (select '2021-08-02 08:30:00'::timestamp as back)
    select empno,sal from scott.emp_flashback
    where zeit=(select max(zeit) from flash,scott.emp_flashback where zeit<flash.back)
    UNION ALL
    select empno,sal from scott.emp
    where empno not in (select empno from scott.emp_flashback
    where zeit=(select max(zeit) from flash,scott.emp_flashback where zeit<flash.back));


    Wenn Sie die Flashback Funktion für Ihre Umgebung nachbauen möchten, müssen Sie hier den Primärschlüssel empno durch Ihren Primärschlüssel austauschen.
    Weitere tolle Tipps erhalten Sie in einem von unseren Postgres Kursen.
     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Oracle APEX 21.2 in Oracle 21c Pluggable Database installieren

    Bereich:APEX:DBA, Version: ab APEX 21.2:RDBMS 21.1, Letzte Überarbeitung: 08.02.2022

    Keywords:Oracle APEx Installation

    Ich habe mich ja lange Zeit geweigert, die Pluggable Database einzusetzen und wenn es nach mir ginge ....

    Trotzdem sollte man sich der Zukunft nicht verschliessen, denn es wird ab 21c (incl) keine NON CDB Datenbanken mehr geben.

    Installation einer Apex Version 21.2 in Oracle XE 21c (geht aber auch in einer Enterprise Edition oder Standard Edition):
    Gehen wir zuerst mal in den Hauptcontainer und schauen uns um

    ALTER SESSION SET CONTAINER=cdb$root;
    select con_id,name,open_mode from v$pdbs p;
    select name from v$datafile;


    Mich stört der Default Container, also löschen ich ihn und lege einen anderen an (ist natürlich optional, und wenn das schon eteas drinliegt, besser vorher migrieren...)

    ALTER PLUGGABLE DATABASE XEPDB1 CLOSE;
    DROP PLUGGABLE DATABASE XEPDB1 INCLUDING DATAFILES;


    Wo liegen denn die Datendateien ?

    select name from v$datafile;


    Diesen Hauptpfad tragen wir im nächsten Kommando ein (bei uns C:\Oracle\Product\Base21\oradata)

    CREATE PLUGGABLE DATABASE apex212 ADMIN USER admin IDENTIFIED BY admin
    CREATE_FILE_DEST= 'C:\Oracle\Product\Base21\oradata';


    Der Container wird geöffnet, automatisch beim Start der DB mitgestartet und wir gehen in den Container

    ALTER PLUGGABLE DATABASE apex212 OPEN;
    ALTER PLUGGABLE DATABASE apex212 SAVE STATE;
    ALTER SESSION SET container=apex212;


    Nun installieren wir in den neu erstellen Container unsere APEX Version.
    Das APEX Download haben wir unter c:\temp ausgepackt

    cd c:\temp\apex
    sqlplus sys/sys@127.0.0.1:1521/apex212 as sysdba
    @apexins SYSAUX SYSAUX TEMP /i212/
    @apex_rest_config;


    Wir entsperren das schema SCOTT und schalten die starke interne Passwort-Prüfung aus (optional) Der Vorteil ist, dass man sich die ganzen Passwort-Parameter wie gewünscht selbst einstellen kann.

    EXEC apex_instance_admin.unrestrict_schema('SCOTT');
    EXEC apex_instance_admin.set_parameter('STRONG_SITE_ADMIN_PASSWORD','N')


    Nun wird das Passwort für den Internal Workspace gesetzt (Sie werden gefragt nach:
    Admin-name:
    Admin-User Email:
    Admin-Passwort:

    @apxchpwd


    Und weil wir schon hundert Mal vergessen haben, nach spätestens 187 Tagen vom APEX Benutzer und seiner ganzen "Verwandschaft" zu ändern,
    erstellen wir ein eigenes Profil für die Truppe:-)
    Die Passwörter passen Sie bitte Ihren Wünschen an

    CREATE PROFILE web_profil LIMIT
    FAILED_LOGIN_ATTEMPTS 10
    PASSWORD_LIFE_TIME 1800;
    alter user apex_public_user profile web_profil account unlock identified by apex;
    alter user APEX_REST_PUBLIC_USER profile web_profil account unlock identified by apex;
    alter user ORDS_PUBLIC_USER profile web_profil account unlock identified by ords;
    alter user scott profile web_profil account unlock identified by ords;
    alter user APEX_LISTENER profile web_profil account unlock identified by apex;


    In einem der nächsten Artikel schauen wir uns die dazu passende ORDS Konfiguration an.
    Viel Spass bei der Benutzung von APEX und wenn Sie mal eine gute Schulung brauchen, denken Sie an uns ...*zwinker*

     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    JSON Daten extrahieren

    Bereich:APEX:PL/SQL, Version: ab RDBMS 18.3, Letzte Überarbeitung: 19.05.2022

    Keywords:JSON, Oracle

    In unserem heutigen Beitrag wollen wir uns mit dem Thema beschäftigen, wie man aus einem JSON String wieder die Daten extrahieren kann.
    Diesen Anwendungsfall hatte ich die letzten 24 Monat sehr häufig, deswegen wurde es mal wieder Zeit sich mit dem Thema JSON in Oracle zu beschäftigen.

    Wir fangen mit einer kleinen Test-Tabelle basiernd auf den Emp und Dept Daten des Benutzers SCOTT an:
    Die Besonderheit / Schwierigkeit besteht darin, dass die Mitarbeiter in einem Array eingetragen werden (["CLARK","KING","MILLER"]
     

    CREATE TABLE dept_json   
    ( json_text CLOB,   
        CONSTRAINT check_json CHECK ( json_text IS JSON ) );

    INSERT INTO dept_json   
    VALUES ('{ "DEPT" : {
                           "DEPTNO" : 10,
                           "DNAME" : "ACCOUNTING",   
                           "LOC" : "NEW YORK",  
                           "EMPS"  : ["CLARK","KING","MILLER"] }}');

    INSERT INTO dept_json   
    VALUES ('{"DEPT" : {
                           "DEPTNO" : 20,
                           "DNAME" : "RESEARCH",   
                           "LOC" : "DALLAS",  
                           "EMPS"  : ["SMITH","JONES","SCOTT","ADAMS","FORD"] }}');


    INSERT INTO dept_json   
    VALUES ('{"DEPT" : {
                           "DEPTNO" : 30,
                           "DNAME" : "SALES",   
                           "LOC" : "CHICAGO",  
                           "EMPS"  : ["ALLEN","BLAKE","JAMES","MARTIN","TURNER","WARD"] }}');


    Als Bonustrack legen wir einen Oracle Text-Index auf die JSON Spalte:


    CREATE INDEX dept_json_index   
      ON dept_json(json_text)   
      INDEXTYPE IS CTXSYS.CONTEXT   
      PARAMETERS ('SECTION GROUP CTXSYS.JSON_SECTION_GROUP SYNC (ON COMMIT)');


    Wir können dann mit der Funktion JSON_TEXTCONTAINS im JSON String suchen.

    SELECT json_text   
      FROM dept_json   
     WHERE JSON_TEXTCONTAINS(json_text, '$', 'KING');


    Das Ergebnis sieht dann so aus:


    { "DEPT" : {
                           "DEPTNO" : 10,
                           "DNAME" : "ACCOUNTING",   
                           "LOC" : "NEW YORK",  
                           "EMPS"  : ["CLARK","KING","MILLER"] }}


    Wenn man die Daten der JSON Tabelle wieder extrahieren (und weiterverarbeiten) möchte:


    SELECT deptno, dname, loc, linenum, arrayval
    from dept_json,json_table(json_text, '$.DEPT[*]'
    columns ( arraynum for ordinality, DEPTNO,DNAME,LOC,
        nested path '$.EMPS[*]'
            columns ( linenum for ordinality,nested path '$[*]'
                     columns( arrayval varchar2 path '$')
      ) ));


    Das Ergebnis sieht dann so aus:
     

    DEPTNODNAMELOCLINENUMARRAYVAL
    10ACCOUNTINGNEW YORK1CLARK
    10ACCOUNTINGNEW YORK2KING
    10ACCOUNTINGNEW YORK3MILLER
    20RESEARCHDALLAS1SMITH
    20RESEARCHDALLAS2JONES
    20RESEARCHDALLAS3SCOTT
    20RESEARCHDALLAS4ADAMS
    20RESEARCHDALLAS5FORD
    30SALESCHICAGO1ALLEN
    30SALESCHICAGO2BLAKE
    30SALESCHICAGO3JAMES
    30SALESCHICAGO4MARTIN
    30SALESCHICAGO5TURNER
    30SALESCHICAGO6WARD


    Wenn man mal einen unbekannten JSON String auswerten möchte stellt Oracle dafür auch ein Package zur Verfügung:

    SELECT json_dataguide(json_text, DBMS_JSON.FORMAT_HIERARCHICAL, DBMS_JSON.PRETTY)
    FROM dept_json;


    Die Ausgabe sieht dann so aus:

    {
      "type" : "object",
      "o:length" : 128,
      "properties" :
      {
        "DEPT" :
        {
          "type" : "object",
          "o:length" : 128,
          "o:preferred_column_name" : "DEPT",
          "properties" :
          {
            "LOC" :
            {
              "type" : "string",
              "o:length" : 8,
              "o:preferred_column_name" : "LOC"
            },
            "EMPS" :
            {
              "type" : "array",
              "o:length" : 64,
              "o:preferred_column_name" : "EMPS",
              "items" :
              {
                "type" : "string",
                "o:length" : 8,
                "o:preferred_column_name" : "scalar_string"
              }
            },
            "DNAME" :
            {
              "type" : "string",
              "o:length" : 16,
              "o:preferred_column_name" : "DNAME"
            },
            "DEPTNO" :
            {
              "type" : "number",
              "o:length" : 2,
              "o:preferred_column_name" : "DEPTNO"
            }
          }
        }
      }

    }

    Und nun viel Spaß mit der Auswertung von Daten aus JSON-Ausdrücken. Bei uns wird das Thema ausführlich behandelt in den Kursen Oracle PL/SQL II, Oracle REST und Oracle Dev New Features 12c - 21c.



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    JSON Umwandlung in realtionales Format mit JSON_TABLE Beispiele

    Bereich:APEX:PL/SQL, Version: ab RDBMS 19.3, Letzte Überarbeitung: 22.07.2022

    Keywords:JSON, Array

    In vielen unserer Kurse ist JSON ein Thema (z.B. im APEX oder ORDS oder PL/SQL II Kurs). Da die Syntax gewöhnungsbedürftig ist, haben wir mal ein paar Beispiele generiert um die syntax besser zu verstehen.
    Ausgangslage ist ein JSON String, der in ein relationales Modell überführt werden soll.

    Übersicht der Beispiele:
    Beispiel 1, mit 3 Werte
    Beispiel 2, Verschiedene Datentypen in JSON
    Beispiel 3, mit Geschachtelten Arrays
    Beispiel 4, mit 3 Zeilen mit 2 Feldern
    Beispiel 5, mit 3 Zeilen mit 2 Feldern und einem Root Eintrag (var)
    Beispiel 6, mit 2 Feldern und 3 Zeilen
    Beispiel 7, mit Sub-Sub Feldern
    Beispiel 8, nur einen Wert extrahieren
    Beispiel 9, Wieviele Elemente hat das Array?
    Beispiel 10, Sub-Arrays (Darstellungsvariante 1)
    Beispiel 11, Sub-Arrays (Darstellungsvariante 2)   
    Beispiel 12, Tabelle die von Oracle mit Auto-Rest zurückkommt zerlegen
    Beispiel 13: JSON String gefiltert

    Beispiel 1, mit 3 Werte

    WITH j_son as (SELECT '
    {"a":1,
     "b":2,
     "c":3
    }' as txt from dual)
    SELECT a,b,c
    FROM j_son,  
         JSON_TABLE(j_son.txt, '$'
         COLUMNS ( a,b,c )
              ) jt;


    Ergebnis:
     

    ABC
       
    123



    Beispiel 2, Verschiedene Datentypen in JSON:

    WITH j_son as (SELECT '
    {"Zahl":1, "Text": "aBc", "Bool":TRUE,
    "Datum1":"2022-07-15", "Datum2":"2019-07-15T14:11:27",
    "Datum3":"2022-07-15T14:11:27Z", "Datum4":"2022-07-15T14:11:27+00:00"
    }' as txt from dual)
    SELECT Zahl,Text,Bool,Datum1,Datum2,Datum3,Datum4
    FROM j_son,  JSON_TABLE(j_son.txt, '$' COLUMNS (
           Zahl NUMBER PATH '$."Zahl"',
           Text VARCHAR2(2000) PATH '$."Text"',
           Bool VARCHAR2(10) PATH '$."Bool"',
           Datum1 DATE PATH '$."Datum1"',
           Datum2 DATE PATH '$."Datum2"',
           Datum3 DATE PATH '$."Datum3"',
           Datum4 DATE PATH '$."Datum4"'
              )
         ) jt;


    Ergebnis:

    ZahlTextBoolDatum1Datum2Datum3Datum4
           
    1aBctrue15.07.2022 00:00:0015.07.2022 00:00:0015.07.2022 00:00:0015.07.2022 00:00:00

    Hinweis: Die Stunden / Minuten / Sekunden verschwinden hier. Alternative: Datum als Text parsen und mittels to_date in Datum umwandeln.

    Beispiel 3, mit Geschachtelten Arrays

    WITH j_son as (SELECT '
    {"a":"a1",
     "b": [
            {"c": "c1",
             "d": [1,2]}
          ]
    }' as txt from dual)
    SELECT j_son.txt, "a","c","d"
    FROM j_son,  
         JSON_TABLE(j_son.txt, '$' COLUMNS (
           "a" VARCHAR2(5) PATH '$.a',
           NESTED PATH '$.b[*]' COLUMNS (
              "c" VARCHAR2(5) PATH '$.c',
              NESTED PATH '$.d[*]' COLUMNS (
                 "d" NUMBER PATH '$[0]'
              )
           )
         )) jt;

        
    Ergebnis:

    a1cd
       
    a1c11
    a1c12



    Beispiel 4, mit 3 Zeilen mit 2 Feldern

    WITH j_son as (SELECT '
    [{"A":1,"B":2},
    { "A":3,"B":4},
    { "A":5,"B":6}]' txt from dual)
    SELECT A,B
    FROM j_son,json_table(j_son.txt,'$[*]'
    columns (A,B));

     Ergebnis

    AB
    12
    34
    56



    Beispiel 5, mit 3 Zeilen mit 2 Feldern und einem Root Eintrag (var)

    WITH j_son as (select '
    {var:[{"A":1,"B":2},
    { "A":3,"B":4},
    { "A":5,"B":6}]}' txt from dual)
    select A,B
    FROM j_son,json_table(j_son.txt,'$.var[*]' columns (A,B));

      Ergebnis

    AB
    12
    34
    56



    Beispiel 6, mit 2 Feldern und 3 Zeilen

    WITH j_son as (select '[
    {"Vorname":"Marco","Nachname":"Patzwahl"},
    {"Vorname":"Hansi","Nachname":"Wurst"},
    {"Vorname":"Karin","Nachname":"Sorglos"}
    ]' txt from dual)
    select vorname,nachname
    FROM j_son,json_table(j_son.txt,'$[*]'
    columns (Vorname,Nachname));

      Ergebnis

    VornameNachname
      
    MarcoPatzwahl
    HansiWurst
    KarinSorglos



    Beispiel 7, mit Sub-Sub Feldern

    SELECT id, var1, sub_id, sub_val
    FROM JSON_TABLE (
            to_clob('{ id: 123, var1: "abc",
            subvalues : [
                { id: 1, value: "a", },
                { id: 2, value: "b" } ]} '),
            '$' COLUMNS (
                id NUMBER PATH '$.id',
                var1 VARCHAR PATH '$.var1',
                NESTED PATH '$.subvalues[*]'
                COLUMNS ( sub_id NUMBER PATH '$.id',
                sub_val VARCHAR2(4000) PATH '$.value'
                ) ) );


    oder

    WITH j_son as (select '{ id: 123, var1: "abc",
            subvalues : [
                { id: 1, value: "a", },
                { id: 2, value: "b" }
                ]}' as txt from dual)
    SELECT id, var1, sub_id, sub_val
    FROM j_son,JSON_TABLE (j_son.txt,
            '$' COLUMNS (
                id NUMBER PATH '$.id',
                var1 VARCHAR PATH '$.var1',
                NESTED PATH '$.subvalues[*]'
                COLUMNS ( sub_id NUMBER PATH '$.id',
                sub_val VARCHAR2(4000) PATH '$.value'
                ) ) );

      Ergebnis

    IDVar2SUB_IDSUB_VAL
    123abc1a
    123abc2b
        



    Beispiel 8, nur einen Wert extrahieren

    SELECT json_value ('{"emp":{ "name":"Marco","city":"Bern" } } ','$.emp.name') as name
    FROM dual;


    Beispiel 9, Wieviele Elemente hat das Array?

    SELECT json_value('[1, 2, 3, 4 ]','$.size()') FROM dual;

    =>4
    oder

    SELECT json_query('[1,[2,2,2],3]','$[*].size()' WITH ARRAY WRAPPER)  FROM dual;

    =>[1,3,1]

    Beispiel 10: Sub-Arrays (Darstellungsvariante 1)

    WITH j_son as (select '
    {var:[{"A":[1,2],"B":[3,4]},
    { "A":[5,6],"B":[7,8]},
    ]}' txt from dual)
    select A,B
    FROM j_son,json_table(j_son.txt,
    '$.var' columns (
        nested path '$.A[*]' columns (A number path '$[0]'),
        nested path '$.B[*]' columns (B number path '$[0]') ));

        
    Ergebnis:
     

    AB
      
    1 
    2 
     3
     4
    5 
    6 
     7
     8


       
    Beispiel 11: Sub-Arrays (Darstellungsvariante 2   

    WITH j_son as (select '
    {var:[{"A":[1,2],"B":[3,4]},
    { "A":[5,6],"B":[7,8]},
    ]}' txt from dual)
    select val
    FROM j_son,json_table(j_son.txt,
    '$.var' columns (
        nested path '$.*[*]' columns (val number path '$[0]' )));

        

    VAL
     
    1
    2
    3
    4
    5
    6
    7
    8


    Beispiel 12, Tabelle die von Oracle mit Auto-Rest zurückkommt zerlegen

    WITH j_son as (SELECT '
    {"items":[
    {"deptno":10,"dname":"ACCOUNTING","loc":"NEW YORK",
    "links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/10"}]},
    {"deptno":20,"dname":"RESEARCH","loc":"DALLAS",
    "links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/20"}]},
    {"deptno":30,"dname":"SALES","loc":"CHICAGO",
    "links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/30"}]},
    {"deptno":40,"dname":"OPERATIONS","loc":"BOSTON",
    "links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/40"}]}],
    "hasMore":false,"limit":25,"offset":0,"count":4,"links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/"},
    {"rel":"edit","href":"http://127.0.0.1:8080/ords/scott/dept/"},
    {"rel":"describedby","href":"http://127.0.0.1:8080/ords/scott/metadata-catalog/dept/"},
    {"rel":"first","href":"http://127.0.0.1:8080/ords/scott/dept/"}]}' as txt from dual)
    SELECT deptno,dname,loc,href
    FROM  
         j_son,JSON_TABLE(j_son.txt, '$.items[*]'
         COLUMNS ( deptno,dname,loc,
         nested path '$.links[*]' columns (href),
         limit,offset,count)
              ) jt;

    Ergebnis:

    DEPTNODNAMELOCHREF
        
    10ACCOUNTINGNEW YORKhttp://127.0.0.1:8080/ords/scott/dept/10
    20RESEARCHDALAShttp://127.0.0.1:8080/ords/scott/dept/20
    30SALESCHICAGOhttp://127.0.0.1:8080/ords/scott/dept/30
    40OPERATIONSBOSTONhttp://127.0.0.1:8080/ords/scott/dept/40

    oder ausführlicher (aber nur für eine Ergebnis-Zeile zur Vereinfachung):


    WITH j_son as (SELECT '
    {"items":[
    {"deptno":10,"dname":"ACCOUNTING","loc":"NEW YORK",
    "links":[{"rel":"self","href":"http://127.0.0.1:8080/ords/scott/dept/40"}]}],
    "hasMore":false,"limit":25,"offset":0,"count":4,"links":[{"rel":"self",
    "href":"http://127.0.0.1:8080/ords/scott/dept1/"},
    {"rel":"edit","href":"http://127.0.0.1:8080/ords/scott/dept2/"},
    {"rel":"describedby","href":"http://127.0.0.1:8080/ords/scott/metadata-catalog/dept/"},
    {"rel":"first","href":"http://127.0.0.1:8080/ords/scott/dept3/"}]}' as txt from dual)
    SELECT deptno,dname,loc,href,hasMore,offset,count,href2,href3
    FROM  j_son,
         JSON_TABLE(j_son.txt, '$.items[*]'
         COLUMNS ( deptno,dname,loc,
         nested path '$.links[*]' columns (href)) ),
         JSON_TABLE(j_son.txt, '$'
         COLUMNS ( hasMore,limit,offset,count,
         nested path '$.links[0]' columns (href2 varchar2 path '$.href')) ),
         JSON_TABLE(j_son.txt, '$'
         COLUMNS (
         nested path '$.links[1]' columns (href3 varchar2 path '$.href')) )jt;
    DEPTNODNAMELOCHREFHASMOREOFFSETCOUNTHREF2HFREF3
             
    40OPERATIONSBOSTONhttp://127.0.0.1:8080/ords/scott/dept/40false04http://127.0.0.1:8080/ords/scott/dept1/http://127.0.0.1:8080/ords/scott/dept2/

    Beispiel 13: JSON String gefiltert (finde die Werte für B, wenn a=4 , 7, 10 oder 13 ist)

    WITH j_son AS (
    select '{
      "items": [
        {
          "sub": [
            {
              "a": 1,
              "b": 2,
              "c": 3
            },
            {
       &nb

    ORDS 22.x Installation in Verbindung mit Oracle APEX

    Bereich:APEX:ORDS, Version: ab APEX 22.1:ORDS 22.2, Letzte Überarbeitung: 16.08.2024

    Keywords:ORDS 22.x APEX

    Seit Mai 2022 ist eine neue ORDS Version veröffentlicht worden, die eine andere Installation benötigt.
    Wir wollen hier die wichtigsten Punkte erklären:

    1. Es werden nur hoch die Java Versionen 11 und 17 unterstützt (und KEIN JAVA 8)
    Prüfen Sie bitte zuerst welche Java Version sie haben:
    Achtung: Bei uns machte auch die OpenJDK Version Probleme und endete mit einem Webserver Fehler 500 und Fehlertext NULL!

    Für Windows:

    java -version

    java -version
    java version "17.0.4.1" 2022-08-18 LTS
    Java(TM) SE Runtime Environment (build 17.0.4.1+1-LTS-2)
    Java HotSpot(TM) 64-Bit Server VM (build 17.0.4.1+1-LTS-2, mixed mode, sharing)
    => So is es gut :-)


    Installation unter Windows:

    ords.exe --config c:\oracle\ords install

    ORDS: Release 22.2 Produktion am Di. Sept. 06 09:49:12 2022

    Copyright (c) 2010, 2022, Oracle.

    Konfiguration:

      /C:/oracle/ords/

    Der Konfigurationsordner C:\oracle\ords enthält keine Konfigurationsdateien.

    Oracle REST Data Services - Interaktive Installation

      Geben Sie eine Zahl zur Auswahl des Installationstyps ein
        [1] ORDS nur in der Datenbank installieren oder upgraden
        [2] Datenbankpool erstellen oder aktualisieren und ORDS in der Datenbank installieren/upgraden
        [3] Nur Datenbankpool erstellen oder aktualisieren
      Choose [2]: 2
       Geben Sie eine Zahl zur Auswahl des zu verwendenden Datenbankverbindungstyps ein
        [1] Basis (Hostname, Port, Servicename)
        [2] TNS (TNS-Alias, TNS-Verzeichnis)
        [3] Benutzerdefinierte Datenbank-URL
      Choose [1]: 1
      Geben Sie den Hostnamen der Datenbank ein [localhost]: 127.0.0.1
      Listener-Port der Datenbank eingeben [1521]:
      Datenbankservicename eingeben [orcl]: apex221
      Geben Sie einen Datenbankbenutzernamen mit Administratorberechtigungen an.
        Geben Sie den Administratorbenutzernamen ein: sys
          Datenbankkennwort für SYS AS SYSDBA eingeben:
    Verbindung zu Datenbankbenutzer: SYS AS SYSDBA URL: jdbc:oracle:thin:@//127.0.0.1:1521/apex221 wird hergestellt

    Informationen werden abgerufen.
    Verbindung zu Datenbankbenutzer: ORDS_PUBLIC_USER URL: jdbc:oracle:thin:@//127.0.0.1:1521/apex221 wird hergestellt
      Geben Sie eine Zahl ein, um zusätzliche Features zum Aktivieren auszuwählen:
        [1] Datenbankaktionen (aktiviert alle Features)
        [2] REST-fähige SQL und Datenbank-API
        [3] REST-fähige SQL
        [4] Datenbank-API
        [5] Kein Wert
      Choose [1]: 1
       Geben Sie eine Zahl zum Konfigurieren und Starten von ORDS im Standalone-Modus ein
        [1] ORDS im Standalone-Modus konfigurieren und starten
        [2] Überspringen
      Choose [1]: 2
    Die Einstellung db.connectionType wurde auf basic in Konfiguration default gesetzt
    Die Einstellung db.hostname wurde auf 127.0.0.1 in Konfiguration default gesetzt
    Die Einstellung db.port wurde auf 1521 in Konfiguration default gesetzt
    Die Einstellung db.servicename wurde auf apex221 in Konfiguration default gesetzt
    Die Einstellung plsql.gateway.mode wurde auf proxied in Konfiguration default gesetzt
    Die Einstellung db.username wurde auf ORDS_PUBLIC_USER in Konfiguration default gesetzt
    Die Einstellung db.password wurde auf ****** in Konfiguration default gesetzt
    Die Einstellung feature.sdw wurde auf true in Konfiguration default gesetzt
    Die globale Einstellung database.api.enabled wurde auf true gesetzt
    Die Einstellung restEnabledSql.active wurde auf true in Konfiguration default gesetzt
    Die Einstellung security.requestValidationFunction wurde auf wwv_flow_epg_include_modules.authorize in Konfiguration default gesetzt

    ....
    INFO: 11:51:30 Validating objects for Oracle REST Data Services.
    VALIDATION: 11:51:30 Starting validation for schema: ORDS_METADATA
    VALIDATION: 11:51:30 Validating objects
    VALIDATION: 11:51:33 Validating roles granted to ORDS_METADATA and
    ORDS_PUBLIC_USER
    VALIDATION: 11:51:33 Validating ORDS Public Synonyms
    VALIDATION: 11:51:34 Total objects: 312, invalid objects: 0, missing objects: 0
    VALIDATION: 11:51:34     88  INDEX
    VALIDATION: 11:51:34      1  JOB
    VALIDATION: 11:51:34      3  LOB
    VALIDATION: 11:51:34     20  PACKAGE
    VALIDATION: 11:51:34     19  PACKAGE BODY
    VALIDATION: 11:51:34      1  PROCEDURE
    VALIDATION: 11:51:34     56  PUBLIC SYNONYM
    VALIDATION: 11:51:34      1  SEQUENCE
    VALIDATION: 11:51:34     31  TABLE
    VALIDATION: 11:51:34     31  TRIGGER
    VALIDATION: 11:51:34     20  TYPE
    VALIDATION: 11:51:34      6  TYPE BODY
    VALIDATION: 11:51:34     35  VIEW
    VALIDATION: 11:51:34 Validation completed.
    INFO: 11:51:34 Completed validating objects for Oracle REST Data Services.

    PL/SQL-Prozedur erfolgreich abgeschlossen.
    Commit abgeschlossen.
    [*** script: ords_alter_session_script.sql]
    PL/SQL-Prozedur erfolgreich abgeschlossen.
    2022-09-06T09:51:34.159Z INFO        Upgrade f³r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:22.914

    [*** Informationen: Upgrade complete]
    [*** Informationen: Upgrade f├╝r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:22.914
    ]
    ------------------------------------------------------------
    Containername: APEX221
    ------------------------------------------------------------

    [*** script: ords_configure_gateway.sql]
    Configured PL/SQL Gateway user APEX_PUBLIC_USER to be proxiable from
    ORDS_PUBLIC_USER

    PL/SQL-Prozedur erfolgreich abgeschlossen.
    2022-09-06T09:51:34.244Z INFO        Konfiguration von PL/SQL-Gatewaybenutzer f³r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.85

    2022-09-06T09:51:34.244Z INFO        Datenbankkennwort f³r ORDS_PUBLIC_USER in APEX221 wird aktualisiert
    [*** Informationen: Konfiguration von PL/SQL-Gatewaybenutzer f├╝r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.85
    ]
    [*** script: ords_change_password.sql]
    PL/SQL-Prozedur erfolgreich abgeschlossen.
    2022-09-06T09:51:34.359Z INFO        Aktualisieren von Datenbankkennwort f³r ORDS_PUBLIC_USER wurde abgeschlossen. Verstrichene Zeit: 00:00:00.100

    [*** Informationen: Aktualisieren von Datenbankkennwort f├╝r ORDS_PUBLIC_USER wurde abgeschlossen. Verstrichene Zeit: 00:00:00.100
    ]
     


    Nun wird die ords.war Datei in das TomCat Verzeichnis kopiert/verschoben (z.B. C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps)
    oder unter Linux: /opt/tomcat/latest/webapps
    TomCat sollte dann innerhalb von 5 Sekunden einen Ordner ords dort anlegen!

    Ein umbenennen des ORDS ist derzeit zu keiner Phase der Installation unterstützt (Stand Nov. 2022)
    Denken Sie daran, dass Sie ggf auch in diesen Ordner die APEX Bilder (Ordner images) in den Ordner "i" kopieren !

    Nun kommt der spannendste Teil (weil nur zum Teil in der Doku :-) aber dafür gibt es ja Kurse bei Muniqsoft Training ....

    Wenn Sie bei TomCat die msi Variante installiert haben, gibt es in er Taskleiste ein TomCat Icon (Feder mit roten oder grünem Punkt)
    Rot bedeutet= TomCat nicht gestartet
    Grün bedeutet = TomCat gestartet
     
    Dort tragen Sie im Reiter Java unter Java Options ein:

    -Dconfig.url=C:\oracle\ords


    Wenn das nicht oder falsch konfiguriert wurde, quittiert Tomcat einen APEX Aufruf mit einem 404 Fehler.

    Sollten Sie TomCat lieber über die Kommandozeile starten, sollte bitte zuerst folgender Parameter im DOS Fenster gesetzt worden sein:

    _JAVA_OPTIONS=-Dconfig.url=c:\oracle\ords


    Sie können das auch unter Systemsteuerungen/System/Erweiterte Systemeigenschaften/Umgebungsvariablen unter SYSTEMVARIABLEN (unten) setzen:

    Wichtig. Unter Windows muss der TomCat Dienst in der Lage sein, die Config-Datei (bzw. den ganzen Ordner lesen zu können)
    Prüfen Sie bitte auf dem Ordner ob der "Lokale Dienst" Leserechte auf dem Ordner hat. Wenn nicht, vergeben Sie die Rechte durch:
    Rechte Maus auf den Ordner / Eigenschaften / Sicherheit : Bearbeiten / Hinzufügen "Lokaler Dienst " eingeben / OK / OK
    Auf dem Reiter Sicherheit / Erweitert (ganz unten)  [x] Alle Berechtigungen für untergeordnete Objekte .. anwählen / OK
    Warnung ignorieren und Fertig !
    Den Fehler sonst zu suchen, macht wirklich [keinen] Spass !
     



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    APEX Neue Funktionen in der Übersicht (ab 21.1)

    Bereich:APEX, Version: ab APEX 22.2, Letzte Überarbeitung: 20.10.2023

    Keywords:APEX, New Features, Neuerungen in APEX 22.1, APEX 22.2, APEX 23.1

    In vielen unserer Oracle APEX Kursen kommt die Frage auf: In welcher Version gibt es denn eigentlich die Funktion XY?
    Deswegen hier mal eine kurze Auflistung der neuen Funktionen, die in den letzten Versionen hinzugekommen sind:

    APEX 21.1

    • Einführung von CSS Variablen
    • Neuer Date Picker
    • Verbesserte Karteneinbindung (Maps)
    • Datenupload in JSON, CSV, XML oder XLSX möglich
    • Export und Import von Apps im Zip Format
    • 95 neue Icons
    • Dynamic Action mit Client Side oder Server Side Conditions
    • Farbige Banner (Links) im Workspace
    • Eingebauter Texteditor dür JS oder CSS Dateien

    APEX 21.2

    • Export Scripts Data Package ( Inhalt von Tabellen kann mit exportiert werden)
    • Neue Items: Display Map und Gecoded Address
    • Neue Region: Smart Filters
    • Neue Regionen Positionen: Banner, After Logo, ...
    • Einführung Progressive Web Applications
    • Verbesserter Breadcrumb Wizard


    APEX 22.1

    • Verbesseruneg bei der Textsuche (Multi-Word Suche)
    • Approvals (Genehmigungprozesse mit 4 Augen-Prinzip)
    • Verbesserte Region Image Unterstützung
    • Rest Enabled SQL Query
    • Verbesserungen in der Developer Toolbar
    • Workspace Files lassen sich getrennt exportieren
    • Exportformat für Appliaktion in JSON oder YAML möglich
    • Neuer Richtext Editor
    • Verbesserte Applikations-Icons (Farbe, Art, Größe)
    • Persisstent Authentication (Rember me Checkbox)
    • Verbesserte Debug Einstellung
    • Session Overrides (Länder oder Zeiteinstellungen sind sofort änderbar und werden in APP angezeigt)



    APEX 22.2

    • Application Search: Es kann eine Suchmenge definiert werden (auf Basis von Tabelle / View / REST / Liste), die dann in einer Kachelform (Badge) ausgegeben wird
    • Invoking API: PL/SQL Objekte können einfacher mit ihren Parametern aufgerufen werden
    • Genehmigungkomponente wurde verbessert in Bezug auf Fälligkeitstermine, Ablauf Policy, Aktionslogging
    • Datumsauswahl (Datepicker) "Heute" Schaltfläche kommt hinzu, schnellere Ladezeit
    • Region dynamischer Inhalt: Alte Region "PL/SQL dynamic Content" wird ersetzt durch Region die eine Funktion aufruft mit Rückgabetyp Varchar2 oder CLOB, der
      dann mittels htp.p in der Region ausgegeben wird
    • TextItem, Textarea und Richtext unterstützen nun den Datentyp CLOB
    • PWA Verbesserungen: Installationsprozess vereinfacht, Anzeige von Screenshots, Verknüpfungen für Seiten verfügbar
    • Gerätegeolokation verfügbar
    • Share Funktion für PWA
    • Dynamic Actions: Debounce (verzögerte Ausführung von Aktionen)
    • Map Region: Wechsel zwischen Vektor und Raster Tile möglich


    APEX 23.1

    • Template Komponenten (Plugins auf Templates)
    • 6 Neue Template Komponenten
    • Avatare und Badges in Interactiven Reports
    • PWA Push Benachrichtungen
    • Überarbeiteter Object Browser
    • Hintergrundprozess als Kettenprozesse definieren
    • Status der Hintergrundprozesse anzeigen
    • Rest Sources nun für Items SQL Expressions verfügbar
    • Raw Selector für Rest Data Source Profiles verfügbar
    • Rest Sources auf Basis der Antwort von Swagger / OpenAPI verfügbar
    • Copy Page nun auch aus dem Create Page Wizard erreichbar
    • Save & Run aus dem Code-Editor verfügbar
    • Export / Import im Theme Roller für Themes verfügbar
    • Color Picker Item wurde überarbeitet
    • TinyMCE ersetzt den RichTextEditor
    • Friendly URLs auch im App Builder

    APEX 23.2

    • Applikations-Arbeits Kopien (diese können wieder zusammengeführt werden mit dem Original)
    • Workflow Verbesserungen (Automatisierung von Business-Prozessen) mit Einbindung von Email-Versendungen, PL/SQL API, Push Nachrichten und REST Aufrufen
    • Neue Items: Combobox
    • Geänderte Items: File Upload (Zuschneiden von Bildern und deren Größe anpassen) Selfie-Aufnahmen werden unterstützt
    • QR Code Generator für Text, URLs, Telefonnummern, SMS, Email oder Geo-Daten
    • Benutzerdefinierte Hintergrundbilder bei Landkarten (Maps)
    • Faceted Search Verbesserungen: Auf- und Absteigende Sortierung, Unterstützung von Operatoren wie >= , <=, <, > bei der Suche
    • Template Komponenten Verbesserungen: Unbegrenzt viele Atrribute (bisher 25)
    • Neue Javascript Bibliotheken: Oracle JET 15.0.0, jQuery 3.6.4, jQuery Migrate 3.4.1, FullCalendar 6.1.8, MarkedJS 5.1.2, DOMPurify 3.0.5, Terser 5.19.2, and TinyMCE 6.6.1


    Für eine genauere Beschreibung der neuen Funktion in Oracle APEX empfehlen wir natürlich einen unserer (inzwischen 8 verschiedenen) APEX Kurse 
    (z.B. den APEX New Features Kurs, dieser wird gerade für APEX 23.2 überarbeitet)



    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    OAUTH2 Authentifizierung mit ORDS 23.1.4 in APEX 23.1

    Bereich:APEX:REST, Version: ab APEX 23.1, Letzte Überarbeitung: 13.08.2024

    Keywords:OAUTH2, APEX, REST

    Als wir auf die Oracle APEX 23.1 Version upgegraded haben, gingen plötzlich unsere REST Authentifizierungen mittels Basic Authent nicht mehr.

    Also die richtige Zeit auf etwas neueres zu wechseln, und damit auf OAUTH2.

    Vorbereitungen auf der Server Seite:

    Wir erstellen einen Client, der sich dann am REST Webservice anmelden soll/darf.

    BEGIN 
     OAUTH.create_client( 
        p_name           => 'ora_rest_client', 
        p_grant_type     => 'client_credentials', 
        p_owner          => 'MUSO_REST', 
        p_support_email  => 'info@muniqsoft-training.de', 
        p_privilege_names=> 'muso_rest_priv' ); 
    COMMIT; 
    END; 
    /

    Wir verbinden den Client mit der Rolle, die unser Modul schützt. (z.B. i
    Hinweis: Wenn Sie es noch nicht erledigt haben, dann erstellen Sie sich bitte eine REST Rolle (z.B. in APEX unter SQL Workshop / Restful Services) und erzeugen zusätzlich ein Privileg, dass die Rolle mit den gewünschten Modulen Verbindet

    
    BEGIN
     OAUTH.grant_client_role(
       p_client_name => 'ora_rest_client',
       p_role_name   => 'muso_role'
     );
    COMMIT;
    END;
    /

    Nun können Sie ermitteln, welche Client ID und welches Secret zur Verfügung gestellt werden. 

    SELECT id, name, client_id, client_secret 
    FROM user_ords_clients;
    => 1,ora_rest_client,YYY..,ZZZ..

    oder etwas ausführlicher:

    SELECT oc.id, oc.name, oc.client_id, oc.client_secret,ocr.role_name,ocp.name,oc.created_by
    FROM user_ords_clients oc,user_ords_client_roles ocr,user_ords_client_privileges ocp
    where oc.id=ocr.client_id(+)
    and oc.id=ocp.client_priv_client_id;

    Zwischenschritt: Wir testen, ob OAUTH2 uns ein Ticket zurückbringt (sonst sind vermutlich client_id oder client_secret nicht korrekt:

    WITH FUNCTION oauth2 RETURN VARCHAR2 IS
    BEGIN
    apex_web_service.oauth_authenticate(
           p_token_url     => 'https://www.muniqsoft-training.de/ords/muso/oauth/token',
           p_client_id     => 'xx..',
           p_client_secret => 'yy..',
           p_wallet_path   => 'file:///opt/oracle/admin/FREE/https_wallet');
     RETURN apex_web_service.oauth_get_last_token;
    END; 
    SELECT oauth2 from dual;
    =>J5C4eT6W8k0rkj5yeVwxg2

    Wir hatten aber noch ein anderes Problem zu lösen: Unser Tomcat ist hinter einem httpd (Apache) Server als Reverse Proxy geschaltet.

    Nur leider gibt per Default httpd an den TomCat die daten per http weiter, das mag aber oauth2 nicht. Obwohl wir in der pool.xml (ords config Ordner/database) den Wert 

    <entry key="security.verifySSL">false</entry>


    eingetragen hatten, bekamen wir trotzdem immer die Fehlermeldungen:

    TomCat Logfile: java.lang.IllegalArgumentException: Invalid character found in method name [0x050x010x00...]. HTTP method names must be tokens.

    Die Lösung bei uns war folgende Zeilen in die httpd.conf Datei einzutragen:

    SSLProxyEngine on
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off
    RequestHeader set Front-End-Https "On"
    ProxyPreserveHost on
    ProxyPass /ords https://127.0.0.1:8443/ords timeout=500
    ProxyPassReverse /ords https://127.0.0.1.8443/ords
    
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"

    Zusätzlich muss für den TomCat noch ein SSL Self Certificate erstellt werden!

    Zurück zum Thema:
    Die beiden Informationen (client_id + client_secret) setzen Sie bitte im nächsten Select ein.
    Wenn der REST Service via SSL angesprochen wird (sehr zu empfehlen!!!!), dann brauchen Sie auch noch das Zertifikat vom Server, 
    dass Sie dann in Ihr lokales Wallet einspielen müssen.
    Das Wallet wird mit einem Passwort gesichert, dass hier im Parameter l_wallet_pwd angegeben werden kann. Auch der Pfad zum Wallet wird benötigt. 
    Er sollte existieren und Oracle sollte wenigstens Leserechte auf dem Ordner besitzen

    WITH FUNCTION get_rest (rest_path IN VARCHAR2) RETURN CLOB
    IS
      l_wallet_path     VARCHAR2(255):='file:/opt/oracle/admin/XE/https_wallet';
      l_wallet_pwd      VARCHAR2(255):='XXX';
      l_client_id       VARCHAR2(255):='YYY..';
      l_client_secret   VARCHAR2(255):='ZZZ..';
      l_base_url        VARCHAR2(255):='https://www.muniqsoft-training.de/ords/oracle/muso_training/';
      l_clob    clob; 
    WITH FUNCTION get_rest (rest_path IN VARCHAR2) RETURN CLOB
    IS
      l_wallet_path     VARCHAR2(255):='file:/opt/oracle/admin/XE/https_wallet';
      l_wallet_pwd      VARCHAR2(255):='XXX';
      l_client_id       VARCHAR2(255):='YYY..';
      l_client_secret   VARCHAR2(255):='ZZZ..';
      l_base_url        VARCHAR2(255):='https://www.muniqsoft-training.de/ords/oracle/muso_training/';
      l_clob    clob; 
      
    BEGIN
      -- Token holen
      apex_web_service.oauth_authenticate(
            p_token_url     => l_base_url||'oauth/token',
            p_client_id     => l_client_id,
            p_client_secret => l_client_secret,
            p_wallet_path   => l_wallet_path,
    		p_wallet_pwd    => l_wallet_pwd );  
     
      -- Request Authorization header setzen
      apex_web_service.g_request_headers.delete();
      apex_web_service.g_request_headers(1).name  := 'Authorization';
      apex_web_service.g_request_headers(1).value := 'Bearer ' || apex_web_service.oauth_get_last_token;
      -- REst Request absetzen:
      l_clob := apex_web_service.make_rest_request (
                    p_url         => l_base_url||rest_path, 
                    p_http_method => 'GET',
    				p_wallet_path => l_wallet_path,
    				p_wallet_pwd  => l_wallet_pwd);
     
    RETURN l_clob;
    END; 
    SELECT get_rest('/muso/getTabCount') FROM dual;


    Weitere Interessente Artikel zum Thema:


    Empfohlene Schulungen zum Thema:


    Oracle SET Operatoren und Gruppenfunktionen und Unterabfragen

    Bereich:SQL, Version: ab RDBMS 11.2, Letzte Überarbeitung: 05.07.2023

    Keywords:Oracle SET Operatoren, Oracle Gruppenfunktionen, Oracle Unterabfragen

    Oracle SET-Operatoren

    INFOBESCHREIBUNGBEISPIEL
    UNIONgibt alle Zeilen aus Mehrfachabfragen zurück (doppelte werden ausgeblendet)SELECT empno, ename, dname, loc, d.deptno    
    FROM emp e, dept d    
    WHERE e.deptno = d.deptno(+)    
    UNION    
    SELECT empno, ename, dname, loc, d.deptno    
    FROM emp e, dept d    
    WHERE e.deptno(+) = d.deptno;
    UNION ALLgibt alle, auch doppelte Zeilen aus Mehrfachabfragen zurück 
    INTERSECTgibt ausschließlich gemeinsame Zeilen aus beiden Anfragen zurück 
    MINUSgibt nur die Zeilen zurück, die von der ersten, nicht aber von der Zweiten Abfrage zurück gegeben werden(Abfrage 1 minus Abfrage 2) 

     

     

     

    Oracle Gruppenfunktionen

    INFOBESCHREIBUNGBEISPIEL
    COUNT(*/Ausdruck/Spalte)zählt alle ausgewählten ZeilenSELECT count(*) FROM emp WHERE deptno = 30;
    MIN/MAX(spalte/ausdruck)ermittelt minimalen / maximalen Wert eines AusdrucksSELECT min(sal), max(sal) FROM emp;
    AVG/SUM(spalte/ausdruck)Durchschnitts/Summenwert einer SpalteSELECT sum(sal), avg(sal) FROM emp;
    grpfkt(NVL(spalte, n))auch NULL-Werte gehen in die Berechnungen mit einSELECT avg(nvl(comm, 0)) FROM emp;
    GROUP BY spalte[, spalte]unterteilt Zeilen einer Tabelle in GruppenSELECT job, avg(sal)    
    FROM emp GROUP BY job;
    HAVING group_condlegt fest welche Gruppen angezeigt werden sollenSELECT deptno, job, count(*), avg(sal)    
    FROM emp GROUP B> deptno, job    
    HAVING count(*) = 1 AND avg(sal>2000);

     

     

     

    Oracle Unterabfragen

    INFOBESCHREIBUNGBEISPIEL
    Single-Row UAgibt eine Zeile aus der inneren SELECT Anweisung zurück(=,><,<>)SELECT * FROM emp WHERE sal >    
    (SELECT avg(sal) FROM emp);    
    SELECT ename, sal FROM emp    
    WHERE deptno = (SELECT deptno FROM dept WHERE loc = 'DALLAS')    
    AND sal > (SELECT sal FROM emp    
    WHERE ename = 'TURNER');
    Multiple-Row Unterabfragegibt mehrere Zeilen Zurück in, ANY, ALL 
    IN Unterabfrageentspricht einem ListenelementSELECT ename, sal deptno FROM emp    
    WHERE sal IN (SELECT max(sal)    
    FROM emp GROUP BY deptno);
    ANY UnterabfrageWert wird mit jedem einzelnen Unterabfragewert verglichenSELECT ename, job, sal FROM emp    
    WHERE sal < ANY (SELECT sal FROM emp    
    WHERE job = 'SALESMAN');
    ALL UnterabfrageWert wird mit allen Unterabfragewert verglichen 

     

     



    Weitere Interessente Artikel zum Thema:



    Empfohlene Schulungen zum Thema:



      Reguläre Ausdrücke in Oracle (Praxisbeispiele)

      Bereich:SQL, Version: ab RDBMS 12.x, Letzte Überarbeitung: 29.02.2024

      Keywords:

      Im heutigen Tipp widmen wir uns ein paar Praxisbeispielen zu Regulär Expression (Reguläre Ausdrücke) in Oracle.

      Beispiel 1: Kreditkartennummern haben meist das Format 1234-1234-1234-1234
      Wir suchen in einem String zwei 4er Blöcke mit Zahlen un einem Minus dazwischen und ersetzen jeden Block durch xxxx-xxxx:

      • [[:digit:]] steht nur für Zahlen
      • [4} 4 Zahlen
      select regexp_replace(
      '1234-5678-1111-2222',
      '[[:digit:]]{4}-[[:digit:]]{4}','xxxx-xxxx') from dual;

      Ergebnis: xxxx-xxxx-xxxx-xxxx

      Oder wir suchen vier 4er Blöcke mit Zahlen und ersetzen das mit XXXX:

      select regexp_replace(
      '1234-5678-1111-2222',
      '[[:digit:]]{4}','xxxx') 
      from dual;

      Ergebnis: xxxx-xxxx-xxxx-xxxx

      Nur der letzte 4er Block soll ausgegeben werden

      select regexp_replace(
      '1234-5678-1111-2222',
      '([[:digit:]]{4})(-)([[:digit:]]{4})(-)([[:digit:]]{4})(-)([[:digit:]]{4})','XXXX-XXXX-XXXX-\7') from dual;

      Ergebnis:

      XXXX-XXXX-XXXX-2222

       

      Alternativ können sie anstatt [[:digit:]] durch \d ersetzen

      select regexp_replace(
      '1234-5678-1111-2222',
      '\d{4}','x') 
      from dual;

      Ergebnis: x-x-x-x

      Beispiel 2: Wir löschen einige HTML Tags in einem String:

      • \/?div findet div, 
      • \/?p findet p und 
      • \/?strong findet strong Tags 
      • (da / ein Sonderzeichen ist, muss es mit \ entwertet (escaped) werden)
      select regexp_replace(
      '<div>Hallo</div><strong> Kurs</strong>',
      '(<\/?div>|<\/?p>|<\/?strong>)','') 
      from dual;

      oder wir löschen alle HTML Tags im String

      select regexp_replace(
      '<div>Hallo</div><strong> Kurs</strong>',
      '<\/?[^>]*>,'') 
      from dual;

      Das war eine kleine Beispielauswahl, die von uns ständig erweitert wird. Oder Sie kommen z.B. in den PL/SQL oder PL/SQL II Kurs, da werden diese Themen auch ausführlich besprochen.



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Export Private Reports einen interactive Report in APEX

      Bereich:APEX, Version: ab APEX 22.1, Letzte Überarbeitung: 17.12.2022

      Keywords:Interactiver Report, Apex private Report

      Wenn Sie eine Seite mit private Reports exportieren möchten, gibt es da einen Trick:
       

      1. Exportieren Sie die komplette Applikation. Wählen Sie aber bitte an:
      a, [x] Split into Multiple Files
      b, optional [X] Export Public Reports
      c, [X] Export Private Reports
      2. Nun wird ein Zip File exportiert, das Sie bitte entpacken.
      3. Nun gehen Sie in SQL*Plus oder SQL*Developer und starten bitte folgende Skripte
      a, f??? (??? für Ihre App ID) / Application / set_environment.sql
      b, f??? / Application / Pages / page_00??.sql für alle Seiten die Sie mit interakiven Report mit Public und/oder Private Reports wieder einspielen möchten
      c, f??? / Application / end_environment.sql


      FERTIG, alle gewünschten Seiten mit interactiven Report sind wieder in Ihrer Applikation

       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Installation der Oracle 23ai FREE Edition auf Rocky Linux mit APEX 22.2 und ORDS 23.1

      Bereich:APEX, Version: ab APEX 22.2:ORDS 23.1, Letzte Überarbeitung: 16.08.2024

      Keywords:Rocky Linux, Oracle 23ai, Free Edition, APEX Installation

      Als vor zwei Wochen die Oracle Version 23ai FREE Edition herauskam, waren wir sehr (positiv) überracht, dass die kostenlose Version vor der Produktiv Version veröffentlicht wurde.
      Es wurde also mal wieder Zeit einen Artikel für die jeweils neusten Oracle Versionen zu schreiben. et voila …

      Wir installieren auf einem Server mit der Ip Adresse 172.30.30.99. Sie können natürlich eine andere IP Adresse wählen, sollten dann aber an allen Stellen wo wir diese IP verwenden Ihre eintragen.
      Da man ja seit Version Oracle 21c nun mit Pluggable Database Containern arbeiten muss, verwenden wir hier den Container apex222. Auch den können Sie natürlich umbenennen.

      Wir empfehlen mit mindestens 2 SSH Sessions parallel zu arbeiten um die Zeit drastisch zu verkürzen.
      Wir nennen im folgenden die beiden Sessions SES_1 und SES_2. Bitte lesen Sie die folgenden Schritte zuerst komplett durch
      weil einige Punkte weiter unten zusammengefasst werden :-)

      1. Redhat 8 / Centos 8 / Rocky 8 Preinstall Packages für Oracle 23ai herunterladen:

      wget https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el8.x86_64.rpm

      2. FREE Edition herunterladen
      wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm

      3. Wir benennen den Pluggable Database Container um( muss man nicht, wenn man mit dem Namen freepdb1 zufrieden ist)

      ALTER PLUGGABLE DATABASE freepdb1 CLOSE;
      ALTER PLUGGABLE DATABASE freepdb1 OPEN RESTRICTED;
      ALTER SESSION SET CONTAINER=freepdb1;
      ALTER PLUGGABLE DATABASE RENAME GLOBAL_NAME TO apex222;


      Laden Sie APEX 23.2 (oder neuer) herunter:
      https://download.oracle.com/otn_software/apex/apex_23.2.zip

      Laden Sie den neusten Patch für APEX herunter (dazu ist ein gültiger Support-Vertrag mit Oracle notwendig):
      https://support.oracle.com/epmos/faces/PatchDetail?patchId=34628174

      Laden Sie die ORDS-Version herunter (April 2023 war Version 23.1.1 aktuell):
      https://download.oracle.com/otn_software/java/ords/ords-23.1.1.109.1003.zip

      Laden Sie die neueste Apache TomCat 9 Version herunter. Version 10 wird aktuell (01.05.2024) nicht von ORDS unterstützt:
      https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.93/bin/apache-tomcat-9.0.93.zip

      Session SES_1
      dnf -y install wget
      dnf -y update

      Download Skript für alle Dateien (bis auf Patch, da müssen Sie beim Support angemeldet sein) in SES_2:

      mkdir -p /tmp/oracle
      cd /tmp/oracle
      wget https://yum.oracle.com/repo/OracleLinux/OL8/developer/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-0.5.el8.x86_64.rpm
      wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm
      wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
      wget https://download.oracle.com/otn_software/apex/apex_23.2.zip
      wget https://download.oracle.com/otn_software/java/ords/ords-23.1.1.109.1003.zip
      wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.89.zip

       

      Nun kann mit der Installation der in SES_2 heruntergeladenen Programme begonnen werden

      Session SES_1:

      dnf -y install oracle-database-preinstall-23ai*
      dnf -y localinstall oracle-database-free-23ai*
      export DB_PASSWORD=mein_password_fuer_2023
      (echo "${DB_PASSWORD}"; echo "${DB_PASSWORD}";) | /etc/init.d/oracle-free-23ai configure

      In der Datei /etc/oratab die Datenbank auf Autostart (N durch Y in der letzten Zeile am Ende ersetzen)

      FREE:/opt/oracle/product/23ai/dbhomeFree:Y

      Wenn die Oracle Datenbank Instanz und der Oracle Listener beim Start des Betriebssystem mitstarten sollen:

      systemctl enable oracle-free-23ai

      Wenn Oracle DB + Listener manuell gestoppt und gestartet werden sollen:

      systemctl stop oracle-free-23ai
      systemctl start oracle-free-23ai

      Wenn Ihnen der Name oracle-free-23 zulange ist, können Sie auch stattdessen “oracle”als Servicename einrichten

      Kopieren Sie dazu nur die Datei /etc/rc.d/init.d/oracle-free-23ai in die Datei oracle um:

      cp /etc/rc.d/init.d/oracle-free-23ai /etc/rc.d/init.d/oracle

      ... dauert wieder ein paar Minuten .. wir wechseln in SES_2

      Session SES_2:

      mkdir -p /opt/tomcat
      mv apache-tomcat-9.0.89.zip /opt/tomcat/
      cd /opt/tomcat
      unzip apache*
      ln -s apache-tomcat-9.* latest
      useradd -r tomcat --shell /bin/false
      chown -R tomcat /opt/tomcat
      chmod +x /opt/tomcat/latest/bin/*.sh
      # Passen Sie die Firewall an Ihre Bedürfnisse an. Hier werden in Zone Public einige Ports freigegeben
      firewall-cmd --zone=public --permanent --add-port=1521/tcp
      firewall-cmd --zone=public --permanent --add-service=https
      firewall-cmd --zone=public --permanent --add-service=http
      firewall-cmd --zone=public --permanent --add-port 8080/tcp
      firewall-cmd --reload
      dnf -y localinstall jdk-17*
      java -version
      which java

      Datei anlegen zum Autostart von TomCat
      vi /etc/systemd/system/tomcat.service

      [Unit]
      Description=Tomcat 9 servlet container
      After=network.target
      [Service]
      Type=forking
      User=tomcat
      Group=tomcat
      Environment="JAVA_HOME=/usr"
      Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords"
      Environment="CATALINA_BASE=/opt/tomcat/latest"
      Environment="CATALINA_HOME=/opt/tomcat/latest"
      Environment="CATALINA_PID=/opt/tomcat/latest/temp/tomcat.pid"
      Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
      ExecStart=/opt/tomcat/latest/bin/startup.sh
      ExecStop=/opt/tomcat/latest/bin/shutdown.sh
      [Install]
      WantedBy=multi-user.target

      Tomcat als Autostart einrichten

      systemctl daemon-reload
      systemctl enable tomcat
      systemctl start tomcat
      systemctl status tomcat

       

      Bash Profile für Oracle Benutzer anlegen:

      cat << EOF > /home/oracle/.bash_profile
      export TERM=vt220
      export EDITOR=vi
      export PS1="[\u@\h:\w]>"
      export DISPLAY=:0.0
      export ORACLE_BASE=/opt/oracle
      export ORACLE_HOME=\$ORACLE_BASE/product/23ai/dbhomeFree
      export ORACLE_SID=FREE
      export ORACLE_INSTANCE=free
      export ORACLE_TERM=vt220
      export ORA_NLS10=\$ORACLE_HOME/nls/data
      export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$ORACLE_HOME/lib
      export NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252
      export PATH=\$ORACLE_HOME/bin:\$PATH:/usr/sbin:/usr/ccs/bin
      alias cdo="cd \$ORACLE_HOME; pwd"
      alias cdd="cd \$ORACLE_BASE/oradata"
      alias cda="cd \$ORACLE_BASE/diag/rdbms/\$ORACLE_INSTANCE/\$ORACLE_SID/trace; pwd"
      alias cdn="cd \$ORACLE_HOME/network/admin; pwd"
      alias cde="cd \$ORACLE_BASE/admin/\$ORACLE_SID/dpdump"
      alias sp="\$ORACLE_HOME/bin/sqlplus '/ as sysdba'"
      alias l="ls -l"
      alias ll="ls -la"
      alias ipconfig="/sbin/ifconfig | grep Bcast"
      echo Folgende Einstellungen wurden gesetzt:
      env | grep ORA
      ps aux | grep [t]omcat | awk '{print "Tomcat-Prozess:" \$2}'
      ps aux | grep [d]b_pmon | awk '{print "Oracle-Prozess:" \$2}'
      ps aux | grep [t]ns | awk '{print "Listener-Prozess:" \$2}'
          EOF
      . .bash_profile

      APEX und ORDS auspacken:

      cd /tmp/oracle
      unzip apex_22*
      chown -R oracle:oinstall apex*
      mkdir ords
      unzip ords-2*.zip -d ords

      Session SES_1

      APEX muss in der anderen Session bereits ausgepackt worden sein!

      su - oracle

       

      REM Bei uns wurde bei der Installation ein exotischer Port für den Listener benutzt. 
      Wenn Sie den Oracle Standard-Port 1521 wieder möchten, ersetzen Sie ihn in der Datei listener.ora

      lsnrctl stop
      IP=$(hostname -I)

       

      cat << EOF >$ORACLE_HOME/network/admin/listener.ora
      # listener.ora Network Configuration File: /opt/oracle/product/23ai/dbhomeFree/network/admin/listener.ora
      # Generated by Oracle configuration tools.
      DEFAULT_SERVICE_LISTENER = FREE
      LISTENER =
       (DESCRIPTION_LIST =
         (DESCRIPTION =
           (ADDRESS = (PROTOCOL = TCP)(HOST = \$IP)(PORT = 1521))
         )
       )
      EOF

      Nun wird APEX installiert. Hier können verschiedene Passwörter für die Oracle APEX Benutzer gesetzt werden. Wir haben aber bis auf den Internal Workspace Admin Benutzer
      das gleiche Passwort gesetzt.

      Auch kann ein eigener Tablespace für die Installation verwendet werden. Wir haben hier APEX jedoch in den Tablespace SYSAUX installiert.

      lsnrctl start
      cd /tmp/oracle/apex
      cat << EOF >preinstall.sql
      alter system set local_listener='(ADDRESS = (PROTOCOL = TCP)(HOST = \$IP)(PORT = 1521))';
      alter system register;
      host lsnrctl status
      define pwd_apx=apex
      define pwd_ws_int=Apex2023#
      @apxsilentins.sql SYSAUX SYSAUX TEMP /i222/ &pwd_apx. &pwd_apx. &pwd_apx. &pwd_ws_int.
      EOF
      sqlplus sys/sys@172.30.30.99/apex222 as sysdba
      @preinstall.sql

      Während die APEX Installation läuft, kann wieder in die andere Session gewechselt werden, dort installieren wir den ORDS…

      cd /tmp/oracle/ords
      bin/ords --config /opt/oracle install
      [2] Datenbankpool erstellen oder aktualisieren ...
      [1] Basis (Hostname, Port, Servicename)
      => 172.30.30.99
      => 1521
      => apex222
      => sys
      => <Ihr sys-pwd>
      => SYSAUX
      => TEMP
      [1] Datenbankaktionen (aktiviert alle Features)
      [2] Überspringen

      Nun kopieren wir den ORDS in den TomCat Ordner:

      cp ords.war /opt/tomcat/latest/webapps/

      Dateien von APEX auch in den TomCat Ordner verschieben:

      mv /tmp/oracle/apex/images/ /opt/tomcat/latest/webapps/i222

      So, das war´s. gar nicht so schwer, oder ? :-)

      Wenn man mit zwei Sessions arbeitet und in keine Probleme läuft, sollte das in ca. einer Stunde erledigt sein.

      Bonus-Track:

      Apache TomCat hat leider keine Redirect Funktion, dazu braucht man den Apache Webserver. Aber Sie können mit einem kleinen Trick dafür sorgen, dass Sie gleich auf Ihre Lieblingsapp weitergeleitet werden, sobald Sie die folgende URL eingeben:

      http://172.30.30.99:8080

      Wir machen dazu einfach einen Refresh als Meta-Tag auf die Datei index.html

      cp /opt/tomcat/latest/webapps/ROOT/index.html /opt/tomcat/latest/webapps/ROOT/index.html.old
      echo '<html><head><meta http-equiv="refresh" content="0; url=http://172.30.30.99:8080/ords/f?p=100" /></head></html>'>/opt/tomcat/latest/webapps/ROOT/index.html

      oder wenn Sie TEST-Maschine haben und kein Problem damit haben, dass Ihr Password im Klartext in einer Datei steht…. können Sie die Anmeldedaten für den Applikation Builder bereits eintragen

      echo '<html><head><meta http-equiv="refresh" content="0; url=http://172.30.30.100:8080/ords/f?p=4550:1:1::::F4550_P1_COMPANY,F4550_P1_USERNAME,F4550_P1_PASSWORD:schulung,admin,ganzschöngeheim2023" /></head></html>'>/opt/tomcat/latest/webapps/ROOT/index.html

      Hier sind eingetragen:

      Workspace-Name (F4550_P1_COMPANY) = schulung
      Username (F4550_P1_USERNAME) = admin
      Password: (F4550_P1_PASSWORD) = ganzschöngeheim2023

      Das sollte natürlich von Ihnen angepasst werden :-)

      Rufen Sie nun im Browser die Seite http://172.30.30.99:8080/ords auf bzw. wenn der Bonustrack installiert wurde: http://172.30.30.99:8080

      Bonus-Bonus-Track:http://172.30.30.99:8080/ords

      Unter Windows können Sie auch gleich eine Portweiterleitung einrichten, dann wird Port 80 auf Port 8080 weitergeleitet. Dies geschieht (als Administrator) mit:

      netsh interface portproxy add v4tov4 listenaddress=172.30.30.99 listenport=80 connectaddress=172.30.30.99 connectport=8080

      Dann lautet der Aufruf nur noch:

      http://172.30.30.99

      und dann besuchen Sie uns doch bald mal in einer von unseren 48 verschiedenen Oracle Schulungen in München-Unterhaching :-)

       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle Attention.log via Pipelined Table Function auslesen / auswerten

      Bereich:DBA:PL/SQL, Version: ab RDBMS 21.1:RDBMS 23.1, Letzte Überarbeitung: 15.11.2023

      Keywords:

      Ab der Version Oracle 21c wird zusätzlich zum alert.log noch eine neue Datei ausgeliefert: das Attention.log. Hier sollen wichtige Information als Zusammenfassung der Alert.log stehen.

      Naja, ich hoffe das wird nicht etwas verbessert, aber trotzdem wäre es praktisch die Datei mit einem Select auszulesen. Ich hatte gehofft, jemand hat sich die Arbeit schon gemacht (Google wo bist Du, wenn man Dich braucht…), aber leider habe ich nichts gefunden.

      Ok, dann mach ich es halt …

      Wir geben die Objekte dem Benuter system, sie können aber natürlich auch einen anderen Benutzer dafür einrichten.

      ALTER SESSION SET current_schema=system;
      col adir new_value adir
      col afile new_value afile
      with diag as (select sys_context('userenv','PLATFORM_SLASH') as ps,value from v$diag_info
      where name='Attention Log')
      select 
      substr(value,1,instr(value,ps,-1)-1) as adir,
      substr(value,instr(value,ps,-1)+1) as afile
      from diag;
      CREATE OR REPLACE DIRECTORY attention_dir as '&adir.';
      GRANT READ ON DIRECTORY attention_dir to system;

       

      CREATE OR REPLACE TYPE attention_type 
      AS OBJECT (
         NOTIFICATION    VARCHAR2(4000), 
         ERROR           VARCHAR2(4000),
         URGENCY         VARCHAR2(4000),
         INFO            VARCHAR2(4000),
         CAUSE           VARCHAR2(4000),
         ACTION          VARCHAR2(4000),
         CLASS           VARCHAR2(4000),
         TIME            TIMESTAMP WITH TIME ZONE    
      );
      /
      CREATE OR REPLACE TYPE attention_tab_type AS TABLE OF attention_type;
      /
      CREATE OR REPLACE FUNCTION read_attention_log 
      RETURN attention_tab_type PIPELINED
      IS
       f_handle  utl_file.file_type:=utl_file.fopen(
       location=>'ATTENTION_DIR',
       filename=>'&afile.',
       open_mode=>'r',
       max_linesize=>32767);
       text         varchar2(32767);
       v_a_log attention_type:=attention_type(null,null,null,null,null,null,null,null);
       v_i INT:=1;
      BEGIN
       LOOP 
           BEGIN
           utl_file.get_line(f_handle,text); -- Neue Zeile lesen
         IF substr(text,1,16)='  "NOTIFICATION"' THEN
             v_a_log.NOTIFICATION:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
         IF substr(text,1,9)='  "ERROR"' THEN 
             v_a_log.ERROR:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
         IF substr(text,1,11)='  "URGENCY"' THEN    
             v_a_log.URGENCY:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
         IF substr(text,1,8)='  "INFO"' THEN    
             v_a_log.INFO:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;  
         IF substr(text,1,9)='  "CAUSE"' THEN
             v_a_log.CAUSE:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
         IF substr(text,1,10)='  "ACTION"' THEN
             v_a_log.ACTION:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
          IF substr(text,1,9)='  "CLASS"' THEN
             v_a_log.CLASS:=rtrim(rtrim(substr(text,21),','),'"');
         END IF;
         IF substr(text,1,8)='  "TIME"' THEN
             v_a_log.TIME:=to_timestamp_tz(rtrim(substr(text,21),'"'),'YYYY-MM-DD"T"HH24:MI:SS.FFTZH:TZM');
             PIPE ROW (v_a_log);
             v_a_log :=attention_type(null,null,null,null,null,null,null,null);
         END IF;
           EXCEPTION 
          WHEN NO_DATA_FOUND THEN EXIT; -- Keine Zeile im Attention.log mehr gefunden oder Fehler=> Schleife verlassen
          WHEN OTHERS THEN RAISE;
           END;
       END LOOP; 
       utl_file.fclose(f_handle);
      END;
      /

      Un nun können Sie das attention.log via SQL auslesen …

      SELECT * FROM table(read_attention_log);


      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle APEX Interactive Grid Javascript Snippets

      Bereich:APEX, Version: ab APEX 22.2:APEX 23.1, Letzte Überarbeitung: 20.09.2023

      Keywords:APEX Javascript, Grid , Interactive Grid

      In unseren Schulungen werden immer mal Fragen zum Interactiven Grid gestellt, die sehr interessant sind. Hier eine kleine Auswahl:

      Vorraussetungen:

      1. Es gibt ein Grid auf die Scott.emp Tabelle mit der Static ID EMP
      2. Es gibt eine Selectbox mit Namen P1_JOB

       

      1. Es soll im Grid für die EMP Tabelle, der Job für alle Mitarbeiter auf einen einheitlichen Wert gesetzt werden, der in einem Item ausserhalb des Grids steht:
      var model = apex.region("EMP").widget().interactiveGrid("getViews", "grid").model;
          model.forEach(function(r) {
             model.setValue(r, "JOB", $v("P1_JOB" )); // Setzen des Jobs pro Zeile
          })

      2. Es sollen nur die mit der im Grid enthaltenen Checkbox (Spalte 1) ausgewählten Einträge geändert werden:

      var grid = apex.region("EMP").widget().interactiveGrid("getViews","grid");
      var model   = grid.model;
      var selectedRecords = grid.getSelectedRecords();
      //console.log("Records" +selectedRecords.length);
      for (idx = 0; idx < selectedRecords.length; idx++) {
         record = model.getRecord(selectedRecords[idx][0]); 
           model.setValue(record, "JOB", $v( "P1_JOB" ));
          //console.log(idx+ " " + selectedRecords[idx][1] ); //Felder [1] EMPNO [2] ENAME, [3] JOB ...
      }

      3. Sie möchten das zurückschreiben in die DB selbst erledigen, kein Problem. Ersetzen Sie den Prozeß durch:

      IF :APEX$ROW_STATUS='C' THEN
          INSERT INTO emp (empno,ename,job,mgr,hiredate,sal,comm,deptno)
          VALUES (:EMPNO,:ENAME,:JOB,:MGR,:HIREDATE,:SAL,:COMM,:DEPTNO);
      ELSIF :APEX$ROW_STATUS='U' THEN
          UPDATE emp SET
          ename=:ENAME,job=:JOB, mgr=:MGR,hiredate=:HIREDATE ,sal=:SAL,comm=:COMM, deptno=:DEPTNO
          WHERE empno=:EMPNO ;
      ELSIF :APEX$ROW_STATUS='D' THEN
          DELETE FROM emp
          WHERE empno=:EMPNO;
      END IF;

      Das war ein kleiner Auszug aus den vielen Fragen in unseren APEX Kursen. Sie haben auch Fragen? Dann kommen Sie doch in einen unserer Kurse…. wir freuen uns auf Sie !



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle 23ai auf Windows WSL

      Bereich:DBA, Version: ab RDBMS 23.1, Letzte Überarbeitung: 17.05.2024

      Keywords:Oracle 23ai, Oracle 23c, WSL

      Alle warten ja gespannt auf die Production Version von Oracle 23ai (formaly known as Oracle 23c).   
      Denn wenn die rauskommt hofft der eine oder andere Windows Benutzer auf eine Windows Portierung.

      Wir wollen hier eine Lösung vorstellen die eigentlich ein Kompromiss ist: Oracle 23ai auf Windows in einer Linux Umgebung.   
      Jetzt werden Sie sagen, ja via Virtualisierung geht das ja schon immer…   
      Es gibt aber evtl eine neue Variante, die nicht so bekannt ist: WSL (Windows Subsystem for Linux). Dazu muss nur die CPU auch Virtualisierung unterstützen.
      Wir arbeiten dann im Windows Terminal (das ab Win 11 vorinstalliert ist)
      Für Win 10 kann es nachinstalliert werden z.B. mittels:

      winget install --id Microsoft.WindowsTerminal -e

      Das läuft zwar unter der Haube auch wie eine Virtualisierung, aber der Benutzer sieht nichts davon.   
      Interessant ist, dass Oracle natürlich diese neue Schnittstelle unterstützt (ob sie supported ist, müssten Sie bitte mit Ihrem Support-Techniker klären)   
      Ich würde mal tippen NEIN, aber für die Testzwecke ist die Installation ganz OK. Be uns funktionierte das Ganze sogar innerhalb einer Virtualisierungsmaschine (Nested Virtualization)

      Zuerst werden die Windows Features aktiviert (in einem Powershell Fenster als Administrator):

      dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
      dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all

      Beachten Sie bitte, dass die Distrubution später auch nur unter diesem Admin Account im Terminal angezeigt wird!

      Wir lassen uns anzeigen, welche Distributionen unterstützt werden:

      wsl --list --online
      Die folgende Liste enthält gültige Distributionen, die installiert werden können.
      Die Standard Distribution ist mit „*“ gekennzeichnet.
      Installieren sie mit dem Befehl „wsl --install -d <Distro>“.
      NAME                                   FRIENDLY NAME
      * Ubuntu                                 Ubuntu
      Debian                                 Debian GNU/Linux
      kali-linux                             Kali Linux Rolling
      Ubuntu-18.04                           Ubuntu 18.04 LTS
      Ubuntu-20.04                           Ubuntu 20.04 LTS
      Ubuntu-22.04                           Ubuntu 22.04 LTS
      Ubuntu-24.04                           Ubuntu 24.04 LTS
      OracleLinux_7_9                        Oracle Linux 7.9
      OracleLinux_8_7                        Oracle Linux 8.7
      OracleLinux_9_1                        Oracle Linux 9.1
      openSUSE-Leap-15.5                     openSUSE Leap 15.5
      SUSE-Linux-Enterprise-Server-15-SP4    SUSE Linux Enterprise Server 15 SP4
      SUSE-Linux-Enterprise-15-SP5           SUSE Linux Enterprise 15 SP5
      openSUSE-Tumbleweed                    openSUSE Tumbleweed
                   

      und siehe da, es werden sogar drei verschiedene Oracle Versionen unterstützt!

      Da Oracle 23ai die Version 9 unterstützt, nehmen wir diese natürlich und installieren die Distribution (dauert ca 4 Min.).

      wsl --install -d OracleLinux_9_1 --web-download
      oder manchmal auch nur:
      wsl --install -d OracleLinux_9_1

      Bei einem Fehler: Error: 0x800701bc WSL 2 erfordert ein Update der Kernelkomponente sollte das WSL upgedated werden. z.B. hier.

      Wir werden nun nach einen Benutzernamen und einem Passwort für die Distribution gefragt. Wir nehmen Oracle Passwort sys (oder ein besseres natürlich…)

      Installing, this may take a few minutes...
      Please create a default UNIX user account. The username does not need to match your Windows username.
      For more information visit: https://aka.ms/wslusers
      Enter new UNIX username: oracle
      Changing password for user oracle.
      New password:
      Retype new password:
      
      Windows-Subsystem für Linux ist jetzt im Microsoft Store verfügbar!
      Sie können ein Upgrade durchführen, indem Sie "wsl.exe --update" ausführen oder https://aka.ms/wslstorepage
      Durch die Installation von WSL aus dem Microsoft Store erhalten Sie schneller die neuesten WSL-Updates.
      Weitere Informationen finden Sie unter https://aka.ms/wslstoreinfo

      gut ein Update schadet ja selten ..

      wsl.exe --update
      Installation: Windows-Subsystem für Linux
      Windows-Subsystem für Linux wurde installiert.

      Danach sind wir im Terminalfenster bereits in der Unix Maschine angemeldet. Sie können aber natürlich sich auch mittels Putty verbinden.

      Nun brauchen wir das Oracle Vorbereitungspackage für die Installation der Datenbank.

      sudo dnf install -y oracle-database-preinstall-23ai

      Danach laden wird die aktuelle Oracle 23ai Version runter und installieren diese:

      wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm
      sudo rpm -ihv oracle-database-free-23ai*

      Wenn Sie SYSTEMCTL aktivieren möchten tragen Sie bitte folgendes in die Datei /etc/wsl.conf ein:

      [boot]
      systemd=true

      Weitere Parameter finden Sie hier.

      Wenn Sie systemd=true gesetzt haben, kann Oracle als Service eingerichtet werden:

      cp /etc/initd.d/oracle-free-23ai /etc/init.d/oracle
      systemctl enable oracle
      
      oracle.service is not a native service, redirecting to systemd-sysv-install.
      Executing: /usr/lib/systemd/systemd-sysv-install enable oracle
      
      systemctl start oracle
      systemctl status oracle
      
      ● oracle.service - SYSV: This script is responsible for taking care of configuring the RPM Oracle FREE Database and its>
          Loaded: loaded (/etc/rc.d/init.d/oracle; generated)
          Active: active (exited) since Sat 2024-05-18 09:44:49 CEST; 6s ago
            Docs: man:systemd-sysv-generator(8)
         Process: 857 ExecStart=/etc/rc.d/init.d/oracle start (code=exited, status=0/SUCCESS)
      May 18 09:44:48 Schulung133 systemd[1]: Starting SYSV: This script is responsible for taking care of configuring the RP>
      May 18 09:44:49 Schulung133 oracle[857]: The Oracle Database instance FREE is already started.
      May 18 09:44:49 Schulung133 systemd[1]: Started SYSV: This script is responsible for taking care of configuring the RPM>
      

      resolv.conf prüfen:

      sudo cat /etc/resolv.conf
      nameserver 172.30.30.6
      nameserver 8.8.8.8

      Weitere Interessante/praktische Packages für Oracle, die sie nun installieren sollten (ohne hostname klappte unsere Installation auf einigen Rechnern nicht):

      OpenSSH

      sudo dnf install -y openssh

      RLWRAP (History für SQL*Plus und RMAN Eingaben:

      sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/r/rlwrap-0.46.1-1.el9.x86_64.rpm

      P7ZIP (Packutility)

      sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/p/p7zip-16.02-21.el9.x86_64.rpm
      sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/p/p7zip-plugins-16.02-21.el9.x86_64.rpm

      Firewall

      sudo dnf install -y firewall

      Hostname

      sudo dnf install -y hostname

       

      Wenn auf Ihrer Windows-Maschine bereits eine Oracle Datenbank mit Listener auf Port 1521 läuft, ändern wir den Port für unsere neue DB:

      Listener Port ändern in /etc/sysconfig/oracle-free-23ai.conf => 1522

      Die Datei hat übrigens folgendes Aussehen (falls Sie vor der Installation noch mehr ändern wollen):

      #This is a configuration file to setup the Oracle Database.
      #It is used when running '/etc/init.d/oracle-free-23ai configure'.
      # LISTENER PORT used Database listener, Leave empty for automatic port assignment
      LISTENER_PORT=1522
      # Character set of the database
      CHARSET=AL32UTF8
      # Database file directory
      # If not specified, database files are stored under Oracle base/oradata
      DBFILE_DEST=
      # DB Domain name
      DB_DOMAIN=
      # Configure TDE
      CONFIGURE_TDE=false
      # Encrypt Tablespaces list, Leave empty for user tablespace alone or provide ALL for encrypting all tablespaces
      # For specific tablespaces use SYSTEM:true,SYSAUX:false
      ENCRYPT_TABLESPACES=
      # SKIP Validations, memory, space
      SKIP_VALIDATIONS=false

      Nun starten wir das Oracle Installationsskript:

      sudo /etc/init.d/oracle-free-23ai configure
      
      ...
      Database creation complete. For details check the logfiles at:
       /opt/oracle/cfgtoollogs/dbca/FREE.
      Database Information:
      Global Database Name:FREE
      System Identifier(SID):FREE
      Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details.
      
      Connect to Oracle Database using one of the connect strings:
           Pluggable database: Schulung133:1522/FREEPDB1
           Multitenant container database: Schulung133:1522

      et voila, die Datenbank ist installiert.

      Praktisch ist es jetzt noch, wenn wir uns gleich ein schönes Profil für die neue DB einrichten

      export TERM=vt220
      export EDITOR=vi
      export PS1="[\u@\h:\w]>"
      export DISPLAY=:0.0
      export ORACLE_BASE=/opt/oracle
      export ORACLE_HOME=$ORACLE_BASE/product/23ai/dbhomeFree
      export ORACLE_SID=FREE
      export ORACLE_INSTANCE=free
      export ORACLE_TERM=vt220
      export ORA_NLS10=$ORACLE_HOME/nls/data
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib
      export NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252
      export PATH=$ORACLE_HOME/bin:$PATH:/usr/sbin:/usr/ccs/bin
      alias cdo="cd $ORACLE_HOME; pwd"
      alias cdd="cd $ORACLE_BASE/oradata"
      alias cda="cd $ORACLE_BASE/diag/rdbms/$ORACLE_INSTANCE/$ORACLE_SID/trace; pwd"
      alias cdn="cd $ORACLE_HOME/network/admin; pwd"
      alias cde="cd $ORACLE_BASE/admin/$ORACLE_SID/dpdump"
      alias sp="$ORACLE_HOME/bin/sqlplus '/ as sysdba'"
      alias l="ls -l"
      alias ll="ls -la"
      alias ipconfig="/sbin/ifconfig | grep Bcast"
      echo Folgende Einstellungen wurden gesetzt:
      env | grep ORA
      ps aux | grep [t]omcat | awk '{print "Tomcat-Prozess:" $2}'
      ps aux | grep [x]e_pmon | awk '{print "Oracle-Prozess:" $2}'
      ps aux | grep [t]ns | awk '{print "Listener-Prozess:" $2}'
      HISTCONTROL=ignorespace

      Na dann testen wir mal:

      sqlplus / as sysdba
      SQL*Plus: Release 23.0.0.0.0 - Production on Mi Mai 15 08:43:05 2024
      Version 23.4.0.24.05
      Copyright (c) 1982, 2024, Oracle.  All rights reserved.
      Verbunden mit:
      Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
      Version 23.4.0.24.05

      wenn die Instanz gestartet wurde, kann natürlich auch von SQL Developer Windows eine Verbindung zur 23ai aufgebaut werden.

      Zum Schluss ein paar Tipps & Tricks , weil die WSL verhält sich nicht ganz Linux-Like …   
      z.B. wird systemctl nicht unterstützt (grmmpf) oder der root account hat kein Passwort und unser Benutzer oracle übernimmt seine Aufgaben mittels sudo …

      Instanz und Listener starten:

      sudo -s service oracle-free-23ai start
      oder
      sudo -s /etc/init.d/oracle-free-23ai start
      [sudo] password for oracle:
      Starting Oracle Net Listener.
      Oracle Net Listener started.
      Starting Oracle Database instance FREE.
      Oracle Database instance FREE started.

      IP Adresse ändern (Static):

      sudo ip address add 172.30.30.233/24 brd + dev eth0

       

      Anmelden an spezieller Distribution mit Benutzer Oracle:

      wsl --distribution OracleLinux_9_1 --user oracle

      Windows Terminal als Admin starten

      Windows Key + X => Windows Terminal (Admin) auswählen

      Stoppen der Oracle Linux Disti (shutdown -r now ist hier nicht möglich)

      wsl --shutdown OracleLinux_9_1      
      
      In Ihrer Linux shell erscheint dann:
      [Verarbeitung des Prozesses mit Code 1 (0x00000001) beendet]
      Sie können dieses Terminal jetzt mit STRG+D schließen oder zum Neustart die EINGABETASTE drücken.
      Nun viel Spass mit Oracle 23ai "unter Windows” und evtl sehen wir uns mal in einem unserer Kurse (live oder per Teams) …


      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle Fehlermeldungen aus der DB anzeigen

      Bereich:DBA, Version: ab RDBMS 12.x:RDBMS 18.1:RDBMS 19.1:RDBMS 21.1:RDBMS 23.1, Letzte Überarbeitung: 10.06.2024

      Keywords:

      Es gibt ja ca 40.000 Oracle Fehlermeldungen, die vermutlich keiner auswendig kennt. Aber dafür hat ja man die Datenbank, denn die kennt natürlich alle Ihre Fehlertexte.

      Die Fehlerfunktion sqlerrm kann mit einem Parameter (der Fehlernummer) aufgerufen werden. Leider klappt das nur in einem PL/SQL Kontext. 
      Aber kein Problem mittels der WITH Klausel kann in SQL auch eine PL/SQL Funktion ausgeführt werden (es ist noch nicht mal das Recht CREATE PROCEDURE) notwendig.

      Also wenn man z.B- die ersten 1000 Oracle Fehlertexte ausgeben möchte, kann man folgene SQL Query ausführen.

      WITH FUNCTION get_err_text(id IN NUMBER) RETURN VARCHAR2 IS
      BEGIN
      return (sqlerrm(id));
      END;
      SELECT get_err_text(-1*rownum) FROM dual
      CONNECT BY LEVEL<1000;

       

      Alternativ kann auch ein spezieller Bereich (hier von ORA-1000 bis ORA-1100) angezeigt werden:

      WITH
      FUNCTION get_err_text(id IN NUMBER) RETURN VARCHAR2 IS
      BEGIN
      return (sqlerrm(id));
      END;
      err_msg as (SELECT rownum as err_id FROM dual CONNECT BY LEVEL<100000)
      SELECT get_err_text(-1*err_id) FROM err_msg
      WHERE err_id between 1000 and 1100;

       

      Wer interesse hat,mehr über die Fehlerbehandlung in Oracle zu erfahren, besucht einfach unseren PL/SQL Grundlagen-Kurs



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      SYSAUX Tablespace verkleinern / reorganisieren

      Bereich:DBA, Version: ab RDBMS 19.3:RDBMS 21.1:RDBMS 23.1, Letzte Überarbeitung: 16.07.2024

      Keywords:SYSAUX Tablespace verkleinern

      Wir hatten letzte Woche das Problem, dass unsere Oracle 23ai FREE Version an ihr Speicherlimit von 12GB (ORA-12954 The request exceeds the maximum allowed database size of 12 GB.) gekommen ist. 
      Obwohl wir nur Daten mit maximal 1 GB besitzen, wollte die FREE Edition uns partout keinen Speicherplatz mehr gönnen.

      Was war passiert ? Der SYSAUX Tablespace hatte in der CDB 3.5 GB und in der PDB bereits 4 GB erreicht. Obwohl in beiden Tablespace mindestens 2GB frei waren!
      Diesen Speicher zählt Oracle also mit in die 12 GB hinein. Gut kein Problem, dachten wir, dann verkleinern wir den SYSAUX Tablespace halt…

      …Honey i shrunk the SYSAUX Tablespace…


      Daraus ist dieser BLOG Eintrag entstanden und viiiiiiel internes Fachwissen, welche Objekte mit Samthandschuhen angefasst werden möchten.

      Offiziell sind viele dieser Tipps hier auf der Seite “not supported” von Oracle. Das Ganze also bitte nur auf Test-Datenbanken durchführen. Wir haben es zwar auf zwei unserer Produktiv-Datenbanken erfolgreich durchgeführt, trotzdem können 
      wir leider keine Garantie auf die Funktionsweise geben !

      Was ist das Problem des SYSAUX Tablespace?

      1. Er wächst und wächst und wächst. In der freien Wildbahn wurden auch schon Exemplare mit mehr als 70GB gesichtet
      2. Viele der Statistik Tabellen bewahren die Daten zu lange auf
      3. Bei einer Reorg der Objekte im gleichen Tablespace, werden häufig nicht die “vordersten” Bereiche in der Datei wiederverwendet

      Lösungen:

      1. Einen Scratch Tablespace erstellen, auf dem die Objekte, die weiter hinten im SYSAUX Tablespace liegen, kurzfristig verlagert werden können
      2. Aufräumen von unnötigen Daten im Tablespace

      Wenn Sie vorab wissen möchten welche Verwaltungstabellen welche Anzahl an Zeilen besitzt, können Sie eine Statistik darauf laufen lassen ( Dauerte bei uns ca 8 Min ! )

      exec dbms_stats.gather_fixed_objects_stats(degree=>8);
      exec dbms_stats.gather_dictionary_stats(degree=>8);
      1. Mülleimer leeren
      PURGE dba_recyclebin;

      2. Plugin Violations Tabelle für CDB und alle PDBs leeren

      exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'PDB$SEED' );
      exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'CDB$ROOT' );
      …
      exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'MY_PDB1' );

       

      3. Kompletten Audit löschen (Achtung vorher evtl. eine Kopie von UNIFIED_AUDIT_TRAIL machen) und den Audit auf anderen Tablespace verschieben
      Achtung es dauert einen Tag bis das Wirkung zeigt. Diesen Schritt also evtl. schon einen Tag vorab laufen lassen

      BEGIN
      dbms_audit_mgmt.clean_audit_trail(audit_trail_type=>
      dbms_audit_mgmt.audit_trail_unified
      ,use_last_arch_timestamp=>FALSE);
      END;
      /
      
      BEGIN
      DBMS_AUDIT_MGMT.ALTER_PARTITION_INTERVAL(
      interval_number => 1,
      interval_frequency => 'DAY');
      END;
      /
      
      BEGIN
      DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_LOCATION( audit_trail_type =>
      DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,
      audit_trail_location_value =>'SYSAUX_SCRATCH');
      END;
      /

       

      4. Alle alten Statistiken löschen (da wird eine Menge Platz wieder frei im SYSAUX Tablespace)

      BEGIN 
      dbms_stats.purge_stats(dbms_stats.purge_all);
      END;
      /
      BEGIN 
      dbms_stats.reset_col_usage (null,null);
      END;
      /

       

      5. Komplette ADDM Statistiken löschen (damit hat Ihre DB die gleichen “Probleme”, als wenn Sie ganz frisch aufgesetzt wurde (sie hat keine Statistiken)

      Sie können natürlich die letzten 2 Snapshots noch behalten (Infos dazu stehen in DBA_HIST_SNAPSHOTS)

      REM Note 2660128.1

      EXEC dbms_workload_repository.drop_snapshot_range(1,999999999); -- 10min
      exec prvt_advisor.delete_expired_tasks;
      WITH FUNCTION do_ddl (cmd IN VARCHAR2)
      RETURN VARCHAR2
      IS
      PRAGMA AUTONOMOUS_TRANSACTION; -- Damit ist die Funktion eigenständig und beeinflusst niemanden :-)
      v_cmd VARCHAR2(32000);
      BEGIN
      v_cmd:=rtrim(cmd,';'); -- Semmikolon ggf.herausfiltern
          BEGIN
          EXECUTE IMMEDIATE v_cmd; -- Befehl ausführen
          EXCEPTION WHEN OTHERS THEN
          IF sqlcode=-65040 THEN
              BEGIN
              dbms_pdb.exec_as_oracle_script(v_cmd);
              EXCEPTION WHEN OTHERS THEN
                  RETURN v_cmd||' --'||sqlerrm;
              END;    
          ELSE RAISE;
          END IF;
          END;
      RETURN v_cmd||'; --OK'; -- Befehl erfolgreich ausgeführt
      EXCEPTION WHEN OTHERS THEN
      RETURN v_cmd||' --'||sqlerrm;
      END;
      select 'ALTER TABLE WRI$_ADV_OBJECTS MOVE' FROM dual
      UNION ALL
      select 'ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD' FROM dual
      UNION ALL
      select 'ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD' FROM dual
      UNION ALL
      select 'ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD' FROM dual
      /

      6. OATS Oracle Active Tracking System (ab 21c):

      Ist auch ein großer Platzfresser. Wir räumen (durch Löschen) alles auf. (Wir waren vor Version 21c  ja auch glücklich mit unserer DB ohne dieses Feature :-) )

      WITH FUNCTION del_oats (del_time date) RETURN varchar2 IS
      PRAGMA AUTONOMOUS_TRANSACTION;
      BEGIN
      IF dbms_activity.delete_snapshots(del_time) THEN RETURN 'OATS deleted';
      ELSE RETURN 'OATS not deleted';
      END IF;
      END;
      SELECT del_oats(sysdate-1/96) FROM dual;

      7.  Scheduler Logs aufräumen:

      exec DBMS_SCHEDULER.PURGE_LOG;
      exec DBMS_SCHEDULER.PURGE_LOG(0,which_log=>'WINDOW_LOG');

      8. Weitere Spezialfälle besprechen wir in unserer Schulung Reorg und Wartung oder im DBA II Kurs :-)

      Nun kommen wir zum interessanten Teil: Verschieben der hinteren Objekte in den Scratch Tablespace

      Der folgende Select erzeugt Ihnen ein Skript, mit dem sich ca. 95% der Objekte verschieben lassen.

      WITH
      S as (select 1000 as block_id, – Nur Objekte hinter Block Nummer 1000 verschieben 
      3 as file_id,'SYSAUX_SCRATCH' as scratch_tbs,  – Name des Scratch Tablespace für die Objekte
      'ONLINE' as on_off_mode – Für SE2 Benutzer bitte Spalte auf ‘’ setzen
      FROM dual),
      db as (select count(*) as is_pdb  from v$pdbs)
      SELECT  CASE-- ## T A B L E und I N D E X  P A R T I T I O N ##
      WHEN  db.is_pdb=1 THEN  'exec dbms_pdb.exec_as_oracle_script(''' END||
      CASE WHEN segment_type  IN ('INDEX PARTITION','TABLE PARTITION') and e.segment_name not like 'SYS_IL0%' THEN
      'ALTER ' || substr(e.segment_type,1,5)||' "' || owner || '"."' || e.segment_name || '"' ||
      CASE segment_type WHEN 'INDEX PARTITION' THEN 
      ' REBUILD PARTITION "' ELSE ' MOVE PARTITION "' END || partition_name|| '" '||
      CASE WHEN e.segment_name NOT LIKE 'WRH$%' 
      AND  e.segment_name NOT LIKE 'WRM$%'  
      AND e.segment_name NOT IN 
      ('ACTIVITY_TABLE$' ,'WRI$_OPTSTAT_HISTGRM_HISTORY' ,'SCHEDULER$_EVENT_LOG','UMF$_ATSK_HIST_MXDB_MXSN','SCHEDULER$_JOB_RUN_DETAILS') THEN 
      s.on_off_mode END ||' tablespace '||nvl(s.scratch_tbs,e.tablespace_name)
      WHEN segment_type IN ('TABLE','INDEX') THEN -- ###### T A B L E und I N D E X ######
      'ALTER '||e.segment_type||' "'||owner||'"."'||e.segment_name||'"'||
      CASE segment_TYPE
      WHEN 'TABLE' THEN ' MOVE ' || s.on_off_mode ||' TABLESPACE '||nvl(s.scratch_tbs,e.tablespace_name) 
      ELSE ' REBUILD ' || s.on_off_mode ||' TABLESPACE '||nvl(s.scratch_tbs,e.tablespace_name) END
      WHEN  segment_type IN ('LOBSEGMENT','LOB PARTITION') THEN -- ###### L O B ######
      'ALTER TABLE "'||e.owner||'"."'||(select table_name 
      FROM dba_lobs l where l.segment_name=e.segment_name)||'" MOVE LOB ("'||
      (select column_name FROM dba_lobs l where l.segment_name=e.segment_name)||'") STORE AS (tablespace "'||
      nvl(s.scratch_tbs,e.tablespace_name) ||'")' END||
      CASE WHEN db.is_pdb=1 THEN ''');--' ELSE ';'   END as sql_cmd
      FROM s,db,dba_extents e
      where e.file_id=s.file_id
      and e.block_id>s.block_id
      ORDER BY e.block_id desc;

      Da werden jetzt einige Objekte sich beschweren, dass Sie nicht verschiebbar sind (z.B. auch als SYS die Fehlermeldung ORA-01031 Insufficient Privileges)
      Wir haben eine Lösung dafür gefunden die aber sicher nicht supported ist, weil damit den Schutz auf sensible Spalten in den Tabellen auch ausschalten wird.

       

      Zu guter Letzt, werden noch die Objekte repariert, die den Status INVALID aufweisen:

      WITH FUNCTION do_ddl (cmd IN VARCHAR2)
      RETURN VARCHAR2
      IS
      PRAGMA AUTONOMOUS_TRANSACTION; -- Damit ist die Funktion eigenständig und beeinflusst niemanden :-)
      v_cmd VARCHAR2(32000);
      BEGIN
      v_cmd:=rtrim(cmd,';'); -- Semmikolon ggf.herausfiltern
      EXECUTE IMMEDIATE v_cmd; -- Befehl ausführen
      RETURN v_cmd||'; --OK'; -- Befehl erfolgreich ausgeführt
      EXCEPTION WHEN OTHERS THEN
      RETURN v_cmd||' --'||sqlerrm;
      END;
      SELECT do_ddl('ALTER INDEX "'||owner||'"."'||index_name||'" REBUILD;')
      FROM dba_indexes i 
      WHERE status='UNUSABLE'
      UNION ALL
      SELECT do_ddl('ALTER INDEX  "'||index_owner||'"."'||index_name||'" REBUILD PARTITION "'||partition_name||'";')
      FROM dba_ind_partitions
      WHERE status='UNUSABLE'
      UNION ALL
      select 'ALTER '|| CASE WHEN object_type='PACKAGE BODY' THEN 'PACKAGE' ELSE object_type END  
      ||' "'|| owner ||'"."'|| object_name ||'" COMPILE ' ||
      CASE WHEN object_type='PACKAGE BODY' THEN 'BODY;' ELSE ';' END as sql_stmt
      from dba_objects
      where object_type in 
      ('PROCEDURE','FUNCTION','PACKAGE','PACKAGE BODY','VIEW')
      and status='INVALID';

      Mehr Informationen erhalten Sie in einem unserer Oracle Reorg und DBA II Kurse, oder wir kommen zu Ihnen und räumen den SYSAUX Tablespace persönlich auf.
      Melden Sie sich gerne bei uns und holen Sie ein Angebot ein. Wir freuen uns auf Sie.
       

       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Listener Info mittels SQL auswerten (External Table)

      Bereich:DBA, Version: ab RDBMS 23.1, Letzte Überarbeitung: 09.08.2024

      Keywords:Listener durch External Table

      Im Gespräch mit einem Oracle Mitarbeiter letztes Jahr kam die Idee auf, warum Oracle keinen Select bietet, um den den Stand des Listeners abzufragen. 

      Der Mitarbeiter (nennen wir ihn mal Sebastian S. :-) ) wollte die Idee ins Development bringen. Bis das umgesetzt ist, helfen wir uns selbst:

      Unter Linux legen wir uns eine kleine Shell Script Datei an

      vi /home/oracle/scripts/lsnr_status.sh
      #!/bin/bash
      ORACLE_HOME=/opt/oracle/product/23c/dbhomeFree
      $ORACLE_HOME/bin/lsnrctl status | /usr/bin/awk '
      BEGIN { OFS=","; print "LINE"}
      { print $0 }'

      Und geben dieser Datei Ausführungsrechte:

      chmod +x /home/oracle/scripts/lsnr_status.sh

      Dann brauchen wir ein Datenbank Directory auf diesen Ordner:

      CREATE DIRECTORY ext_tab_dir AS '/home/oracle/scripts';
      grant read,execute on directory ext_tab_dir to muniq;

      Seit Version 19c kann eine External Table ohne ein Create direct “On the Fly” erzeugt werden:

      SELECT * FROM EXTERNAL (
      ( line varchar2(2000))
       TYPE oracle_loader
       DEFAULT DIRECTORY ext_tab_dir
       ACCESS PARAMETERS (
         RECORDS DELIMITED BY NEWLINE
          PREPROCESSOR ext_tab_dir:'lsnr_status.sh'
         FIELDS CSV WITH EMBEDDED TERMINATED BY ';' 
         OPTIONALLY ENCLOSED BY '"'
         MISSING FIELD VALUES ARE NULL )
       LOCATION ('lsnr_status.sh')
       REJECT LIMIT UNLIMITED ) inline_ext_tab;

      Bei älteren Versionen legt man halt zuesrt die Tabelle an:

      CREATE TABLE ext_listener_status (
          line VARCHAR2(4000)
        )
        ORGANIZATION EXTERNAL (
          TYPE ORACLE_LOADER
          DEFAULT DIRECTORY ext_tab_dir
          ACCESS PARAMETERS (
            RECORDS DELIMITED BY NEWLINE
            --PREPROCESSOR ext_tab_dir:'lsnr_status.sh'
            FIELDS TERMINATED BY ','
            MISSING FIELD VALUES ARE NULL
            ( line )
          )
          LOCATION ('lsnr.info')
        );
      SELECT * FROM ext_listener_status;

      Das war es schon, jetzt können Sie den Listener Zustand auch innerhalb der Datenbabnk abfragen (also via SQL*Plus, SQL cl, SQL Developer oder TOAD, oder …)



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Globale Suche in APEX

      Bereich:APEX, Version: ab APEX 23.2, Letzte Überarbeitung: 18.08.2024

      Keywords:Globale Suche

      Wir verwenden für unsere Webseite Oracle 23ai mit APEX 24.1.x (Stand August 2024). Leider funktioniert die Globale Suche dort nicht mehr und die Anfrage stürzt ab mit Webserver Internal Server Fehler 500.

      Deswegen haben wir uns eine eigene Suche geschrieben, die kann nur leider nicht direkt auf die Komponente verlinken, aber durchsucht dafür alle APEX Tabellen !

      CREATE OR REPLACE TYPE apex_search_type 
              AS OBJECT (
              app_id         NUMBER, 
              page_id     NUMBER, 
              row_text     CLOB, 
              tab_name    VARCHAR2(128),
              col_name     VARCHAR2(128),
              row_id         VARCHAR2(32));
              /

       

      CREATE OR REPLACE FUNCTION  muso_apex_search
              (p_app_id IN NUMBER DEFAULT 0, p_search_string IN VARCHAR2)
              RETURN  apex_search_tab_type PIPELINED IS
              TYPE    ref_curs_type IS REF CURSOR;  
              refc    ref_curs_type;
              str             VARCHAR2(2001);  
              ret_rowid    ROWID;  
              ret_col         CLOB;
              v_schema VARCHAR2(128);
              v_flow_id   VARCHAR2(64);
              v_page_id   VARCHAR2(128);
              BEGIN
                  SELECT schema 
                      INTO v_schema
                  FROM dba_registry WHERE comp_id='APEX';
              FOR rec IN (select table_name,column_name,data_type
                      FROM sys.all_tab_columns dtc, all_objects do
                      WHERE dtc.table_name=do.object_name and
                    do.object_type='TABLE' and dtc.owner=v_schema) 
                     LOOP
                    
                     v_flow_Id:='';
                     v_page_id:='';
                     FOR c_flow IN (SELECT column_name FROM all_tab_columns 
                         WHERE owner=v_schema AND table_name=rec.table_name 
                         AND column_name IN('FLOW_ID','PAGE_ID' ) ) 
                          LOOP
                         IF c_flow.column_name='FLOW_ID' THEN
                             v_flow_id:=',flow_id';
                         ELSIF c_flow.column_name='PAGE_ID' THEN
                              v_page_id:=',page_id';
                         END IF;
                    END LOOP;
                      IF rec.data_type IN( 'CHAR','VARCHAR2','CLOB') THEN
                          str:= 'SELECT rowid,'||rec.column_name||nvl(v_flow_id,',null as flow_id')||nvl(v_page_id,',null as page_id')||
                         ' FROM '||v_schema||'.'||rec.table_name||    
                          ' WHERE '||rec.column_name||' like '||chr(39)||'%'||p_search_string||'%'||chr(39);
                          BEGIN
                               OPEN refc FOR str;
                          LOOP         
                          FETCH refc 
                          INTO ret_rowid,ret_col,v_flow_id,v_page_id;  
                             EXIT WHEN refc%NOTFOUND;         
                             If nvl(p_app_id,v_flow_id)=v_flow_ID THEN
                                 PIPE ROW (apex_search_type(v_flow_id,v_page_id,ret_col,v_schema||'.'||rec.table_name,rec.column_name,ret_rowid));   
                             END IF;
                          END LOOP;  
                               ret_rowid:='';   
                             ret_col:='';  
                          CLOSE refc;
                               EXCEPTION WHEN OTHERS THEN
                    PIPE ROW (apex_search_type(0,0,'Fehler:'||sqlerrm||' =>'||str,rec.table_name,null,null));
                   END;
                      END IF;
              END LOOP;
              END;
              /
              
      • Jetzt können Sie Ihre globale Suche beginnen. Wir brauchen bis zu zwei Parameter:
        App ID: ist nicht Pflicht, wenn es leergelassen wird, findet die Suche in allen APPs (auch den internen !) statt
      • Der Suchstring: Dieser ist natürlich Pflicht
      select * from table(muso_apex_search(11000,'Sitemap') );

      Weitere tolle Tipps bekommen Sie in einem von unseren 6 APEX Kursen ! Wir freuen uns auf Sie !



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Suche nach Bildern und Links in einer APEX Seite

      Bereich:APEX, Version: ab APEX 23.2, Letzte Überarbeitung: 19.08.2024

      Keywords:

      Wollten Sie immer schon mal wissen, welche BIlder in Ihrer Seite vorkommen? Wenn man das über die APEX Tabellen lösen möchte wird es schwierig, denn davon gibt es fast 600.

      Wir verwenden deswegen einen anderen Ansatz: Wir rendern die Seite und suchen dann nach Links oder Bildern.

      Geben Sie dazu im Kopf des SQL Statements die Werte für die Application ID (hier 100

      Bilder in einer Seite finden:

      WITH my_app as  (select 100 as app_id, 1 as page_id FROM dual)
      SELECT my_app.app_id,my_app.page_id,replace(column_value,'/','/') img FROM TABLE (
      SELECT APEX_STRING.GREP(page, '<img src[^>]*','i')as bilder FROM (
      select apex_web_service.make_rest_request(
      p_url=>'https://www.muniqsoft-training.de/ords/oracle/r/muso_training/schulung/'||page_alias,
      p_http_method=>'GET',
      p_wallet_path=>'file:///opt/oracle/admin/FREE/https_wallet'
      ) as page 
      from  apex_application_pages app,my_app
      where app.application_id=my_app.app_id
      and app.page_id =my_app.page_id)),my_app
      /

      Links in einer Seite finden:

      WITH my_app as  (select 100 as app_id, 1 as page_id FROM dual)
      SELECT my_app.app_id,my_app.page_id,replace(column_value,'/','/') link FROM TABLE (
      SELECT APEX_STRING.GREP(page, '<a href=*[^>]*">[[:alnum:] ]{1,}<\/a>' ,'i')as bilder FROM (
      select apex_web_service.make_rest_request(
      p_url=>'https://www.muniqsoft-training.de/ords/oracle/r/muso_training/schulung/'||page_alias,
      p_http_method=>'GET',
      p_wallet_path=>'file:///opt/oracle/admin/FREE/https_wallet'
      ) as page 
      from  apex_application_pages app,my_app
      where app.application_id=my_app.app_id
      and app.page_id =my_app.page_id)),my_app;

      Weitere Tipps erfahren Sie in unserem APEX Kurs



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle Constraints nachträglich anlegen

      Bereich:SQL, Version: ab RDBMS 12.x:RDBMS 18.3:RDBMS 19.3:RDBMS 21.1, Letzte Überarbeitung: 08.08.2022

      Keywords:Primary Key, Foreign Key, Not Null

      Wie oft habe ich schon nach der Syntax gesucht um nachträglich einen Constraint auf eine Tabelle zu legen. Google ist ja da immer eine gute Hilfe, aber in deutsch gab es bisher wenig.
      Das ändert sich nun, wir beschätigen uns mit dem Thema Constraints hier nun.

      Nachträglich einen Not Null Constraints auf eine Tabelle legen:

      ALTER TABLE emp MODIFY (ename VARCHAR2(10) CONSTRAINT emp_ename_nn NOT NULL);


      Constraint wieder löschen:

      ALTER TABLE emp DROP CONSTRAINT emp_ename_nn;


      Nachträglich einen Primärschlüssel anlegen (Achtung es darf keiner bisher existieren):

      ALTER TABLE emp ADD CONSTRAINT pk_emp PRIMARY KEY(empno);


      Constraint wieder löschen:

      ALTER TABLE emp DROP CONSTRAINT pk_emp;


      Nachträglich einen Unique Index anlegen (davon dürfen Sie mehrere auf der gleichen Tabelle besitzen)
      Hier erlauben wir pro Tag nur einen Mitarbeiter mit gleichem Nachname einzustellen.

      ALTER TABLE emp ADD CONSTRAINT emp_hiredate_ename_uk UNIQUE KEY(hiredate,ename);


      Constraint wieder löschen:

      ALTER TABLE emp DROP CONSTRAINT emp_hiredate_ename_uk;



      Foreign Key Constraint anlegen. (Dieser hat einen Bezug zu einer lokalen Spalte der Tabelle und eine Verbindung zu einer Spalte einer anderen Tabelle)

      ALTER TABLE emp ADD CONSTRAINT fk_deptno FOREIGN KEY (deptno)
      REFERENCES dept(deptno);


      Der Foreign Key Constraint hat aber noch eine weitere nette Option: On Delete Cascade
      Wenn hier ein Hauptdatensatz (bei uns z.B. die Abteilung) gelöscht wird, werden die Kinddatensätze (hier die Mitarbeiter der Abteilung) auch rekursiv gelöscht

      ALTER TABLE emp ADD CONSTRAINT fk_deptno FOREIGN KEY (deptno)
      REFERENCES dept(deptno) ON DELETE CASCADE;


      Alternativ kann auch nur die abhängige Spalte auf NULL gesetzt werden

      ALTER TABLE emp ADD CONSTRAINT fk_deptno FOREIGN KEY (deptno)
      REFERENCES dept(deptno) ON DELETE SET NULL;


      Constraint wieder löschen:

      ALTER TABLE emp DROP CONSTRAINT fk_deptno;

       
      Sonderfälle
      Constraints können auch verzögert geprüft werden. Das ist dann sinvoll, wenn im Datenmodell mit Constraints Änderungen durchgeführt werden sollen, die gegen die Regeln des Constraint verstossen würden.
      Durch die verzögerte Prüfung erfolgt dies erst beim Commit und nicht schon während der Transaktion.

      ALTER TABLE emp ADD CONSTRAINT fk_deptno FOREIGN KEY (deptno)
      REFERENCES dept(deptno) DEFERRABLE INITIALLY IMMEDIATE;

      Bei der Option DEFERRABLE ENABLE NOVALIDATE  wird bei einem Unique Index ein Non-Unique Index angelegt.
      Sollte ein Index auf den benötigten Spalten bereits vorhanden sein, wird dieser verwendet.

      Danach kann die verzögerte Prüfung in der Session aktiviert werden:
      ALTER SESSION SET CONSTRAINTS = DEFERRED;
      oder wieder zurück auf Default:
      ALTER SESSION SET CONSTRAINTS = IMMEDIATE;

       

      Mit einem ALTER TABLE kann der Zustand der verzögerten Constraints verändert werden:

      • ENABLE VALIDATE   entspricht dem ENABLE. Der Constraint wird für alle Zeilen geprüft
      • ENABLE NOVALIDATE  hier werden nur neue Zeilen geprüft, bereits existierende Zeilen können gegen den Constraint verstossen:
        Oracle muss hier einen Non-Unique Index anlegen, weil ja evtl Doubletten bereits vorhanden sind.
      • DISABLE NOVALIDATE  entspricht dem Zustand DISABLE. Der Constraint wird nicht geprüft und damit kann es Daten geben, die gegen die Constraint Regel verstossen.
        Bei Unique Constraints wird der dazugehörige Index gelöscht
      • DISABLE VALIDATE bedeutet, dass der Constraint nicht geprüft wird und verbietet Änderungen an den betroffenen Spalten. Sinnvoll bei einem Exchange Parition Vorgng im DWH.
        Bei Unique Constraints wird der dazugehörige Index gelöscht
       

       

       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle ORDS 22.x-25.x Installation und Fehlerbehebung / ORDS Troubleshooting

      Bereich:APEX:ORDS, Version: ab ORDS 23.1:ORDS 23.2:ORDS 24.2:ORDS 22.2, Letzte Überarbeitung: 04.03.2025

      Keywords:Oracle, ORDS 22.x/23.x/24.x/25.x , Installation

      Seit einiger Zeit  ist die neue Oracle ORDS Version 23.x zum Download verfügbar. 
      Wie heisst ein berühmtes Zitat: Mann muss in einem System jeden Fehler gemacht haben um das System verstanden zu haben.         
      Na dann sind wir kurz davor alles zu wissen :-) …

      1. Installation
      2. Prüfung im OS
      3. Silent Installation (Unix)
      4. Weitere Datenbank in ORDS eintragen (Unix)
      5. Silent Installation (Win)
      6. Zusätzliche Datenbank in ORDS eintragen (win)
      7. Prüfungen Im Betriebssystem
      8. Prüfungen in der Datenbank
      9. Gängige Fehler des ORDS
      10. Bonustrack: Apex Fehler

      1. Installation

      Laden Sie die Software von Oracle herunter und packen Sie das ZIP File in einem eigenen Ordner aus.      

       

      2. Prüfung im OS

         
      Prüfen Sie nun Ihre installierte Java Version:

      Unix / Linux

      java --version
          java 11.0.16.1 2022-08-18 LTS
          Java(TM) SE Runtime Environment 18.9 (build 11.0.16.1+1-LTS-1)
          Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.16.1+1-LTS-1, mixed mode)
                                          

      Das sieht gut aus … OpenJDK wird offiziell von Oracle nicht unterstützt und kann Probleme verursachen! Verwenden Sie Java 11 oder Java 17

      Windows:

      java.exe --version
          openjdk 11 2018-09-25
          OpenJDK Runtime Environment 18.9 (build 11+28)
          OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

      Das ist schlecht, weil Oracle unterstützt wie gesagt keine Java OpenJDK Version. KEINE !         
      Es kann funktionieren, bei uns trat meist ein Webserver Fehler 500 auf (ohne große Begründung)         
      Unterstützt werden nur die Oracle Java Versionen 11 und 17.

      Nach erfolgreicher Installation der Oracle Java Version gehen Sie in den ausgepackten Ordner (z.B. cd c:\temp\ords)

      Dort sollte ein “bin” Ordner liegen und da drin eine ords.exe und eine ords Datei

      Tragen Sie Java in Ihren Pfad ein:

      Windows:

      set PATH=%PATH%;"C:\Program Files\Java\jdk-11\bin"

      UNIX:

      export PATH=$PATH:/usr/bin/

      Wenn Java in Ihrem Pfad eingetragen wurde, starten Sie die Installation mit:

      Windows:
          bin/ords.exe --config c:\oracle\ords install

      Tipp: Sie sollten auch nach der Installation des Ords das “bin” Verzeichnis des ORDS und die Datei ords.war nicht wegwerfen. Für nachtägliche Wartungsarbeiten benötigt man die Dateien eventuell nochmal. 
      Sie können die Dateien z.B in den Hauptordner des Config-Verzeichnisses kopieren, also z.B. C:\oracle\ords für Windows, oder /opt/oracle für Linux.

      Ab ORDS Version 22.2.x wird der Pfad für den Config Ordner beim Tomcat unter UNIX im Service File eingetragen:

      cat /etc/systemd/system/tomcat.service:

      …
          Environment="JAVA_HOME=/usr/lib/jvm/jre"
          Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords"
      …

       

      Windows (wird im Tomcat (tomcat9w.exe) Eigenschaftsfenster Reiter “Java” im Bereich “Java Options” (nicht “Java 9 Options” !!!) eingetragen)

      -Dconfig.url=c:\oracle\ords

      Unix/Linux:

       bin/ords --config /opt/oracle/ords install

      Interaktion mit dem Skript:

      # bin/ords --config /opt/oracle/ords install
          ORDS: Release 23.4 Produktion am Mi. Dez 15 06:49:08 2023
          Copyright (c) 2010, 2023, Oracle.
          Konfiguration:/opt/oracle/ords/
          Der Konfigurationsordner /opt/oracle/ords enthält keine Konfigurationsdateien.
          Oracle REST Data Services - Interaktive Installation
          Geben Sie eine Zahl zur Auswahl des Installationstyps ein
          [1] ORDS nur in der Datenbank installieren oder upgraden
          [2] Datenbankpool erstellen oder aktualisieren und ORDS in der Datenbank installieren/upgraden
          [3] Nur Datenbankpool erstellen oder aktualisieren
          Choose [2]:
          Geben Sie eine Zahl zur Auswahl des zu verwendenden Datenbankverbindungstyps ein
          [1] Basis (Hostname, Port, Servicename)
          [2] TNS (TNS-Alias, TNS-Verzeichnis)
          [3] Benutzerdefinierte Datenbank-URL
          Choose [1]:
          Geben Sie den Hostnamen der Datenbank ein [localhost]: 172.30.30.141
          Listener-Port der Datenbank eingeben [1521]:
          Datenbankservicename eingeben [orcl]: apex222
          Geben Sie einen Datenbankbenutzernamen mit Administratorberechtigungen an.
          Geben Sie den Administratorbenutzernamen ein: sys
          Datenbankkennwort für SYS AS SYSDBA eingeben:
          Verbindung zu Datenbankbenutzer: SYS AS SYSDBA URL: jdbc:oracle:thin:@//172.30.30.141:1521/apex222 wird hergestellt
          Informationen werden abgerufen.
          Geben Sie den Default Tablespace für ORDS_METADATA und ORDS_PUBLIC_USER ein [SYSAUX]:
          Geben Sie den Temporary Tablespace für ORDS_METADATA und ORDS_PUBLIC_USER ein [TEMP]:
          Geben Sie eine Zahl ein, um zusätzliche Features zum Aktivieren auszuwählen:
           [1] Datenbankaktionen (aktiviert alle Features)
           [2] REST-fähige SQL und Datenbank-API
           [3] REST-fähige SQL
           [4] Datenbank-API
           [5] Kein Wert
          Choose [1]:
           Geben Sie eine Zahl zum Konfigurieren und Starten von ORDS im Standalone-Modus ein
           [1] ORDS im Standalone-Modus konfigurieren und starten
           [2] Überspringen
           Choose [1]: 2
           …
           INFO: 08:19:07 Validating objects for Oracle REST Data Services.
           VALIDATION: 08:19:07 Starting validation for schema: ORDS_METADATA
           VALIDATION: 08:19:07 Validating objects
           VALIDATION: 08:19:08 Validating roles granted to ORDS_METADATA and
           ORDS_PUBLIC_USER
           VALIDATION: 08:19:08 Validating ORDS Public Synonyms
           VALIDATION: 08:19:08 Total objects: 306, invalid objects: 0, missing objects: 0
           VALIDATION: 08:19:08     94  INDEX
           VALIDATION: 08:19:08      3  LOB
           VALIDATION: 08:19:08     15  PACKAGE
           VALIDATION: 08:19:08     14  PACKAGE BODY
           VALIDATION: 08:19:08      1  PROCEDURE
           VALIDATION: 08:19:08     52  PUBLIC SYNONYM
           VALIDATION: 08:19:08      1  SEQUENCE
           VALIDATION: 08:19:08     32  TABLE
           VALIDATION: 08:19:08     32  TRIGGER
           VALIDATION: 08:19:08     20  TYPE
           VALIDATION: 08:19:08      6  TYPE BODY
           VALIDATION: 08:19:08     36  VIEW
           VALIDATION: 08:19:08 Validation completed.
           INFO: 08:19:08 Completed validation for Oracle REST Data Services.
           PL/SQL-Prozedur erfolgreich abgeschlossen.
           Commit abgeschlossen.
           ------------------------------------------------------------
           Containername: APEX222
           Skripts für scheduler werden ausgeführt
           ------------------------------------------------------------
           …
           PL/SQL-Prozedur erfolgreich abgeschlossen.
           Commit abgeschlossen.
           2023-03-15T07:19:15.030Z INFO        Installation für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:27.496
           [*** Informationen: Installation für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:27.496
           ]
           ------------------------------------------------------------
           Containername: APEX222
           ------------------------------------------------------------
           [*** script: ords_configure_gateway.sql]
           Configured PL/SQL Gateway user APEX_PUBLIC_USER to be proxiable from
           ORDS_PUBLIC_USER
           PL/SQL-Prozedur erfolgreich abgeschlossen.
           2023-03-15T07:19:15.130Z INFO        Konfiguration von PL/SQL-Gatewaybenutzer für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.95
           [*** Informationen: Konfiguration von PL/SQL-Gatewaybenutzer für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.95
           ]

      3. Silent Installation (Unix)

      export DB_PORT=1521
          export DB_SERVICE=apex231
          export SYSDBA_USER=SYS
          export SYSDBA_PASSWORD=sys
          export ORDS_PASSWORD=ords
          export ORDS_HOME=/opt/oracle/ords
          export ORDS_CONFIG=/opt/oracle/ords
          export ORDS_LOGS=$ORDS_CONFIG/logs
              export PATH=$PATH:$ORDS_HOME/bin
      ords --config $ORDS_CONFIG install \
          --log-folder $ORDS_LOGS \
          --admin-user $SYSDBA_USER \
          --db-hostname 127.0.0.1 \
          --db-port $DB_PORT \
          --feature-db-api true \ 
          --feature-rest-enabled-sql true \
          --feature-sdw true \
          --gateway-mode proxied \
          --gateway-user APEX_PUBLIC_USER \
          --proxy-user 

      Zugriff dann im Browser via: http:server:8080/ords

      4. oder neue Datenbank bzw. Alias zusätzlich in ORDS (Unix) eintragen:

      ords --config $ORDS_CONFIG install \
          --db-pool $DB_SERVICE \
          --admin-user $SYSDBA_USER \
          --db-hostname 127.0.0.1 \
          --db-port $DB_PORT \
          --db-servicename $DB_SERVICE \
          --feature-db-api true \ 
          --feature-rest-enabled-sql true \
          --feature-sdw true \
          --gateway-mode proxied \
          --gateway-user APEX_PUBLIC_USER \
          --proxy-user 
           Zugriff dann via: http:server:8080/ords/$DB_SERVICE

      5. Silent Installation unter Windows:

      set DB_PORT=1521
          set DB_SERVICE=apex231
          set SYSDBA_USER=SYS
          set SYSDBA_PASSWORD=sys
          set ORDS_PASSWORD=ords
          set ORDS_HOME=c:\oracle\ords
          set ORDS_CONFIG=c:\oracle\ords
          set ORDS_LOGS=%ORDS_CONFIG%\logs
              set PATH=%PATH%;%ORDS_HOME%\bin
      ords --config %ORDS_CONFIG% install ^ 
          --log-folder %ORDS_LOGS% ^
          --admin-user %SYSDBA_USER% ^
          --db-hostname 127.0.0.1 ^
          --db-port %DB_PORT% ^
          --db-servicename %DB_SERVICE% ^
          --feature-db-api true ^
          --feature-rest-enabled-sql true ^
          --feature-sdw true ^
          --gateway-mode proxied ^
          --gateway-user APEX_PUBLIC_USER ^
          --proxy-user 
          

      6. Zusätzliche Datenbank oder Alias in ORDS eintragen (Windows)

      ords --config %ORDS_CONFIG% install ^ 
          --log-folder %ORDS_LOGS% ^
          --db-pool %DB_SERVICE% ^
          --admin-user %SYSDBA_USER% ^
          --db-hostname 127.0.0.1 ^
          --db-port %DB_PORT% ^
          --db-servicename %DB_SERVICE% ^
          --feature-db-api true ^
          --feature-rest-enabled-sql true ^
          --feature-sdw true ^
          --gateway-mode proxied ^
          --gateway-user APEX_PUBLIC_USER ^
              --proxy-user 
          Zugriff dann im Browser via: http:server:80/ords/%DB_SERVICE%
          Hinweis: der Tomcat Dienst benötigt Leserechte im ORDS Config Verzeichnis !!!
          icacls %ORDS_CONFIG% /T /grant Benutzer:R

      7. Prüfung im OS

      Wir oben beschrieben muss die richtige Java Version installiert worden sein (Oracle Java 11 oder 17)         
      Kann der config Ordner von Oracle/Tomcat Benutzer gelesen werden? Wenn nicht bitte Lese/Schreibrechte an die Dateien vergeben.

       

      8. Prüfung in der Datenbank

      Sind alle notwendigen Accounts NICHT gesperrt und stimmt das Passwort ?

      select username,account_status,lock_date,expiry_date
          from dba_users
          where username like '%PUBLIC%';
          USERNAME                 ACCOUNT_STATUS     LOCK_DATE           EXPIRY_DATE        
          ------------------------ ------------------ ------------------- -------------------
          APEX_PUBLIC_USER         LOCKED             15.03.2023 07:57:59                    
          APEX_REST_PUBLIC_USER    OPEN                                   11.09.2024 08:08:32

      Das schaut hier nicht gut aus, der Benutzer APEX_PUBLIC_USER ist gesperrt!.

      Entsperren mittels:

      ALTER USER apex_public_user ACCOUNT UNLOCK IDENTIFIED BY <mein_geheimes_passwort>;

      Danach starten wir dem TomCat nochmal durch.

      Windows:

      net stop TomCat9
      net start TomCat9

      Für den Fall, dass Sie das Passwort vom ORDS_PUBLIC_USER in der DB geändert haben und das im ORDS nachtragen möchten:

      Für den Default Pool: (wenn der Config Ordner unter /opt/oracle/ords liegt)

      ords --config /opt/oracle/ords config --db-pool default secret db.password

      Für einen anderen Pool (hier apex231)

      ords --config /opt/oracle/ords config --db-pool apex231 secret db.password

       

      Fehlermeldung: Benutzer oder Kennwort für den Verbindungspool namens |default|lo| ist ungültig oder abgelaufen, oder der Account wurde gesperrt 

      Die naheliegenden Lösungen wären natürlich:

      • Passwort falsch
      • Account abgelaufen

      aber in unserem Fall war die Datenbank (pluggable Database Container) im restricted Modus:

      Die Lösung war:

      alter pluggable database <containername> close immediate;
      alter pluggable database <containername> open;

       

      Fehlermeldung: Service Unavailable

      ORDS_Fehler_503.jpeg

      HTTP Status Code: 503

      Request ID: bI7hBYBLvXJ1aZXhH61iMA

      Request Timestamp: 2023-10-21T08:58:05.233483445Z

      Das Datenbankkennwort-Secret fehlt in dem mit dem Pool |default|lo| verknüpften Wallet


      Hier fehlt das Passwort für den ORDS_PUBLIC_USER, oder es ist veraltet oder abgelaufen. 
      Die Lösung unter LINUX ist, das Wallet mit dem Passwort neu anzulegen mittels:

      cd /opt/oracle/ords
      REM dort liegt der Ordner bin aus der Installtion des ORDS!, wenn nicht, gehen Sie bitte in den entsprechenden Ordner
      sudo bin/ords --config /opt/oracle/ords config secret db.password
      REM zweimal das Passwort eingeben
      REM wenn Sie noch weitere Pools besitzen, muss auch hier das Passwort geöndert werden (Pool-Name apex231)
      sudo bin/ords --config /opt/oracle/ords config --db-pool apex231 secret db.password
      REM TomCat durchstarten
      sudo systemctl restart tomcat

      Für Windows würde die Lösung so aussehen:

      cd c:\oracle\ords
          bin\ords --config c:\oracle\ords config --db-pool default secret db.password
          bin\ords --config c:\oracle\ords config --db-pool apex241 secret db.password

      Unsere Ordnerstruckur für den Ords sieht wie folgt aus:

      ORDS_Ordner.png

      Fehler 404 DispatcherNotFoundException

      Hier war ein falscher Eintrag in der pool.xml Datei (unter Windows z.B. unter c:\oracle\ords\databases) schuld.

      Der Parameter plsql.gateway.mode muss auf proxied stehen!

      Für Windows:

      set ORDS_HOME=c:\oracle\ords
      set ORDS_CONFIG=c:\oracle\ords
      %ORDS_HOME%\bin\ords --config %ORDS_CONFIG% config set plsql.gateway.mode proxied

      Für Unix

      export ORDS_HOME=/opt/oracle/ords
      export ORDS_CONFIG=/opt/oracle/ords
      $ORDS_HOME/bin/ords --config $ORDS_CONFIG config set plsql.gateway.mode proxied

      Fehler 404 not found

      Im Logfile des Apache TomCat steht nur:

      "GET /ords/wwv_flow.js_messages?p_app_id=4550&p_lang=en&p_version=24.1.5-3518415 HTTP/1.1" 404 451412

      Problem war eine falsche Einstellung in der Datei pool.xml (z.B. unter c:\oracle\ords\databases\default):

      dort musste 

      <entry key="plsql.gateway.mode">disabled</entry>

      durch

      <entry key="plsql.gateway.mode">proxied</entry>

      ersetzt werden.

      10. Bonustrack: Oracle Apex Fehler

      Wir hatten kürzlich das Problem, das keine Applikationen mehr importiert werden konnten. Beim Auswählen der Datei kam im nächsten Schritt die Fehlermeldung, dass keine Datei ausgewählt wurde.

      Das Problem war hier, dass beim Benutzer FLOWS_FILES einige Indizes defekt waren. Nach einem Rebuild war ein Import wieder möglich.

      Der folgende Select schreibt Ihnen ein Skript, um defekte Indizes zu finden und reparieren.

      select 'ALTER INDEX '||owner||'.'||index_name||' REBUILD;' as sql_stmt
      from dba_indexes 
      where (owner='FLOWS_FILES' 
      or owner=(select schema from dba_registry where comp_id='APEX'))
      and status='UNUSABLE';

      Bei der Migration auf einen anderen Server hatten wir plätzlich beim start des Workspace den Fehler:

      Die Anforderung kann nicht verarbeitet werden, da diese Ressource keine Cross Origin Sharing-Anforderungen 
      unterstützt oder da der Anforderungsursprung nicht autorisiert ist, 
      auf diese Ressource zuzugreifen. Wenn ords als Reverse-Proxy verwendet wird, stellen Sie sicher, 
      dass der Frontend-Server den Hostnamen propagiert. 
      Stellen Sie für mod_proxy sicher, dass "ProxyPreserveHost" eingeschaltet ist.
      

      Die Lösung bestand darin in die die Datei /etc/httpd/conf/httpd.conf (bzw. eine Unterdatei z.B. in conf.d) um folgenden Eintrag zu ergänzen:

      RequestHeader unset Origin

       

      Mehr Tipps & Tricks erfahren Sie in unserem Oracle ORDS und im APEX II Kurs. Wir freuen uns auf Sie! 
       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Funktion Return Boolean in SQL Problem lösen

      Bereich:PL/SQL, Version: ab RDBMS 10.x, Letzte Überarbeitung: 26.07.2018

      Keywords:SQL, Boolean, WITH Function

      Haben Sie sich auch schon darüber geärgert, dass gerade Oracle keine Boolean Datentypen in SQL erlaubt?
      Wenn Sie also eine PL/SQL Funktion besitzen, die nur TRUE oder FALSE zurückgibt, muss man sich einen Wrapper in PL/SQL schreiben.

      Aber in unserem Tipp des Monats, bekommen wir das mit einem Trick auch nur in SQL hin.

      Sagen wir mal, wir hätten eine Funktion wie diese hier:

      CREATE OR REPLACE FUNCTION my_bool
      RETURN BOOLEAN IS
      BEGIN
      IF EXTRACT(HOUR FROM cast (systimestamp as timestamp))<=12 RETURN true;
      ELSE RETURN false;
      END IF;
      END;

      Dann könnten wir mit einer einfachen WITH Klausel das auch in reinem SQL hinbekommen.

      WITH
        FUNCTION return_boolean RETURN VARCHAR2 IS
        BEGIN
         IF my_bool THEN
          RETURN 'True';
         ELSE
          RETURN 'False';
        END IF;
        END;
      SELECT return_boolean FROM dual;

       

      Viele weitere Tipps & Tricks bekommen Sie in einem unserer bewährten PL/SQL Kurse (PL/SQL, PL/SQL II, PL/SQL Packages, ...)



      Weitere Interessente Artikel zum Thema:



      Empfohlene Schulungen zum Thema:


      DBMS_OUTPUT umgeleitet

      Bereich:PL/SQL, Version: ab RDBMS 10.x, Letzte Überarbeitung: 23.07.2018

      Keywords:dbms_output, dbms_pipe, htp.p

      Ich liebe das Package dbms_output, wenn es nur nicht ...

      • so einen langen Namen
      • so eine eingeschänkte Bedienung

      hätte.

      Aber den letzen Punkt können wir ändern. In diesem Tipp holen wir die Daten, die wir in den Puffer von dbms_output geschrieben haben und legen Sie woanders hin.

      ##################################################
      Umleitung von dbms_output zu pipe
      ##################################################

      CREATE OR REPLACE PROCEDURE test_ausgabe
      -- Rechte: grant execute on dbms_pipe to scott;
      IS
          PROCEDURE dop2pipe (pipe_name IN VARCHAR2 DEFAULT 'DBMS_OUTPUT_PIPE') IS
             lines dbms_output.chararr;
             num_lines number:=1000000;
          BEGIN
             dbms_output.get_lines(lines, num_lines);
             FOR i IN 1..num_lines LOOP
                  dbms_pipe.pack_message (lines(i));
             END LOOP;
              IF (dbms_pipe.send_message (pipe_name)) <> 0 THEN
                  raise_application_error(-20500,'Fehler beim Senden in Pipe '||pipe_name||' aufgetreten !');
              END IF;
          END;
      BEGIN
         dbms_output.enable(null);  
         FOR i IN 1 .. 10 LOOP
           dbms_output.put_line('Zeile='||i);
         END LOOP;
      dop2pipe;   -- <=######## Umwandelung von dbms_output in Pipe
      END;
      /

      CREATE OR REPLACE PROCEDURE get_dout_from_pipe (pipe_name IN VARCHAR2 DEFAULT 'DBMS_OUTPUT_PIPE')

      IS

           v_message VARCHAR2(32767);

           v_timeout NUMBER:=120;

      BEGIN

           IF (DBMS_PIPE.receive_message(pipe_name,v_timeout)) <> 0 THEN

                RAISE_APPLICATION_ERROR(-20501,'Fehler beim Lesen aus Pipe '||pipe_name||' aufgetreten !');

           END IF;

           LOOP

              EXIT WHEN DBMS_PIPE.NEXT_ITEM_TYPE = 0;

               DBMS_PIPE.unpack_message(v_message);

               DBMS_OUTPUT.PUT_LINE(v_message);

           END LOOP;

      END;

      /

      ##################################################
      Umleitung von dbms_output zu htp
      ##################################################

      
      CREATE OR REPLACE PROCEDURE test_ausgabe
      IS
          PROCEDURE dop2htp IS
             lines dbms_output.chararr;
             num_lines number:=1000000;
          BEGIN
             dbms_output.get_lines(lines, num_lines);
             FOR i IN 1..num_lines LOOP
                htp.p(lines(i)||'<BR>');
             END LOOP;
          END;
      BEGIN
         dbms_output.enable(null);  
         FOR i IN 1 .. 10 LOOP
           dbms_output.put_line('Zeile='||i);
         END LOOP;
      dop2htp;   -- <=######## Umwandelung von dbms_output in htp.p Ausgabe
      END;
      

       

      Ich hoffe dies konnte Ihnen weiterhelfen, bei sonstigen Fragen melden sie sich gerne bei uns und oder besuchen sie einen der Kurse. :-)



      Weitere Interessente Artikel zum Thema:



      Empfohlene Schulungen zum Thema:


      Best Practices für das Datenbank-Audit in Oracle 11g und 12c

      Bereich:DBA, Version: ab RDBMS 11.x, Letzte Überarbeitung: 19.05.2022

      Keywords:Vorträge, DBA

      Firmen, die mit personenbezogenen Daten arbeiten, sind gesetzlich zum Audit verpflichtet. In der Praxis sieht das allerdings häufig so aus, dass man im Vertrauen darauf, dass die Default-Audit Einstellungen von Oracle schon alles Wesentliche abdecken werden, die Inhalte der Audit-Trails eine bestimmte Zeit aufhebt und dann löscht oder irgendwohin exportiert, ohne jemals einen Blick auf den Inhalt geworfen zu haben.

      Und wenn ein entnervter DBA unter Oracle 11g kurz nachsehen will, welcher xxxxx an den Datenbankparametern gedreht hat und es wieder mal keiner gewesen sein will, wird er im Audit-Trail der Datenbank vergeblich danach suchen, selbst wenn er den Parameter AUDIT_SYS_OPERATIONS auf TRUE gesetzt hat. Unter Linux müsste er dazu unzählige aud-Files im Betriebssystem und unter Windows das Eventlog durchforsten.

      Um wirklich das auditiert zu bekommen, was man gerne hätte und die Auswertung nicht allzu zeitraubend zu gestalten, muss man die Audit-Einstellungen und das Housekeeping der Daten manuell einrichten und testen. Auch die Übertragung eines fertigen 11g-Audit-Konzepts auf Oracle 12c ist eine Menge Arbeit. Dieser Vortrag beschäftigt sich anhand eines fiktiven, aber nicht untypischen Szenarios mit den Schwachstellen der Default-Audit-Konfiguration in Version 11g und 12c und stellt Lösungsansätze für das Audit vor, mit denen man die Erfassung der Daten und die Auswertung vereinfachen kann.

      AUSGANGSLAGE FÜR DAS AUDIT-SZENARIO
      Der neue, motivierte und experimentierfreudige DBA einer mittelständischen Firma soll ein neues Audit-Konzept umsetzen. Im Einsatz sind Oracle-Datenbanken der Version 11.2.0.4 (Standard Edition One) auf Linux und auf Windows. Alle Angestellten der Firma loggen sich unter dem selben Account , aber von unterschiedlichen Rechnern aus ein und können entweder direkt (über SQL Developer) oder über ein APEX-Interface auf die Tabellen zugreifen. Der DBA-Kollege nutzt manchmal auch den Enterprise Manager. Die DBAs arbeiten als SYSDBA auf der Instanz, alle anderen haben die Rollen CONNECT und RESOURCE.

      Auditiert werden sollen:

      • Änderungen (DML) an der Tabelle Kundendaten im Schema KUNDEN
      • DROP oder TRUNCATE-Vorgänge an Tabellen im Schema KUNDEN
      • Änderungen am PL/SQL-Code im Schema KUNDEN
      • fehlgeschlagene Login-Versuche
      • Für einen begrenzten Zeitraum alle Aktionen des neuen Werkstudenten, der eine neue Applikationin einem eigenen Schema (mit vollem Zugriff auf das Kundenschema) entwickeln soll.
      • Alle Aktionen des externen Consultants, der sich ebenfalls als SYSDBA auf der Instanz einloggt.
      • Stop, Starts, Änderungen an Parametern und Datenbankdateien
      • Rechte-Vergabe bzw. Entzug 

      Weitere Forderungen

      • Bis jetzt wurde die Tabelle aud$ einmal pro Woche über einen DBMS_JOB-Aufruf geleert. In Zukunft sollen die Daten 120 Tage aufbewahrt und "zeitnah" ausgewertet werden.
      • Alle Audit-Einträge sollen über eine zentrale View selektierbar sein, um die Auswertung zu erleichtern.
      • Das Audit soll mit möglichst wenig Aufwand (bzw. Kosten) einzurichten sein.
      • Es soll sowohl für Windows- als auch für Linux-Datenbanken umsetzbar sein und möglichst keine zusätzlichen Shell- oder Batch-Skripte für das Housekeeping etc. erfordern.

      PROBLEME BEI EINRICHTUNG, AUSWERTUNG UND HOUSEKEEPING DES AUDITS UNTER 11G

      Gewöhnungsbedürftige Syntax für das Einrichten der Audit-Optionen
      Von den oben geforderten Audits wird nur ein kleiner Teil über die Default-Einstellungen abgedeckt. Es ist also viel Handarbeit nötig, wobei die Syntax der AUDIT-Anweisung einige Fallstricke enthält.
      So kann z.B. ein unvorsichtiges SELECT TABLE BY <username> den Audit-Trail exponentiell aufblasen, wenn man ein Tool wie den SQL Developer benutzt.

      Überflüssige Informationen im Audit-Trail
      Wenn man den Enterprise Manager konfiguriert hat, der sich im Sekundentakt bei der Datenbank anmeldet, führen die Default-Einstellungen dazu, dass der Audit-Trail größtenteils mit den Logon- und Logoff-Einträgen der User SYSMAN und DBNSMP gefüllt wird. Beim SYS-Auditing werden unter 11g alle Statements aufgezeichnet. Hier muss man den Overhead der Data-Dictionary-Zugriffe (recursive SQL) beim Auswerten herausfiltern. Auch der RMAN erzeugt eine Flut von Einträgen, wenn er sich als SYSDBA anmeldet.


      Unterschiedliche Speicherorte der verschiedenen Audit-Informationen
      Connects als SYSDBA bzw. SYSOPER, Stops und Starts der Datenbank werden per default auditiert (mandatory auditing). Alle weiteren Aktionen des Users SYS können durch Umstellung des Parameters AUDIT_SYS_OPERATIONS auf TRUE auditiert werden. Unter Unix werden die Informationen jedoch in das durch den Parameter audit_file_dest angegebene Verzeichnis geschrieben, unter Windows ins Eventlog. Um dieses Audit auswerten zu können, müsste man die Inhalte der *.aud-Files unter Linux bzw. die Oracle-spezifischen Inhalte des Eventlogs unter Windows parsen und in die Datenbank laden. Beides ist möglich, aber aufwendig.


      Unzulänglichkeiten des Packages DBMS_AUDIT_MGMT
      Das Package DBMS_AUDIT_MGMT ist umständlich zu bedienen, vor allem, wenn man sowohl in der Datenbank als auch im Filesystem aufräumen will. Um die Einträge im Windows Event Log muss man sich selber kümmern.


      VORSCHLAG FÜR EIN "UNIFIED AUDITING" ab 11G
      Wenn man den Parameter AUDIT_TRAIL auf XML setzt, werden alle zu auditierenden Statements des Standard, Mandatory, SYS- und Fine Grained Auditing (letzteres natürlich nur in der Enterprise Edition) im AUDIT-FILE-DEST-Verzeichnis als XML-Files gespeichert und können über die View V$XML_AUDIT_TRAIL gemeinsam ausgewertet werden, ähnlich wie die XML-Files des Alert.logs über die View V$DIAG_ALERT_EXT. Die seit der Oracle-Version 10.2 verfügbare View DBA_COMMON_AUDIT_TRAIL vereint diese Einträge mit denen aus DBA_AUDIT_TRAIL und DBA_FGA_AUDIT_TRAIL, so dass auch die Inhalte der Tabellen AUD$ und FGA_LOG$ noch sichtbar bleiben. Diese Lösung kann man durchaus als abgespecktes "Unified Auditing" für 11g bezeichnen. Die Auswertung und das Housekeeping werden dadurch wesentlich erleichtert. Auch die Performance des Audits leidet nicht darunter, dass man die Audit-Files im Betriebssystem speichert , eher im Gegenteil. Wenn man den XML-Audit-Trail vor Zugriffen durch übel gesinnte DBAs schützen will, muss man dafür sorgen, dass die Files in kurzen Abständen auf einen anderen Server außer Reichweite gesichert werden.

      Im Vortrag wird gezeigt, wie man die oben genannten Anforderungen an das Audit mit dieser Methode, ein paar Views für die bequeme Auswertung und einem datenbankgesteuerten Housekeeping umsetzen kann.

      UND WIE SIEHT'S UNTER 12C AUS ?
      Unsere mittelständische Firma wächst und gedeiht und denkt an einen Upgrade auf die Version 12c.

      Das unter 12c neu eingeführte Unified Auditing soll schneller, leichter einzurichten und zu verwalten und für alle Editions verfügbar sein.
      Im Prinzip ja, aber ...

      Die Standard Edition One (SEO) gibt es nur noch in der Version 12.1.0.1. Hier ist das Feature wegen des Bugs 17466854 (CANNOT SET UNIFIED AUDITING IN STANDARD EDITION) nicht zu aktivieren. Dafür gibt es einen Patch 17466854, den man aber nicht einspielen kann, wenn man seine Datenbank mit dem aktuellen Patchset versorgt hat. Der Bugfix wurde für den Patchset 12.1.0.1.5 (vom 14.10.2014) geschrieben und funktioniert nicht für höhere Levels. Für SEO-Datenbanken unter Windows soll der Bugfix im Patchset 12.1.0.1.18 eingeschlossen sein.

      Da die SEO allerdings sowieso ein Auslaufmodell ist, steigt unsere Firma doch lieber auf die Standard Edition 2 (SE2) um. Bei der Version 12.1.0.2 funktioniert der Umstieg auf Unified Auditing problemlos. Es macht sich jedoch deutlich bemerkbar, dass bei jedem Patch diverse Bugs gefixt werden. Man sollte also unbedingt die neuesten Patches einspielen !

      Nach der Migration auf die Version 12c ist zunächst der sogenannte Mixed Mode aktiv, unter dem nur die Policies ORA_SECURECONFIG und zusätzlich ORA_LOGON_FAILURES (erst ab 12.1.0.2) aktiviert sind. Diesen beizubehalten, ist keine wirklich gute Option, vor allem hinsichtlich des Housekeepings und der Sicherheit der Audit-Daten gegenüber Manipulation durch den DBA. Zudem gibt es einige wirklich nützliche zusätzliche Features beim neuen Unified Auditing, die man sich nicht entgehen lassen sollte. Dazu zählt vor allem die größere Sicherheit der Audit-Daten.

      WAS IST BEIM UMSTIEG AUF UNIFIED AUDITING UNTER ANDEREM ZU BEACHTEN ?


      Das sys-Audit ist nicht mehr das, was es einmal war
      Änderungen am System, an den Audit-Einstellungen etc. werden im Unified Auditing immer auditiert, egal, ob man sich als SYSTEM oder SYS AS SYSDBA, SYSOPER, SYSDG, SYSBACKUP bzw. SYSKM anmeldet.
      Ansonsten wird der User SYS aber genauso behandelt wie Hinz und Kunz !!! Auch seine Selects erscheinen nicht mehr im Audit-Trail. Wenn man z.B. mitbekommen will, ob er sich per DML an irgendwelchen User-Tabellen vergreift, muss man dieses Audit explizit in einer Policy einrichten! Der Parameter AUDIT_SYS_OPERATIONS hat keinen Einfluss mehr.


      Per Default werden nur failed logins auditiert
      Dass nicht mehr jeder LOGON und LOGOFF registriert wird, macht den Audit-Trail zwar übersichtlicher, aber für Auswertungen des Audit-Trails hinsichtlich der Dauer der Sessions oder der Anzahl nicht korrekt beendeter Session (LOGOFF BY CLEANUP) muss man sich nun eigene Policies schreiben. 


      Die alten Audit-Optionen sind nicht 1:1 in den neuen Policies abzubilden
      Ein AUDIT PROCEDURE BY consultant;
      unter 11g wird unter 12c zu
      CREATE AUDIT POLICY consultant_plsql_pol
      ACTIONS CREATE FUNCTION,
       DROP FUNCTION,
       CREATE LIBRARY,
       DROP LIBRARY,
       CREATE PACKAGE,
       DROP PACKAGE,
       CREATE PACKAGE BODY,
       CREATE PROCEDURE,
       DROP PROCEDURE;
      AUDIT POLICY consultant_plsql_pol BY consultant;


      Das ist eigentlich ein Vorteil, weil diese Syntax besser verständlich ist, aber die Policies können schnell unübersichtlich werden. Die Anforderungen an das Audit von Seite 1 lassen sich über die beiden Default-Policies und 3 zusätzliche maßgeschneiderte Policies verwirklichen. Zuviel Policies wirken sich eher schädlich auf die Performance aus.

      Das neue Audit ist per Default "extended"
      Während man unter der Version 11g den Parameter audit_trail auf DB, extended oder XML, extended setzen musste, um auch die SQL-Statement und Bindvariablen zu erfassen, ist das in Version 12c per Default der Fall. Das lässt den Audit Trail entsprechend schnell anwachsen, wenn die Statements etwas komplexer werden. Auch das obligatorische RMAN-Audit braucht einiges an Platz. Deshalb ist ein durchdachtes Housekeeping fast noch wichtiger als unter 11g.


      Wie der (immer noch motivierte) DBA den Umstieg von der selbstgestrickten Unified Auditing Lösung unter 11g auf die Audit-Konfiguration unter 12c meistert und was ein vernünftig konfiguriertes Audit alles an Verbrechen gegen die Datenbank im allgemeinen und die guten Sitten im besonderen zu Tage fördern kann, erfahren Sie im Vortrag.



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Das PL/SQL-Berechtigungskonzept in 12c

      Bereich:PL/SQL, Version: ab RDBMS 12.x, Letzte Überarbeitung: 11.01.2021

      Keywords:Oracle Neuerungen, PL/SQL, 12C Release 1

      Oracle hat das Berechtigungskonzept zu PL/SQL in Hinblick auf zwei gegensätzliche Szenarien in 12c ausgebaut:

      • Szenario 1: Der Ausführende hat mehr Rechte als der Programmierer.
        Die Änderung zu diesem Szenario (Privileg "INHERIT [ANY] PRIVILEGES") betrifft ausschließlich Prozeduren, die mit Invoker Rights arbeiten. 
      • Szenario 2: Der Ausführende hat weniger Rechte als der Programmierer.

      Die Änderung zu diesem Szenario (Vergabe von Rollen) betrifft Prozeduren, die mit Invoker Rights arbeiten oder mit dynamischem SQL.

      Beiden Neuerungen gemeinsam ist, dass es um die Überprüfung von Rechten zur Laufzeit geht. Auch weiterhin benötigt ein Entwickler alle entsprechenden Berechtigungen selber, um eine Prozedur erfolgreich kompilieren zu können. Dynamisches SQL allerdings wird zur Kompilierzeit nicht ausgewertet.

      Hinweis: Hier und im weiteren ist "Prozedur" als Sammelbegriff zu verstehen, der auch Funktionen und Packages mit einschließt. 

      INHERIT [ANY] PRIVILEGES 

      Hier kommt Szenario 1 ins Spiel:

      Angenommen, der User ADMIN hat weitreichende Rechte.

      Weiter angenommen, der Programmierer SCOTT hat vergleichsweise wenig Rechte.

      Nun schreibt SCOTT eine Prozedur mit Invoker Rights (bei Definer Rights spielt das neue Privileg keine Rolle), die er ADMIN zur Verfügung stellt. Solange es sich um statisches SQL handelt, kann nicht viel passieren, da ja SCOTT's Berechtigungen zur Compile-Zeit überprüft werden.

      Nun könnte aber SCOTT bösartigerweise Befehle in dynamisches SQL verpacken, die weit über seine eigenen Berechtigungen hinausgehen (z. B. an sich selbst Admin-Rechte vergeben), nicht jedoch über diejenigen von ADMIN. SCOTT kann so eine Prozedur problemlos erstellen - aber nicht ausführen. ADMIN dagegen kann sie ausführen.

      Um einen solchen Missbrauch ggf. unterbinden zu können, wurde mit Version 12c die Berechtigung INHERIT [ANY] PRIVILEGES eingeführt. Das Konzept dabei sieht folgendermaßen aus:

      Der Eigentümer der Prozedur (in obigem Szenario SCOTT) braucht, sofern er nicht über das Systemprivileg INHERIT ANY PRIVILEGES  verfügt, von dem Benutzer, der die Prozedur später ausführen soll - also hier ADMIN - , das Objektprivileg INHERIT PRIVILEGES. Hat er das nicht, so kann ADMIN später die Prozedur nicht ausführen.

      Damit sich das Verhalten zwischen 11g und 12c nicht ändert, erhält PUBLIC automatisch für jeden neu angelegten User dieses Recht. Das können Sie leicht nachprüfen über dba_tab_privs:

      SELECT *
        FROM dba_tab_privs
       WHERE grantee = 'PUBLIC' 
         AND privilege = 'INHERIT PRIVILEGES';


      Oracle empfiehlt jedoch PUBLIC diese Rechte zu entziehen.
       

      Für das oben beschriebene Szenario bedeutet dies:

      Hat PUBLIC das Recht INHERIT PRIVILEGES ON USER ADMIN, wie das dem Default entspricht, so wird ADMIN die Prozedur von SCOTT ausführen können, wie auch schon in 11g. Entzieht ADMIN dieses Recht mit

      REVOKE INHERIT PRIVILEGES ON USER ADMIN FROM PUBLIC;

      und vergibt das Recht auch nicht explizit an SCOTT, dann kann er keine Prozedur von SCOTT mehr ausführen, die mit INVOKER RIGHTS angelegt wurde. Beim Versuch erhält er die Fehlermeldung

      ORA-06598: Nicht ausreichende INHERIT PRIVILEGES-Berechtigung

      ROLLEN AN PL/SQL-OBJEKTE VERGEBEN

      Szenario 2 sieht so aus:

      User SCOTT stellt wiederum Invoker Rights-Prozeduren zur Verfügung, in diesem Fall für den User LEHRLING. Eine der Prozeduren greift auf ein Tabelle im Schema SCOTT zu. SCOTT will aber nicht, dass LEHRLING direkten Zugriff auf diese Tabelle bekommt. Den bräuchte LEHRLING aber bis einschließlich Version 11g, um diese Prozedur ausführen zu können.

      SCOTT erstellt z. B. folgende Funktion:

      CREATE OR REPLACE FUNCTION deptno_exists (p_deptno IN SCOTT.DEPT.deptno%TYPE)
         RETURN BOOLEAN
         AUTHID CURRENT_USER
      IS
         v_count   NUMBER;
         v_ret     BOOLEAN;
      BEGIN
         SELECT COUNT (*)
           INTO v_count
           FROM scott.dept
          WHERE deptno = p_deptno;
         IF v_count > 0
         THEN
            v_ret  := TRUE;
         ELSE
            v_ret  := FALSE;
         END IF;
         RETURN v_ret;
      END deptno_exists;
      /
      GRANT EXECUTE ON deptno_exists TO LEHRLING
      /

      LEHRLING wird diese Funktion bis jetzt nicht erfolgreich ausführen können:

      ORA-00942: Tabelle oder View nicht vorhanden
      ORA-06512: in "SCOTT.DEPTNO_EXISTS", Zeile 8

      In Version 12c stellt nun ein DB-Administrator SCOTT eine Rolle zur Verfügung:

      CREATE ROLE select_dept;
      GRANT select_dept TO SCOTT WITH ADMIN OPTION;

      SCOTT vergibt das benötigte Select-Recht and die Rolle:

      GRANT SELECT ON dept TO select_dept;

      Und die Rolle an die Funktion(!):

      GRANT select_dept TO FUNCTION deptno_exists;

      Nun kann LEHRLING die Funktion erfolgreich ausführen ohne direkten Zugriff auf SCOTT.dept zu erhalten.

      An dem Grundprinzip, dass Rollen in PL/SQL unwirksam sind, ändert sich nichts: Eine Prozedur kann auch weiterhin nur dann erfolgreich kompiliert werden, wenn ihr Eigentümer alle dafür erforderlichen Rechte DIREKT gegrantet bekommen hat.

      Ein Beispiel zur Anwendung dieses Rollenkonzepts bei Definer Rights und dynamischem SQL hat Tom Kyte in seinem Blog beschrieben.



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Die wahre Größe einer Tabelle mit LOB Spalten

      Bereich:DBA:Monitoring, Version: ab RDBMS 10.x, Letzte Überarbeitung: 06.07.2018

      Keywords:Lobs, Tabellengröße, DBA_SEGMENTS

      Letztens bin ich über ein vermeintlich trivales Problem gestolpert: Ich wollte die Größe einer Tabelle berechnen. Nur war die vermeintlich nur sehr klein. Wo lag das Problem?

      Wenn man in USER_SEGMENTS oder DBA_SEGMENTS nachschaut, steht dort beim Tabellen (Segment) Namen nur die Größe der Basistabelle (ohne Lob Spalten)

      Als Eigentümer des Objekts kann man folgenden Befehl absetzen:
      Hinweis: Ändern Sie bitte in der ersten Zeile den Namen der Tabelle ab.

      WITH t as (select 'TEST_TAB' as table_name FROM dual)
      select 'Tab: '||t.table_name as info,to_char(round(bytes/1024/1024,2),'999,999,9990.99')||' MB' as SIZE_MB
      from user_segments s, t
      where s.segment_name=t.table_name
      UNION ALL
      select 'LOB: '||column_name,to_char(round(u.bytes/1024/1024,2),'999,999,9990.99')||' MB'
      from user_lobs l, user_segments u, t
      where l.segment_name=u.segment_name
      AND l.table_name=t.table_name
      UNION ALL
      select 'Zusammen: ',to_char(round(sum(u.bytes/1024/1024),2),'999,999,9990.99')||' MB'
      from user_segments u, t
      where u.segment_name IN (select segment_name FROM t,user_lobs ul WHERE ul.table_name=t.table_name)
      OR u.segment_name=t.table_name
      group by 'Zusammen: ';

      Das Ergebnis könnte dann z.B so aussehen:

      INFOSIZE_MB
      -------------------------------------------------
      Tab: EMP_LOB0.06 MB
      LOB: BILD4.19 MB
      Zusammen:4.25 MB

      Wenn man als DBA das Ganze ansehen möchte:

      WITH t as (select 'SCOTT' as owner, 'EMP_LOB' as table_name FROM dual)
      select 'Tab: '||t.table_name as info,to_char(round(bytes/1024/1024,2),'999,999,9990.99')||' MB' as SIZE_MB
      from dba_segments s, t
      where s.segment_name=t.table_name AND s.owner=t.owner
      UNION ALL
      select 'LOB: '||column_name,to_char(round(u.bytes/1024/1024,2),'999,999,9990.99')||' MB'
      from dba_lobs l, dba_segments u, t
      where l.segment_name=u.segment_name
      AND l.table_name=t.table_name AND l.owner=t.owner
      UNION ALL
      select 'Zusammen: ',to_char(round(sum(u.bytes/1024/1024),2),'999,999,9990.99')||' MB'
      from dba_segments u, t
      where u.segment_name IN (select segment_name FROM t,dba_lobs ul WHERE ul.table_name=t.table_name AND ul.owner=t.owner)
      OR u.segment_name=t.table_name AND u.owner=t.owner
      group by 'Zusammen: ';


      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Informationssystem für APEX-Applikationen

      Bereich:APEX, Version: ab APEX 5.x, Letzte Überarbeitung: 10.06.2024

      Keywords:APEX

      Hatten Sie auch schon einmal den Wunsch, den Anwendern einer Applikation etwas mitzuteilen? Und wäre es nicht manchmal gut, wenn jeder Anwender nachweislich die Information gelesen hat? Die Informationen sollen sofort, also auch in einer laufenden Session, in einem modalen Popup- Fenster angezeigt werden. Dieses Problem stellte sich vor einiger Zeit in einem APEX-Projekt und aus diesem Grund haben wir ein Informationssystem für APEX-Anwendungen entwickelt.

      Um die Anforderungen abzudecken brauchen wir im ersten Schritt zwei Tabellen. In der ersten werden die "Nachrichten" gespeichert, in der zweiten die Information, wer wann das Lesen bestätigt hat.

      CREATE TABLE INFORMATIONEN
      (
        ID          NUMBER,        -- Eindeutige ID, Trigger und Sequence
        APP_ID      NUMBER,        -- Applikations ID der Apexanwendung
        STATUS      CHAR(1),       -- A für aktiv oder I für inaktiv
        INFORMATION VARCHAR2(500), -- Freitext für die Informationsn
        CONSTRAINT PK_INFORMATIONEN PRIMARY KEY (ID)
      );
      CREATE TABLE INFORMATION_READ
      (
        INFO_ID     NUMBER,        -- ID der Information die gelesen wurde  
        APP_USER    VARCHAR2(30),  -- Welcher User hat gelesen
        READ_DATE   DATE           -- Wann wurde gelesen, Trigger mit SYSDATE
      );


      Der nächste Schritt ist, eine Seite in der Applikation zu erstellen auf der die Informationen angezeigt werden sollen. Als Template wählen wir Popup. Im Bereich "Page HTML Body Attribute" kommt noch folgende Anweisung dazu:


      Jetzt sollte man sich auch überlegen wie viele Informationen gleichzeitig angezeigt werden müssen. Entsprechend viele Items müssen erzeugt werden.
      Wir benötigen je Info ein "Display only" Item (PX_INFOTEXT_X). Dabei sollte beachtet werden, dass die Eigenschaft "Escape special characters" auf NO steht, dadurch können HTML Formatierungen in den Text integriert werden. Zu jedem Infotext kommt noch eine Checkbox (return 1 when checked), damit können die Nachrichten einzeln bestätigt werden. Infotext und Checkbox werden nur angezeigt, wenn Infotext "NOT NULL" ist. Schließlich fehlt noch je ein Hidden Item zum Speichern der ID und ein Button zum Bestätigen der Seite.

      Jetzt fehlen noch zwei Prozesse, der erste "On Load - Before Header" mit dem die Inhalte gefüllt werden:

      declare
       v_cnt number := 1;
       v_trenner varchar2(30) := '<p><hr><p>';
      begin
       for rec in (select id, information from informationen
                     where app_id = :APP_ID and status = 'A'
                     and id not in (select info_id
                      from information_read where app_user = :APP_USER)
                      order by id) loop
        if v_cnt = 1 then
         :PX_ID1 := rec.id;
         :PX_INFOTEXT_1 := rec.information;
        end if;
        if v_cnt = 2 then
         :PX_ID2 := rec.id;
         :PX_INFOTEXT_2 := rec.information;
        end if;
        v_cnt := v_cnt + 1;
       end loop;
      end;


      Dann kommt der Prozess zum Speichern der Informationen, wenn der Button gedrückt wurde:

      begin
       if :PX_CHECK1 = 1 then
        insert into information_read values(:PX_ID1, :APP_USER, SYSDATE);
       end if;
       if :PX_CHECK2 = 1 then
        insert into information_read values(:PX_ID2, :APP_USER, SYSDATE);
       end if;
       :FXXX_HIDE := 'TRUE';
       :FXXX_INFO := '0';
      end;


      Hier tauchen erstmals die Applikations Items FXXX_HIDE und FXXX_INFO auf. Diese werden für die Steuerung des Infofensters benötigt. Bei Betätigung des Buttons wird auf jeden Fall das Item HIDE auf TRUE gesetzt, damit wird eine weitere Anzeige innerhalb der gleichen Session verhindert. Die Nachrichten können separat bestätigt werden, das heißt der Anwender kann entscheiden, ob sie in der nächsten Session wieder erscheinen sollen.

      Nachdem es sich um ein modales Popup-Fenster handelt brauchen wir noch einen Branch, um es nach der Verarbeitung zu schließen. Der Branch Typ ist "Branch to PL/SQL Procedure".

      begin
       htp.p('<body>');
       htp.p('<script type="text/java-script">');
       htp.p('parent.$("#modalDialog").dialog("close");');
       htp.p('</script>');
       htp.p('</body>');
      end;


      Kommen wir nun zur Steuerung. Bedingung war ja, dass es auch in einer laufenden Session erscheinen soll. Dafür müssen wir bei jedem Neuladen einer Seite nachsehen, ob es eine Nachricht gibt die der jeweilige User noch nicht gelesen hat. Weiterhin soll es die Möglichkeit geben, das modale Fenster zu schließen ohne die Nachrichten zu bestätigen. Dafür werden die Applikationsitems FXXX_HIDE und FXXX_INFO angelegt.
      Dazu gehört auch ein Applikations Prozess mit dem Zündpunkt "On Load: Before Header".

      begin
       select count(*)into :FXXX_INFO
                   from informationen
                   where app_id = :APP_ID
                   and status = 'A'
                   and id not in (select info_id from information_read where app_user = :APP_USER);
      end;


      Jetzt der zentrale Punkt: wann und wie zeige ich das modale Fenster an!

      Dazu wird auf der Seite 0 eine "Dynamic Action" mit folgenden Einstellungen angelegt.

      When:      Event = Page Load
                 Condition = No Condition
      Advanced:  Event Scope = once
      Condition: Type = PL/SQL Expression
                 Expression1 = NVL(:FXXX_HIDE,'F') != 'TRUE' and :FXXX_INFO > 0 and :APP_PAGE_ID not in (101,X)


      Es müssen Loginseite und die Seite die als Popup erscheint ausgeschlossen werden.

      TRUE ACTION: Execute Java-ScriptCode (In diesem Beispiel wird in der Applikation 100 die Seite 7 als modales Popup aufgerufen)
      var ev = this.browserEvent;
      ev.preventDefault;
      var horizontalPadding = 20;
      var verticalPadding = 20;
      $('<iframe id="modalDialog" src="f?p=100:7:&APP_SESSION.::NO::" />').dialog(
             {title: "APEX System Info",
              autoOpen: true,
              width: 700,
              hight: 350,
              modal: true,
              close: function(event, ui) { $(this).remove();},
              overlay: {opacity: 0.5, background: "black"}
              }
        ).width(700 - horizontalPadding).height(350 - verticalPadding);
      return false;

      Der Anwender bekommt "neue Informationen" auch während einer laufenden Session sofort angezeigt und er muss aktiv werden und die Meldungen bestätigen, um sie dauerhaft auszublenden.

      Achtung! Ab der APEX Version 4.1 sind aus Sicherheitsgründen Frames per default nicht erlaubt. Damit dieses Beispiel funktioniert muss in den Security Attributen "Embed in Frames" auf "Allow from same origin" umgestellt werden.

       

      Weitere Informationen und Tipps zur Entwicklung mit APEX bekommen Sie auch in unseren Schulungen Entwicklung mit Application Express.



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Unsichtbare Spalten

      Bereich:SQL, Version: ab RDBMS 12.2, Letzte Überarbeitung: 04.07.2018

      Keywords:Oracle Neuerungen, SQL, 12C Release 1

      Ab Version 12c können Spalten ausgeblendet werden, indem man sie als "invisible" deklariert. Das ist sowohl beim Anlegen einer Tabelle oder Spalte möglich als auch nachträglich.
      Das bedeutet aber nicht, dass auf eine solche Spalte nicht zugegriffen werden kann, sondern nur, dass sie ohne Angabe einer expliziten Spaltenliste nicht berücksichtigt wird:

      CREATE TABLE UNSICHTBAR
      (
        A        NUMBER,
        B        NUMBER INVISIBLE,
        C        NUMBER
      );

       

      INSERT INTO UNSICHTBAR   
      VALUES(1, 1);

       

      INSERT INTO UNSICHTBAR   
      (A, B, C )
      VALUES(2, 2, 2);

       

      SELECT * FROM UNSICHTBAR;
               A          C
      ---------- ----------
               1          1
               2          2

       

      SELECT A, B, C FROM UNSICHTBAR;
               A          B          C
      ---------- ---------- ----------
               1                     1
               2          2          2

      Solange man die Spalte explizit anspricht, kann man also ganz normal mit ihr arbeiten.

      Interessant ist, dass TOAD die Spalte beim DESCRIBE mit angibt - und an welcher Position:

      DESC UNSICHTBAR   -- in SQL*Plus
       Name                         Null?    Typ
       ---------------------------- -------- -----------
       A                                     NUMBER
       C                                     NUMBER
       
      DESC UNSICHTBAR   -- im TOAD
       Name                         Null?    Type                       
       ---------------------------- -------- ------------
       A                                     NUMBER     
       C                                     NUMBER     
       B                                     NUMBER                    

      Hier lohnt sich ein Blick ins Data Dictionary:

        SELECT column_name, column_id
          FROM user_tab_columns
         WHERE table_name = 'UNSICHTBAR'
      ORDER BY column_id;
      COL  COLUMN_ID
      --- ----------
      A            1
      C            2
      B            

      Die column_id ist also bei unsichtbaren Spalten nicht gefüllt. Interessanter noch ist die etwas weniger bekannte user_tab_cols:

        SELECT column_name, column_id, internal_column_id,
               hidden_column, virtual_column
          FROM user_tab_cols
         WHERE table_name = 'UNSICHTBAR'
      ORDER BY internal_column_id;
      COL  COLUMN_ID INTERNAL_COLUMN_ID HIDDEN_COLUMN VIRTUAL_COLUMN
      --- ---------- ------------------ ------------- --------------
      A            1                  1 NO            NO           
      B                               2 YES           NO           
      C            2                  3 NO            NO           

      Wenn eine unsichtbare Spalte wieder sichtbar gemacht wird, bekommt sie grundsätzlich die höchste column_id und rückt dementsprechend ans Ende der Spaltenliste:

      ALTER TABLE UNSICHTBAR MODIFY (b VISIBLE);

       

      SELECT * FROM UNSICHTBAR;
               A          C          B
      ---------- ---------- ----------
               1          1           
               2          2          2

       

        SELECT column_name, column_id,  internal_column_id,
               hidden_column, virtual_column
          FROM user_tab_cols
         WHERE table_name = 'UNSICHTBAR'
      ORDER BY internal_column_id;
      COL  COLUMN_ID INTERNAL_COLUMN_ID HIDDEN_COLUMN VIRTUAL_COLUMN
      --- ---------- ------------------ ------------- --------------
      A            1                  1 NO            NO           
      B            3                  2 NO            NO           
      C            2                  3 NO            NO                  

      Auf diese Art könnte man beispielsweise auch eine neu eingefügte Spalte, die ja bis 11g grundsätzlich als letzte Spalte angezeigt wird, in der Spaltenliste weiter nach vorne wandern lassen:

      ALTER TABLE UNSICHTBAR ADD (e NUMBER);
      ALTER TABLE UNSICHTBAR MODIFY (b INVISIBLE, c INVISIBLE);
      ALTER TABLE UNSICHTBAR MODIFY (b VISIBLE, c VISIBLE);

       

      SELECT *  FROM UNSICHTBAR;
               A          E          B          C
      ---------- ---------- ---------- ----------
               1                                1
               2                     2          2

      So ganz neu ist das Konzept der unsichtbaren Spalten nicht. Haben Sie sich schon einmal angeschaut, wie eine Spalte vom Typ XMLTYPE intern dargestellt wird?

      ALTER TABLE UNSICHTBAR ADD (xml XMLTYPE);

       

        SELECT column_name, column_id
          FROM user_tab_columns
         WHERE table_name = 'UNSICHTBAR'
      ORDER BY column_id;
      COLUMN_NAME    COLUMN_ID
      ------------- ----------
      A                      1
      E                      2
      B                      3
      C                      4
      XML                    5

       

        SELECT column_name, column_id, internal_column_id,
               hidden_column, virtual_column
          FROM user_tab_cols
         WHERE table_name = 'UNSICHTBAR'
      ORDER BY internal_column_id;        
      COLUMN_NAME    COLUMN_ID INTERNAL_COLUMN_ID HIDDEN_COLUMN VIRTUAL_COLUMN
      ------------- ---------- ------------------ ------------- --------------
      A                      1                  1 NO            NO            
      B                      3                  2 NO            NO            
      C                      4                  3 NO            NO            
      E                      2                  4 NO            NO            
      XML                    5                  5 NO            YES           
      SYS_NC00006$           5                  6 YES           NO                 

       

      Hier kann die unsichtbare Spalte SYS_NC00006$ prinzipiell auch direkt angesprochen werden. Da es sich aber bei Speicherung des XMLTYPE als binary xml (dem Default in 12c) um einen BLOB handelt, ist das allerdings nicht sehr sinnvoll. Und bei Speicherung als CLOB (deprecated in 12c) bietet es zumindest keine Vorteile.

      Das Prinzip ist also ähnlich, auch wenn es offensichtlich Unterschiede im Detail gibt. Interessierte sollten sich die Spalten column_id (hier gefüllt!), segment_column_id, virtual_column und - in Version 12c neu eingeführt - user_generated in user_tab_cols genauer anschauen.

      Sie würden gerne wissen, was ist alles neu in 12c? - dann schauen Sie doch in unserer Oracle Schulung Neuerungen 12c vorbei.



      Weitere Interessente Artikel zum Thema:



      Empfohlene Schulungen zum Thema:


      Tipps zur Statistikerstellung in der Datenbank

      Bereich:DBA, Version: ab RDBMS 10.x:RDBMS 11.1:RDBMS 11.2:RDBMS 12.x:RDBMS 18.1:RDBMS 18.3:RDBMS 19.1:RDBMS 19.3:RDBMS 21.1, Letzte Überarbeitung: 12.01.2021

      Keywords:DBA, Oracle Tuning, Statistiken

      Die Erstellung von Statistiken über Datenbank-Objekte wie Tabellen oder Indizes ist seit der Einführung des kostenbasierenden Optimizers ein absolutes Muss. Die Qualität der Statistiken entscheidet darüber, ob ein SQL-Statement performant in der Datenbank verarbeitet werden kann oder nicht. Mit Hilfe der Statistiken bestimmt die Datenbank, welche Kosten im Sinne von Ressourcen-Nutzung entstehen und welcher Zugriffs-Pfad zu den geringsten Kosten führt.

      Der vorliegende Monatstipp hat nicht das Ziel einer detaillierten Beschreibung des kostenbasierenden Optimizers. Dazu wird auf unsere Muniqsoft-Training-Schulungen und auf die einschlägige Literatur verwiesen.

      Vielmehr werden folgende Fragestellungen näher betrachtet:

      • Wie sollen Statistiken erstellt werden?
      • Wann sollten Statistiken erstellt werden?
      • Welche Arten von Statistiken sollten erstellt werden?


      WIE SOLLEN  STATISTIKEN ERSTELLT WERDEN ?
      AUTOMATISCH

      Seit Einführung der RDBMS-Version 10g existiert ein automatischer Statistik-Erstell-Job, der für alle Tabellen, die entweder keine oder veraltete (Stale) Statistiken aufweisen, Statistiken erstellt. Die verwendete Prozedur heißt „DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC“ und verwendet die gleichen Default-Parameter wie die „DBMS_STATS.GATHER_*_STATS“-Prozedur. Per Default werden die Statistiken aller Tabellen, deren Datensätze sich zu 10% geändert haben, als veraltet (stale) betrachtet und somit neu erstellt. Dieser Wert ist bis Oracle Version 10.2 fest und kann nicht geändert werden. Wenn die Notwendigkeit besteht, Statistiken für eine Tabelle öfters erstellen zu lassen, gibt es ab Version 11.1 die Prozedur „DBMS_STATS.SET_TABLE_PREFS“.

      Z.B. kann die Tabelle „SCHULUNG“ des Users „MQS“ bereits bei 5% Änderungen folgendermaßen als veraltet deklariert werden und somit die Erstellung von Statistiken erzwungen werden:

      SQL>
      BEGIN
        DBMS_STATS.SET_TABLE_PREFS('MQS','SCHULUNG','STALE_PERCENT',5);
      END;
      /


      MANUELL

      Wenn das automatische Erstellen von Statistiken nicht gewünscht wird, weil z.B. eine andere Prozedur dies bereits erledigt, kann der Automatismus folgendermaßen nur auf Erstellung der Data Dictionary-Tabellen eingeschränkt werden:

      SQL>
      BEGIN
        DBMS_STATS.SET_GLOBAL_PREFS('AUTOSTATS_TARGET','ORACLE');
      END;
      /


      Für die manuelle Erstellung von Statistiken ist grundsätzlich das PL/SQL-Package DBMS_STATS und nicht mehr das ANALYZE-Kommando zu verwenden.

      Bei der DBMS_STATS-Prozedur sollen die beiden Parameter ESTIMATE_PERCENT und METHOD_OPT näher betrachtet werden:

      ESTIMATE_PERCENT gibt den prozentualen Wert an, wieviele Datensätze einer Tabelle als Basis für die Statistikerstellung herangezogen werden. Je höher der Wert, desto genauer die Statistik, aber desto höher auch die Ausführungszeit der Statistikerstellung. Ab 10g hat sich der Default-Wert für estimate_percent von 100% auf AUTO_SAMPLE_SIZE geändert. Hierbei entscheidet die Datenbank selbst über das Verhältnis von untersuchten Datensätzen zur Erzielung brauchbarer Statistiken und der möglichst geringen Systembelastung bedingt durch deren Erstellung. Leider hat sich bei 10g gezeigt, dass die Anzahl der untersuchten Datensätze zu gering war und deswegen ein absoluter Wert für ESTIMATE_PERCENT sinnvoller war.

      Mit Version 11g hat Oracle den Algorithmus für AUTO_SAMPLE_SIZE geändert. Der Effekt ist, dass 100% der Datensätze untersucht werden, aber nur eine Systembelastung wie bei einem Sample von ca. 10% zu verzeichnen ist.

      Die Empfehlung ist daher bei der Statistik-Erstellung von Tabellen einer 11g-Datenbank für ESTIMATE_PERCENT den  AUTO_SAMPLE_SIZE Parameter zu verwenden.

      SQL>
      BEGIN
       DBMS_STATS.GATHER_TABLE_STATS('MQS','SCHULUNG',
         ESTIMATE_PERCENT => DBMS_STATS.AUTO_SAMPLE_SIZE);
      END;
      /


      METHOD_OPT

      Mit dem Parameter METHOD_OPT kann definiert werden, ob sogenannte Histogramme für Tabellenspalten erzeugt werden. Histogramme teilen dem Oracle Optimizer mit, wie die Werte in den Spalten verteilt sind – z. B. wie oft der Wert „Müller“ in der Spalte „KD_NAME“ enthalten ist. Je öfter der Wert vorhanden ist, desto eher kann sich der Oracle Optimizer dazu entschließen, anstatt einem Direkt-Zugriff über Index alle Datensätze der Tabelle mit einem Full Table Scan zu lesen.

      Bei Datenbanken der Version 10g trat bei Verwendung von Histogrammen der sogenannte „Bind-Peeking“-Effekt ein, bei dem Oracle auf Grund des ersten Wertes einer Spalte in der „where“-Klausel einen Ausführungsplan gewählt hat (z.B. ein Full Table Scan, weil der Wert sehr häufig vorkam) und bei der nächsten Ausführung trotz eines Wertes mit geringerer Selektivität (Wert kommt seltener vor) den Ausführungsplan nicht geändert hat.

      Um diesen Effekt bei Version 10g zu verhindern gibt es zwei Möglichkeiten:

      • Löschen der Histogramme und Erstellen der Statistiken ohne Histogramme
      • Ausschalten von Bind Peeking

      Wenn in der Applikation aussschließlich Bind-Variablen verwendet werden, sollten die Histogramme gelöscht werden:

      BEGIN
        DBMS_STATS.DELETE_TABLE_STATS('MQS','SCHULUNG');
      END;
      /


      Nach Ausführen der folgenden Prozedur erstellen sowohl der automatische Statistik-Erstell-Job als auch die DBMS_STATS.GATHER_*_STATS-Prozeduren keine Histogramme mehr.

      BEGIN
        DBMS_STATS.SET_PARAM(PNAME => 'METHOD_OPT',
          PVAL  => 'FOR ALL COLUMNS SIZE 1');
      END;
      /


      Wenn die Applikation auch Literale verwendet, ist das Ausschalten des Bind-Peekings die bessere Methode.

      SQL> alter system set "_OPTIM_PEEK_USER_BINDS"=false;


      Bitte vor Setzen des sogenanten Underscore-Parameters in MyOracleSupport über mögliche Seiteneffekte informieren oder beim Oracle Support nachfragen.

      Mit Version 11g ist das sogenannte „Adaptive Cursor Sharing“ zur Verhinderung des Bind-Peekings eingeführt worden. Vereinfacht gesprochen können bei diesem Konzept mehrere Ausführungspläne für ein SQL-Statement bei Vorlage unterschiedlicher Verteilungen in den Bind-Variablen erstellt werden.

      Die Empfehlung bei 11g für den Parameter METHOD_OPT ist der Default-Wert mit Erstellung von Histogrammen.


      PENDING STATISTICS  (Ab Oracle 11.1)

      Eine weitere Option, die beim Erstellen von Statistiken beachtet werden kann, sind „Pending Statistics“. Wenn man vom Default abweichende Angaben bei der Erstellung von Statistiken gemacht hat, können diese innerhalb der eigenen Session ohne Beeinflussung des Gesamtsystems als „nicht zu veröffentlichen“ deklariert werden.

      BEGIN
        DBMS_STATS.SET_TABLE_PREFS ('MQS','SCHULUNG','PUBLISH','FALSE');
      END;
      /


      Mit Hilfe des Session-Parameters “OPTIMIZER_USE_PENDING_STATISTICS“ = TRUE werden die erstellten Statistiken innerhalb der Session verwendet. Wenn die Statistiken akzeptiert werden sollen, können sie „veröffentlicht“ werden und gelten damit für das Gesamtsystem.

      BEGIN
        DBMS_STATS.PUBLISH_PENDING_STATS('MQS','CONSULTING');
      END;
      /


      WANN SOLLEN STATISTIKEN ERSTELLT WERDEN ?
      AUTOMATISCHE ERSTELLUNG

      Die Datenbank erstellt seit Version 10g automatisch im Rahmen eines Maintenance-Windows (werktäglich um 22 Uhr, Samstag und Sonntag  um 6 Uhr bei 11g ) Statistiken für alle Tabellen, die keine oder veraltete Statistiken haben.

      Wenn der Zeitpunkt nicht erwünscht ist, kann die Statistikerstellung folgendermaßen deaktiviert

      BEGIN
        DBMS_AUTO_TASK_ADMIN.DISABLE('auto optimizer stats collection',null,null);
      END;
      /


      oder verschoben werden  (z. B. am Montag auf 6 Uhr morgens):

      BEGIN
        DBMS_SCHEDULER.SET_ATTRIBUTE('MONDAY_WINDOW',
          'repeat_interval',
          'freq=daily;byday=MON;byhour=06;byminute=0; bysecond=0');
      END;
      /


      MANUELLE ERSTELLUNG

      Eine manuelle Erstellung bietet sich dann an, wenn zum Zeitpunkt der automatischen Statistik-Erstellung die Tabelle keine repräsentativen Inhalte für Statistiken besitzt.

      Ein Batch-Programm hat um 20 Uhr die Tabelle geleert, der Statistik-Erstell-Job um 22 Uhr ermittelt als Anzahl 0 Datensätze, um 2 Uhr morgens befüllt wiederum ein Batch-Job die Tabelle und um 10 Uhr erfolgt eine Query im Rahmen eines DataWareHouse-Systems. Der Oracle Optimizer ist hierbei nicht in der Lage, einen adäquaten Ausführungsplan zu erzeugen.

      In einem solchen Fall ist es besser, den Statistik-Erstell-Job als Bestandteil des Ladeprozesses zu definieren. Der Aufwand für die Erstellung der Statistiken während des Ladeprozesses wird durch eine spürbare Laufzeitverbesserung des SQL-Statements (im DWH-Umfeld kann es sich um Stunden handeln) mehr als ausgeglichen.

      Eine Alternative wäre auch, die Statistiken nach Beladung zu sperren oder zu löschen. Aufgrund der Möglichkeit des Optimizers, ein dynamisches Sampling bei Tabellen ohne Statistiken während der Laufzeit durchzuführen (init.ora-Parameter "optimizer_dynamic_sampling" Default=2) kann ein immer noch besserer Ausführungsplan als mit falschen Statistiken erzielt werden.


      WELCHE ZUSÄTZLICHEN STATISTIKEN SOLLTEN ERSTELLT WERDEN?
      FIXED OBJECT STATISTIKEN

      Für X$-Tabellen verwendet der Optimizer voreingestellte Statistikwerte, die nicht unbedingt ein Abbild der tatsächlichen Beladung darstellen. Da Dynamic Sampling nicht automatisch für diese Tabellen verwendet wird, sollten Statistiken folgendermaßen erzeugt werden:

      BEGIN
       DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;
      END;
      /


      Die Statistik-Erstellung für Fixed Objects sollte nach Datenbank-Upgrades oder nach Änderungen in der Datenbank-Konfiguration wiederholt werden.


      SYSTEM-STATISTIKEN

      Neben den Objekt-Statistiken benötigt der Oracle Optimizer Informationen über die Kapazität des Systems, auf dem die Datenbank läuft.

      Bei der Ausführung der Query  „select * from mqs.consulting order by mitarbeiter“ kommen im wesentlichen zwei Ausführungspfade in Betracht:

      • Full-Table-Scan auf mqs.consulting und Sortierung der Ergebnismenge
      • Ermitteln der (bereits sortierten) Zeilen über den Primary Index

      Wenn das System über schnelle CPUs und langsame Platten verfügt, ist der erste Ausführungspfad günstiger. Bei schnellen Platten und langsameren CPUs ist möglicherweise der zweite Pfad günstiger.

      Damit sich die Datenbank einen Überblick über das System verschaffen kann, ist es empfehlenswert, mit folgender Prozedur Systemstatistiken zur Hauptverarbeitungszeit zu erstellen:

      BEGIN
        DBMS_STATS.GATHER_SYSTEM_STATS(
          gathering_mode => 'INTERVAL',
          Interval => 60);
      END;
      /


      Die von Oracle im Intervall von 60 Minuten ermittelten Werte können anschließend der VIEW SYS.AUX_STATS$ entnommen werden.

      Fazit

      Das Vorhandensein von passenden Objekt-Statistiken ist die unabdingbare Voraussetzung für ein performantes Datenbanksystem und eine hohe Akzeptanz auf Anwenderseite.

      Statistiken auf Fixed Tables und auf Systemressourcen verbessern den Durchsatz in der Datenbank, haben aber bei weitem nicht den Effekt wie die Objekt-Statistiken.

      Detaillierte Informationen zu Statistiken erhalten Sie in den DB Tuning , SQL Tuning und Optimizer Schulungsangeboten der Muniqsoft GmbH.



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle Workspace Manager (Package dbms_wm)

      Bereich:DBA:PL/SQL, Version: ab RDBMS 10.x, Letzte Überarbeitung: 15.05.2019

      Keywords:Workspace Manager, dbms_wm, Tabellenversionierung

      Der Workspace Manager dient zur Versionierung von Tabellendaten in verschieden Versionen (Workspaces)
      Vorteile

      • Langlaufende Transaktionen können in einem eigenen Workspace laufen, ohne dass sie andere Sessions behindern
      • Unterschiedliche Versionsstände einer Tabelle können unendlich lange gespeichert werden
      • Was wäre, wenn Analysen in beliebiger Anzahl durchgeführt werden, ohne dass die Produktionsdaten dadurch verändert werden?
      • Verfügbar in Standard und Enterprise Edition

      Vorbereitungen:

      • Tabellen müssen für den Workspace vorbereitet werden (DBMS_WM.EnableVersioning)
      • Dadurch wird die Tabelle umbenannt in <tabellenname>_LT
      • Dann wird eine View erzeugt mit dem Ursprungsnamen der Tabelle
      • Auf die View wird ein Instead of Trigger gelegt, der die Daten dann wieder in die Tabelle einträgt
      • Der Tablespace für die Tabelle wird nicht gewechselt

      Sie können eine Administrationsrolle mit allen Rechten für die Workspacebearbeitung vergeben:

      GRANT WM_ADMIN_ROLE TO <user>;


      Folgende Einzelrechte können vergeben werden:

      • ACCESS_WORKSPACE
      • CREATE_WORKSPACE
      • MERGE_WORKSPACE
      • REMOVE_WORKSPACE
      • ROLLBACK_WORKSPACE
      • FREEZE_WORKSPACE

      Beispiel:

      BEGIN
      DBMS_WM.GrantWorkspacePriv('ACCESS_ANY_WORKSPACE, MERGE_ANY_WORKSPACE', 'my_workspace_1','SCOTT','NO');
      END;
      /


      Folgendes gilt für die Tabellen:

      • Nur der Eigentümer oder der Inhaber des Rechts WM_ADMIN_ROLE kann die Versionierung aktivieren
      • Die Tabelle muss einen Primärschlüssel besitzen
      • SYS Tabellen können nicht versioniert werden
      • Wenn eine Parent Tabelle versioniert wurde, muss die Child Tabelle es auch sein
      • Aber eine Child Tabelle kann auch ohne Parent Tabelle versioniert werden
      • Foreign Key Constraints dürfen nach Aktivieren der Versionierung nicht mehr nachträglich erzeugt werden

      Beispiel:
      Tabelle für den Workspace Manager aktivieren:

      BEGIN
      DBMS_WM.EnableVersioning(Table_Name => 'emp');
      END;
      /


      Zwei Workspaces einrichten:

      EXECUTE DBMS_WM.CreateWorkspace('my_workspace_1');


      In den ersten Workspace wechseln:

      EXECUTE DBMS_WM.GotoWorkspace('my_workspace_1');


      Durchführen von Änderungen in der Tabelle emp im Workspace my_workspace_1:

      INSERT INTO emp (empno,ename,deptno) VALUES (8000,'Marco',40);
      DELETE FROM emp WHERE deptno=10;
      UPDATE emp SET sal=sal+1 WHERE deptno=20;


      In den Haupt-Workspace wechseln:

      EXECUTE DBMS_WM.GotoWorkspace('LIVE');

      Dort ist die Tabelle in Ihrem Ursprungszustand zu sehen (ohne die 3 DML Änderungen)

      In welchem Workspace sind wir gerade?

      SELECT DBMS_WM.GetWorkspace FROM dual;


      Die Live Tabelle kann nun auf die Workspace Tabellen-Variante refreshed werden:

      BEGIN
      DBMS_WM.RefreshWorkspace(
      workspace =>'my_workspace_1');
      END;
      /

      Oder die Workspace Variante wird auf Live synchronisiert:

      BEGIN
      DBMS_WM.MergeWorkspace(
      workspace =>'my_workspace_1');
      END;
      /


      Die Tabelle kann wieder aus der Versionsverwaltung herausgenommen werden durch:

      EXEC DBMS_WM.DisableVersioning('SCOTT.EMP');

      Mit der Option FORCE wird das Kommando auch mit geänderten Workspacedaten durchgeführt, sonst erhält man einen Oracle Fehler:

      ORA-20038: cannot disable version a table modified in non-LIVE workspaces

      BEGIN
      DBMS_WM.DisableVersioning('SCOTT.EMP',force=>TRUE);
      END;
      /


      Zum Löschen eines Workspace verwenden Sie:

      BEGIN
      DBMS_WM.RemoveWorkspace('my_workspace_1');
      END;
      /


      Weitere Informationen zum Workspace Manager erhalten Sie in unserem PL/SQL II Kurs.
       



      Weitere Interessente Artikel zum Thema:



      Empfohlene Schulungen zum Thema:


      Oracle 23ai FREE auf Debian (bookworm) Installation

      Bereich:DBA, Version: ab RDBMS 23.1, Letzte Überarbeitung: 13.06.2024

      Keywords:

      Installation von Oracle 23ai FREE auf Debian

      Die folgende Installation wird zwar nicht von Oracle supported, aber das wird die 23ai FREE Edition sowieso nicht, also los geht´s …

      Benutzer anlegen (kann man auch durch das Preinstall Skript durchführen lassen), aber hier ist man flexibler…

      addgroup --system oinstall
      addgroup --system dba
      adduser --system --ingroup oinstall --shell /bin/bash oracle
      usermod -d /home/oracle oracle
      chown -R oracle:oinstall /home/oracle
      adduser -d /home/oracle oracle dba

      Ein paar Packages vorinstallieren:

      apt-get install alien rlwrap

      REM Download der beiden Dateien von der URL: https://www.oracle.com/database/free/download/

      Red Hat 8 / Rocky Linux 8 / Alma Linux 8 / Oracle Linux 8
      wget https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el8.x86_64.rpm
      wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm
      
      Red Hat 9 / Rocky Linux 9 / Alma Linux 9 / Oracle Linux 9
      https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el9.x86_64.rpm
      wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el9.x86_64.rpm

      REM Unwandeln der .rpm Dateien in .deb Dateien:

      alien --script oracle-database-preinstall*.rpm
      alien --script oracle-database-free-23ai*.rpm

      ### Achtung dauert laaaaange #### nicht abbrechen #### bei uns fast 1 Stunde ! 
      zur Überbrückung bekommt man dauernd die Warnung:  
      warning: oracle-database-free-23ai-1.0-1.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID ad986da3: NOKEY  
      oder wenn Sie Langeweile haben, können Sie die Größe des Zielordners "im Auge"  behalten:

      du -hs oracle-database-free-23ai-1.0

      da sollten dann ca. 11 GB rauspurzeln

      Sie können während Sie auf die Beendigung der Umwandlung warten schon mal (in einer zweiten Session) die .bash_profile Datei bearbeiten/anpassen:

      cat << EOF > /home/oracle/.bash_profile
          export TERM=vt220
          export EDITOR=vi
          export PS1="[\u@\h:\w]>"
          export DISPLAY=:0.0
          export ORACLE_BASE=/opt/oracle
          export ORACLE_HOME=\$ORACLE_BASE/product/23ai/dbhomeFree
          export ORACLE_SID=FREE
          export ORACLE_INSTANCE=free
          export ORACLE_TERM=vt220
          export ORA_NLS10=\$ORACLE_HOME/nls/data
          export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$ORACLE_HOME/lib
          export NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252
          export PATH=\$ORACLE_HOME/bin:\$PATH:/usr/sbin:/usr/ccs/bin
          alias cdo="cd \$ORACLE_HOME; pwd"
          alias cdd="cd \$ORACLE_BASE/oradata"
          alias cda="cd \$ORACLE_BASE/diag/rdbms/\$ORACLE_INSTANCE/\$ORACLE_SID/trace; pwd"
          alias cdn="cd \$ORACLE_HOME/network/admin; pwd"
          alias cde="cd \$ORACLE_BASE/admin/\$ORACLE_SID/dpdump"
          alias sp="\$ORACLE_HOME/bin/sqlplus '/ as sysdba'"
          alias l="ls -l"
          alias ll="ls -la"
          alias ipconfig="/sbin/ifconfig | grep Bcast"
          echo Folgende Einstellungen wurden gesetzt:
          env | grep ORA
          ps aux | grep [t]omcat | awk '{print "Tomcat-Prozess:" $2}'
          ps aux | grep [x]e_pmon | awk '{print "Oracle-Prozess:" $2}'
          ps aux | grep [t]ns | awk '{print "Listener-Prozess:" $2}'
          EOF

      Wenn der Umwandlungsprozess fertig ist, geht es weiter mit:

      apt update 
      apt install libaio* 
      apt install ./oracle-database-preinstall-23ai_1.0-1.5_amd64.deb 
      apt install ./oracle-database-free-23ai_1.0-2_amd64.deb 

      dann geht es weiter mit: 

      Hinweis: Bei uns wurde bei der automatischen Installation der Listener Port 1539 verwendet und dann abgebrochen.

      Sie können den Port in folgender Datei selber setzen:

      vi /etc/sysconfig/oracle-free-23ai.conf
      LISTENER_PORT=1521
      /etc/init.d/oracle-free-23ai configure 

      zweimal ein schönes langes Passwort eingeben, z.B. "dasistmeinPasswordganzschoenlangoder"

      /etc/init.d/oracle-free-23ai configure
      Oracle Net Listener configured.
      Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:
      Confirm the password:
      Configuring Oracle Listener.
      Listener configuration succeeded.
      Configuring Oracle Database FREE.
      Enter SYS user password: 
      ***
      Enter SYSTEM user password: 
      ****
      Enter PDBADMIN User Password: 
      *****
      Prepare for db operation
      7% complete
      Copying database files
      29% complete
      Creating and starting Oracle instance
      30% complete
      33% complete
      36% complete
      39% complete
      43% complete
      Completing Database Creation
      47% complete
      49% complete
      50% complete
      Creating Pluggable Databases
      54% complete
      71% complete
      Executing Post Configuration Actions
      93% complete
      Running Custom Scripts
      100% complete
      Database creation complete. For details check the logfiles at:
      /opt/oracle/cfgtoollogs/dbca/FREE.
      Database Information:
      Global Database Name:FREE
      System Identifier(SID):FREE
      Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details.
      Connect to Oracle Database using one of the connect strings:
          Pluggable database: pve4/FREEPDB1
          Multitenant container database: pve4
      

      Beim ersten Versuch gab es leider kein schöner Abschluss, wir bekommen den Fehler:

      Listener configuration failed. Check log '/opt/oracle/cfgtoollogs/netca/netca_configure_out.log' for more details

      und da steht drinnen: 

      The information provided for this listener is currently in use by other software on this computer.

      In der listener.ora Datei ($ORACLE_HOME/network/admin) steht ein Port 1539 hmm, kenn ich nicht, Oracle verwendet normalerweise den Port 1521. 
      Oder Sie haben wir oben beschrieben den Port bereits geändert, dann sollte alles durchlaufen.

      So jetzt können Sie mit Ihren SQL / DBA /APEX Kenntnissen loslegen… oder doch erst einen Kurs bei uns besuchen ?
      Kein Problem, bei 44 verschiedenen Kursen ist sicher auch für Sie etwas dabei.

       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Linux Shell Skripten in Oracle Tabellen speichern

      Bereich:DBA:PL/SQL, Version: ab RDBMS 21.1:RDBMS 23.1, Letzte Überarbeitung: 23.12.2024

      Keywords:Shell Script, Linux,

      Wollten Sie immer schon mal zu Dokumentationszwecken ihre Shell Skripten in Oracle Tabellen speichern, das Ganze auch noch Clientseitig?

      Das Problem sind die vielen Zeilenumbrüche in den Shell Skript Dateien, deswegen wandeln wir die Datei in BASE64 um. 
      Da die Dateien länger als 32767 Zeichen lang werden können und damit die Maximallänge von VARCHAR2 in Tabellen von 4k (bzw. 32K ab 12.1 bei spezieller Einrichtung) übersteigen können,
      wandeln wir es sicherheitshalber in CLOB um.
      Leider hat Oracle eine solche Funktion nicht, dewegen schreiben wir sie uns selbst.

      1. Funktion anlegen:

      CREATE OR REPLACE FUNCTION Decode_Base64(
             p_base64 IN CLOB
          ) RETURN CLOB AS
             v_blob       BLOB;
             v_decoded    CLOB;
             v_length     INT;
             v_warning    INT;
             v_offset     INT:= 1;
             v_context    INT:= dbms_lob.default_lang_ctx;
          BEGIN
             -- Convert the Base64 CLOB into a BLOB
             DBMS_LOB.CREATETEMPORARY(v_blob, TRUE);
             DBMS_LOB.WRITE(v_blob, DBMS_LOB.GETLENGTH(p_base64), 1, UTL_RAW.CAST_TO_RAW(p_base64));
             -- Decode the Base64 BLOB
             v_blob := UTL_ENCODE.BASE64_DECODE(v_blob);
             -- Determine the length of the decoded text
             v_length := DBMS_LOB.GETLENGTH(v_blob);
             -- Convert the BLOB to CLOB
             DBMS_LOB.CREATETEMPORARY(v_decoded, TRUE);
             DBMS_LOB.CONVERTTOCLOB(
                 DEST_LOB     => v_decoded,
                 SRC_BLOB     => v_blob,
                 AMOUNT       => v_length,
                 DEST_OFFSET  => v_offset,
                 SRC_OFFSET   => v_offset,
                 blob_csid    => dbms_lob.default_csid,
                 lang_context => v_context,
                 warning      => v_warning
             );
              
                  -- Free resources
             DBMS_LOB.FREETEMPORARY(v_blob);
             RETURN v_decoded;
          END Decode_Base64;
          /

      2. Ziel-Tabelle erstellen:

      CREATE TABLE script_table (
          id int 
          GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
          content CLOB);

      3. Auf Shell-Ebene gewünschte Datei (hier: install.sh) in Base64 codieren und in Variable B64 speichern:

      export B64=`echo -n \`cat install.sh\` | base64`

      4. OS-Variable in Oracle Tabelle eintragen und wieder aus Base64 in CLOB Text konvertieren:

          sqlplus scott/TIGER@172.24.114.237:1522/pdb1  <<EOF
          set echo off termout off 
          DECLARE
           script_content CLOB := q'^${B64}^';
          BEGIN
           INSERT INTO script_table(content)VALUES(decode_base64(script_content));
           COMMIT;
          END;
          /
          EXIT;
          EOF

      So nun steht Ihrer Versionsverwaltung oder dem Audit nichts mehr im Wege…
      Weitere tolle Tipps erhalten Sie in einem unserer 50 Oracle und Postgres Kurse. Wir freuen uns auf Sie …
       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Tablespace Shrink ab 23ai

      Bereich:DBA, Version: ab RDBMS 23.1, Letzte Überarbeitung: 11.02.2025

      Keywords:

      Seit 30 Jahren warte ich auf dieses Feature, aber wie sagt man besser spät als nie …

      Ab 23ai kann nun endlich ein Tablespace reorganisiert werden. Es gibt da nur ein paar Einschränkungen:

      1. Es muss ein Bigfile Tablespace sein
      2. Es dürfen keine exotischen und schreibgeschützten Objekte dort liegen wie z.B.
        aud$unified

      Zuerst prüfen wir mal, welche Tablespaces sich den lohnen bzgl eines Reorg?

      set serveroutput on linesize 400
      set long 9999999
      WITH function analyze_tbs(tbs_name In VARCHAR2) RETURN CLOB
      IS
      PRAGMA AUTONOMOUS_TRANSACTION;
      v_result CLOB:=empty_clob();
      BEGIN
      dbms_output.put_line('###  '||tbs_name||'  ###:');
      DBMS_SPACE.TABLESPACE_SHRINK(tbs_name, 
      SHRINK_MODE => DBMS_SPACE.TS_MODE_ANALYZE, 
      SHRINK_RESULT => v_result);
      RETURN tbs_name||':'||chr(10)||v_result;
      END;
      select analyze_tbs(tablespace_name)
      from dba_tablespaces
      where bigfile='YES'
      and contents='PERMANENT';

       

      Nun können wir einen Tablespace von Oracle shrinken/reorganisieren …

      BEGIN
      DBMS_SPACE.TABLESPACE_SHRINK('SYSAUX', 
      SHRINK_MODE => dbms_space.ts_mode_shrink, 
      target_size => dbms_space.ts_target_max_shrink);
      END;
      /

      Viel Spaß mit dem neuen gewonnen Speicherplatz. Die Einsparung kann man ja nun in eine Schulung stecken :-)



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle ORDS 24.x Install mit Apache TomCat 10.1.x oder TomCat 11.x

      Bereich:APEX, Version: ab APEX 23.2:APEX 24.1:APEX 24.2:ORDS 23.2, Letzte Überarbeitung: 29.07.2025

      Keywords:

      TomCat Version 10 ist nun einige Jahre auf dem Markt, nur leider unterstützt Oracle diese Version weiterhin nicht. Inwischen gibt es sogar auch schon TomCat 11!
      Wer doch schon mal auf undokumentierten Pfaden wandeln möchte, bekommt hier die Anleitung dazu.

      1. Wenn Sie noch kein Java JDK installiert haben, sollten Sie das jetzt bitte tun (Download Seite Java JDK 17)
      2. Nun brauchen wir die neuste Apache TomCat Version 10 (Download) oder Apache TomCat 11 (Download)
        Link zur Apache Webseite (Apache 10)
        Der TomCat wird ganz normal installiert, sie sollten aber evtl eine alte TomCat Version entfernen oder für beide TomCat Versionen verschiedene Ports (z.B. 8080 und 8081) einrichten
      3. Dann brauchen wir ein Apache Konvertierungsutility, um die ORDS Version in das für Version 10 buw. Version 11 passende Format zu wandeln (Download) Link zur Webseite (Apache Konvertierungstool)
      4. Laden Sie sich die neuste ORDS Version herunter (Webseite)

      Packen Sie nun die jakartaee-migration Dateien aus Schritt 3 z.B. in das Temp Verzeichnis aus (c:\temp für Windows oder /tmp für Linux)

      Packen Sie auch die ORDS Version aus Schritt 4 im Temp Verzeichnis aus

      Kopieren Sie die Datei ords.war in das Verzeichnis C:\Temp\jakartaee-migration-*\lib (Windows) oder /tmp/jakartaee-migration-*/lib (Linux)

      Windows: "C:\Program Files\Java\jdk-17\bin\java.exe" -jar jakartaee-migration-1.0.8.jar ords.war ords_neu.war
      Linux: java -jar jakartaee-migration-1.0.8.jar ords.war ords_neu.war

      Nun wird die ords_neu.war in ords.war umbennant und in das webapps Verzeichnis des TomCat kopiert

      Windows: move C:\Temp\jakartaee-migration-1.0.8\lib\ords_neu.war “C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\ords.war”
      bzw. Version 11
      Windows: move C:\Temp\jakartaee-migration-1.0.8\lib\ords_neu.war “C:\Program Files\Apache Software Foundation\Tomcat 11.0\webapps\ords.war”
      Linux: mv /tmp/jakartaee-migration-1.0.8/lib/ords_neu.war /opt/tomcat/latest/webapss

      Ords Einrichtung (Windows)

      set JAVA_HOME="C:\Program Files\Java\jdk-17"
      set PATH=%PATH%;%JAVA_HOME%
      set ORDS_HOME=c:\oracle\ords
      set ORDS_CONFIG=c:\oracle\ords
      set ORDS_LOGS=%ORDS_CONFIG%\logs
      mkdir %ORDS_CONFIG%
      mkdir %ORDS_LOGS%
      dir %JAVA_HOME%
      set DB_PORT=1521
      set DB_SERVICE=apex241
      set SYSDBA_USER=SYS
      set SYSDBA_PASSWORD=sys
      set ORDS_PASSWORD=ords
      set ORA_HOST=172.30.30.2
      #%ORDS_HOME%\bin\ords --config %ORDS_CONFIG% uninstall
      %ORDS_HOME%\bin\ords --config %ORDS_CONFIG% install ^
          --log-folder %ORDS_LOGS% ^
          --admin-user %SYSDBA_USER% ^
          --db-hostname %ORA_HOST% ^
          --db-port %DB_PORT% ^
          --db-servicename %DB_SERVICE% ^
          --feature-db-api true ^
          --feature-rest-enabled-sql true ^
          --feature-sdw true ^
          --gateway-mode proxied ^
          --gateway-user APEX_PUBLIC_USER ^
          --proxy-user 

      ORDS Einrichtung (Linux)

      export ORDS_HOME=/opt/oracle/ords
      mkdir -p $ORDS_HOME
      chown -R tomcat:dba $ORDS_HOME
      export ORA_HOST=172.30.30.2
      export DB_SERVICE=apex241
      export ORDS_CONFIG=/opt/oracle/ords
      cp ords.war $ORDS_HOME
      cp -R bin $ORDS_HOME
      cd $ORDS_HOME
      export SYSDBA_USER=sys
      export DB_PORT=1521
      chmod u+x $ORDS_HOME/bin/ords
      tnsping $ORA_HOST:$DB_PORT/$DB_SERVICE
      lsnrctl status | grep $DB_SERVICE
      # Optional: Deinstallation
      # systemctl stop tomcat
      # $ORDS_HOME/bin/ords --config $ORDS_CONFIG uninstall --admin-user $SYSDBA_USER
      $ORDS_HOME/bin/ords --config $ORDS_CONFIG install \
          --log-folder $ORDS_HOME \
          --admin-user $SYSDBA_USER \
          --db-hostname $ORA_HOST \
          --db-port $DB_PORT \
          --db-servicename $DB_SERVICE \
          --feature-db-api true \
          --feature-rest-enabled-sql true \
          --feature-sdw true \
          --gateway-mode proxied \
          --gateway-user APEX_PUBLIC_USER \
          --proxy-user 

      Auf jeden Fall immer beachten: Der TomCat muss wissen, wo sein Configfile für den ORDS ist.

      Unter Windows trägt man das im Apache Tomcat Config Fenster im Bereich Java ein:

      -Dconfig.url=C:\oracle\ords

      Unter Unix natürlich entsprechend (Datei /etc/systemd/system/tomcat.service):

      Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords"

      Danach sollte in der der Catalina*.log etwas stehen wie:

      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 9.0
      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 9.0
      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 9.0\temp
      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\conf\logging.properties
      19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dconfig.url=C:\opt\oracle\ords
      

      So, das war es schon. nur immer daran denken, wenn es ein Problem in dieser nicht unterstützen Konfiguartion gibt, müsste das Ganze erst unter TomCat Version 9 reproduziert werden!

      Viel Spass und bis Bald in einem unserer APEX Kurse …



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Save Linux shell scripts in Oracle tables

      Bereich:DBA:PL/SQL, Version: ab RDBMS 21.1:RDBMS 23.1, Letzte Überarbeitung: 23.12.2024

      Keywords:Shell Script, Linux,

      Have you always wanted to save your shell scripts in Oracle tables for documentation purposes, even on the client side?

      The problem is the many line breaks in the shell script files, so we convert the file to BASE64. 
      Since the files can be longer than 32767 characters and thus exceed the maximum length of VARCHAR2 in tables of 4k (or 32K from 12.1 with special setup),

      1. Create Funktion :

      CREATE OR REPLACE FUNCTION Decode_Base64(
             p_base64 IN CLOB
          ) RETURN CLOB AS
             v_blob       BLOB;
             v_decoded    CLOB;
             v_length     INT;
             v_warning    INT;
             v_offset     INT:= 1;
             v_context    INT:= dbms_lob.default_lang_ctx;
          BEGIN
             -- Convert the Base64 CLOB into a BLOB
             DBMS_LOB.CREATETEMPORARY(v_blob, TRUE);
             DBMS_LOB.WRITE(v_blob, DBMS_LOB.GETLENGTH(p_base64), 1, UTL_RAW.CAST_TO_RAW(p_base64));
             -- Decode the Base64 BLOB
             v_blob := UTL_ENCODE.BASE64_DECODE(v_blob);
             -- Determine the length of the decoded text
             v_length := DBMS_LOB.GETLENGTH(v_blob);
             -- Convert the BLOB to CLOB
             DBMS_LOB.CREATETEMPORARY(v_decoded, TRUE);
             DBMS_LOB.CONVERTTOCLOB(
                 DEST_LOB     => v_decoded,
                 SRC_BLOB     => v_blob,
                 AMOUNT       => v_length,
                 DEST_OFFSET  => v_offset,
                 SRC_OFFSET   => v_offset,
                 blob_csid    => dbms_lob.default_csid,
                 lang_context => v_context,
                 warning      => v_warning
             );
              
                  -- Free resources
             DBMS_LOB.FREETEMPORARY(v_blob);
             RETURN v_decoded;
          END Decode_Base64;
          /

      2. Target-Tabelle:

      CREATE TABLE script_table (
          id int 
          GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
          content CLOB);

      3. At shell level, code the desired file (here: install.sh) in Base64 and save it in variable B64:

      export B64=`echo -n \`cat install.sh\` | base64`

      4. Enter OS variable in Oracle table and convert back from Base64 to CLOB text:

          sqlplus scott/TIGER@172.24.114.237:1522/pdb1  <<EOF
          set echo off termout off 
          DECLARE
           script_content CLOB := q'^${B64}^';
          BEGIN
           INSERT INTO script_table(content)VALUES(decode_base64(script_content));
           COMMIT;
          END;
          /
          EXIT;
          EOF

      So now nothing stands in the way of your version management or audit...
      You can get more great tips in one of our 50 Oracle and Postgres courses. We look forward to seeing you ...
       



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Tablespace Shrink available as of Oracle 23ai

      Bereich:DBA, Version: ab RDBMS 23.1, Letzte Überarbeitung: 11.02.2025

      Keywords:

      I've been waiting 30 years for this feature, but as they say – better late than never…

      Starting with Oracle 23ai, it is finally possible to reorganize a tablespace. There are just a few limitations:

      1. It must be a Bigfile Tablespace

      2. It must not contain any exotic or read-only objects such as
        AUD$UNIFIED

      First, let's check which tablespaces are actually worth reorganizing.

      set serveroutput on linesize 400
      set long 9999999
      WITH function analyze_tbs(tbs_name In VARCHAR2) RETURN CLOB
      IS
      PRAGMA AUTONOMOUS_TRANSACTION;
      v_result CLOB:=empty_clob();
      BEGIN
      dbms_output.put_line('###  '||tbs_name||'  ###:');
      DBMS_SPACE.TABLESPACE_SHRINK(tbs_name, 
      SHRINK_MODE => DBMS_SPACE.TS_MODE_ANALYZE, 
      SHRINK_RESULT => v_result);
      RETURN tbs_name||':'||chr(10)||v_result;
      END;
      select analyze_tbs(tablespace_name)
      from dba_tablespaces
      where bigfile='YES'
      and contents='PERMANENT';

       

      Now, we are finally able to shrink or reorganize a tablespace in Oracle...

      BEGIN
      DBMS_SPACE.TABLESPACE_SHRINK('SYSAUX', 
      SHRINK_MODE => dbms_space.ts_mode_shrink, 
      target_size => dbms_space.ts_target_max_shrink);
      END;
      /

      Have fun with the newly reclaimed space. The savings can now be invested in a training course. :-)



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      PDF display from table in APEX

      Bereich:APEX, Version: ab APEX 22.2:APEX 23.1:APEX 23.2:APEX 24.1:APEX 24.2:RDBMS 19.1, Letzte Überarbeitung: 05.04.2025

      Keywords:APEX, PDF, Tabelle

      The question of how to display a PDF in a page comes up very often in our APEX courses. In our case, the PDF comes from a table in the Oracle database.

      Preparation:

      1. Create Table
        Example-Table: emp_lob
         
      2. CREATE TABLE emp_lob (
        EMPNO        NUMBER(4,0),
        ENAME        VARCHAR2(10 BYTE),
        DATEINAME    VARCHAR2(512 BYTE),
        BESCHREIBUNG VARCHAR2(4000 BYTE),
        DATEITYP     VARCHAR2(100 BYTE),
        L_UPDATE     DATE,
        BILD         BLOB)
      3. Place the form with report on this table. You can then use this to load the PDF into your table
      4. Create a new application item (Shared Components / Application Logic / Application Item) in APEX (name: EMPNO) and set this item to unrestricted.
      5. Create an application process (Shared Components / Application Logic / Application Process) in APEX: Name getPDF and define as Ajax Processes

        The process has the following code:

        begin
           for file in (select * from emp_lob
                       where empno = :EMPNO
             and dateityp='application/pdf') loop
               sys.htp.init;
               sys.owa_util.mime_header( file.dateityp, FALSE );
               sys.htp.p('Content-length: ' || sys.dbms_lob.getlength( file.bild));
               sys.htp.p('Content-Disposition: inline; filename="' || file.fname || '"' );
               sys.htp.p('Cache-Control: max-age=3600');  -- tell the browser to cache for one hour, adjust as necessary
               sys.owa_util.http_header_close;
               sys.wpg_docload.download_file( file.bild );
            
               apex_application.stop_apex_engine;
           end loop;
        end;
      6.  Create a new page with a static content region:
        Please adjust the IP address and possibly the port on your server
      7. In this region (we are now starting from page 1) there should be an item with the name P1_EMPNO. The corresponding line in which the PDF is located can then be selected there.
        The page should then have a submit button (e.g. via a button)
      8. <object 
        data="http://127.0.0.1:8080/ords/f?p=100:0:&SESSION.:APPLICATION_PROCESS=getPDF:::EMPNO:&P1_EMPNO." style="width:100%;height:700px">
        <a href="http://127.0.0.1:8080/ords/f?p=100:0:&SESSION.:APPLICATION_PROCESS=getPDF:::EMPNO:&P1_EMPNO.">PDF laden</a>
        </object>

      And now have fun displaying all your PDFs. We use it to display our PDF invoices in APEX :-)
      See you (hopefully) soon in one of our courses ...



      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema:


      Oracle APEX Interactive Grid Javascript Snippets

      Bereich:APEX, Version: ab APEX 22.2:APEX 23.1, Letzte Überarbeitung: 20.09.2023

      Keywords:APEX Javascript, Grid , Interactive Grid

      In our training sessions, we frequently get interesting questions about the Interactive Grid. Here's a small selection:

      Requirements:

      1. There is a grid on the Scott.emp table with the static ID EMP

      2. There is a select list named P1_JOB

       

      1. In the grid for the EMP table, the job for all employees should be set to a single unified value, which is defined in an item outside of the grid.
      var model = apex.region("EMP").widget().interactiveGrid("getViews", "grid").model;
          model.forEach(function(r) {
             model.setValue(r, "JOB", $v("P1_JOB" )); // Setzen des Jobs pro Zeile
          })

      2. Only the entries selected using the checkbox (column 1) in the grid should be updated.

      var grid = apex.region("EMP").widget().interactiveGrid("getViews","grid");
      var model   = grid.model;
      var selectedRecords = grid.getSelectedRecords();
      //console.log("Records" +selectedRecords.length);
      for (idx = 0; idx < selectedRecords.length; idx++) {
         record = model.getRecord(selectedRecords[idx][0]); 
           model.setValue(record, "JOB", $v( "P1_JOB" ));
          //console.log(idx+ " " + selectedRecords[idx][1] ); //Felder [1] EMPNO [2] ENAME, [3] JOB ...
      }

      3. ou want to handle writing back to the database yourself? No problem. Simply replace the process with:

      IF :APEX$ROW_STATUS='C' THEN
          INSERT INTO emp (empno,ename,job,mgr,hiredate,sal,comm,deptno)
          VALUES (:EMPNO,:ENAME,:JOB,:MGR,:HIREDATE,:SAL,:COMM,:DEPTNO);
      ELSIF :APEX$ROW_STATUS='U' THEN
          UPDATE emp SET
          ename=:ENAME,job=:JOB, mgr=:MGR,hiredate=:HIREDATE ,sal=:SAL,comm=:COMM, deptno=:DEPTNO
          WHERE empno=:EMPNO ;
      ELSIF :APEX$ROW_STATUS='D' THEN
          DELETE FROM emp
          WHERE empno=:EMPNO;
      END IF;

      That was a small excerpt from the many questions we get in our APEX courses. Do you have questions too? Then join one of our courses… we look forward to seeing you!

       


      Weitere Interessente Artikel zum Thema:


      Empfohlene Schulungen zum Thema: