SQL
SQL mit ORACLE 10.2
SELECT
DELETE
UPDATE
System Tables
Die Namen aller Tabellen ausgeben
Die Namen aller Indexe ausgeben
Die Namen aller Procedures und Functions ausgeben
Die Constraints auf einer Tabelle ausgeben
DROP TABLE
ORACLE Stored Procedures
Procedures and Functions
Editieren mit SQLDeveloper und Output von Informationen
Rückgabe mehrerer Zeilen
Packages
Object Types
Native Dynamic SQL
Native Dynamic SQL in Java
Native Dynamic SQL in PL/SQL
SELECT
SELECT * FROM <tableName>;
DELETE
DELETE FROM <tableName>;
UPDATE
UPDATE <tableName>
SET <columnName>
WHERE <columnName> = <value>;
Hinter UPDATE muss der Name der Tabelle stehen, die verändert werden soll. SET beschreibt die Änderung durch den Spaltennamen und den neuen Wert. Where beschreibt alle Zeilen der Tabelle in denen die Änderung vorgenommen werden soll. Die Zeilen werden über Eigenschaften ihrer Inhalte in bestimmten Spalten beschrieben.
System Tables
Der ORACLE SQL Server fügt alle Objekte, die er verwaltet als Einträge in System Tabellen ein. System Tabellen sind nützlich um Objekte zu suchen oder zu ändern. http://www.techonthenet.com/oracle/sys_tables/index.php
Die Namen aller Tabellen ausgeben
Die System Table ALL_TABLES speichert die Namen aller dem Benutzer zugänglicher Tabellen.
SELECT * FROM ALL_TABLES;
SELECT * FROM ALL_ALL_TABLES;
Die System Table USER_TABLES speichert alle Tabellen, die der Benutzer angelegt hat. Die System Table DBA_TABLE speichert alle Tabellen, die der Sysadmin angelegt hat.
SELECT * FROM TABS;
SELECT * FROM USER_TABLES;
SELECT * FROM DBA_TABLES;
Die Namen aller Indexe ausgeben
SELECT * FROM ALL_INDEXES;
SELECT * FROM USER_INDEXES;
SELECT * FROM DBA_INDEXES;
Die Namen aller Procedures und Functions ausgeben
Die System Tabels ALL_PROCEDURES, USER_PROCEDURES und DBA_PROCEDURES enthalten jeweils sowohl Procedures als auch Functions!
SELECT * FROM ALL_PROCEDURES;
SELECT * FROM USER_PROCEDURES;
SELECT * FROM DBA_PROCEDURES;
Die Constraints auf einer Tabelle ausgeben
SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'LINK';
-- table name has to be written in uppercase for constraint queries
SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'MULTILAYERSUBNETWORK' AND CONSTRAINT_TYPE = 'R';
DROP TABLE
DROP TABLE <tableName>;
DROP TABLE <tableName> CASCADE CONSTRAINTS;
Editieren mit SQLDeveloper und Output von Informationen
Stored Procedures werden über einen Datenbankclient (Java JDBC Programm, SQLDeveloper, sqlplus, TOAD, ...) in die Datenbank eingebracht und arbeiten auf dem Datenbankserver, wenn sie aufgerufen werden. Stored Procedures können Parameter haben und Ergebnisse an den Aufrufer zurückgeben. Eine Stored Procedure kann SQL Befehle ausführen und die Sprache in der Stored Procedures geschrieben werden erlaubt Kontrollstrukturen und Exception Handling.
Eine Hello World Stored Procedure kann man mit SQLDeveloper erstellen. Dazu öffnet man ein Worksheet und trägt folgendes ein:
CREATE OR REPLACE
PROCEDURE helloworld AS
BEGIN
DBMS_OUTPUT.PUT('Hello ');
DBMS_OUTPUT.PUT_LINE('World!');
END;
/
Man führt das Sheet aus. Die Procedure wurde in die Datenbank übernommen und befindet sich im Ordner Procedures. Die Procedure kann nun noch fehlerhaft sein. Um eine Stored Procedure zu korrigieren muss man das Kontextmenü der Stored Procedure und edit auswählen. Der Edit Tab zeigt Fehler an und erlaubt das Editieren und Speichern des Codes in der Datenbank.
DBMS_OUTPUT.PUT() gibt einen String zunächst in den Puffer aus. Der String erscheint erst, wenn der Puffer ausgegeben wird. DBMS_OUTPUT.PUT_LINE() schreibt Dinge in den Puffer und leert den Puffer zusätzlich.
Procedures and Functions
http://www.gc.maricopa.edu/business/oracle/docs/Oracle8iDocs/java.815/a64686/04_call5.htm
Stored Procedures können entweder einen Rückgabewert zurückgeben oder nicht. Eine Stored Procedure mit Rückgabewert wird Function genannt und muss mit dem Schlüsselwort FUNCTION deklariert werden.
create or replace
FUNCTION getMEAtt RETURN types.meatt_array
AS
...
Eine Stored Procedure ohne Rückgabewert wird Procedure genannt und muss mit dem Schlüsselwort Procedure definiert werden
create or replace
PROCEDURE getMEAtt
AS
...
Functions und Procedures können Parameter haben. Hinter dem Namen der Procedur oder Funktion wird die Parameterliste in runden Klammern angegeben.
create or replace
FUNCTION getMEAtt(startIndex in INTEGER) RETURN meattarray
AS
Parameter können vom Typ in, out oder in out sein. in bedeutet, das der Parameter Daten enthält die die Procedur oder Funktion liest. out bedeutet, das die Prozedur oder Funktion den Inhalt des Parameters ignoriert und nur Ergebnisse in den Parameter schreibt, die der Aufrufer lesen kann. in out ist eine Kombination, bei der gelesen und geschrieben wird.
Die Verwendung der Parameter in einem Java Programm geschieht wie folgt:
OracleCallableStatement stmt
= (OracleCallableStatement)conn.prepareCall(
"begin ? := GETMEATT(?); end;" );
stmt.registerOutParameter(1, OracleTypes.ARRAY, "MEATTARRAY");
stmt.setInt(2, 30);
stmt.executeUpdate();
Parameter und Returnwerte werden durch Fragezeichen maskiert. Die Reihenfolge der Fragezeichen ist wichtig und muss beim registrieren oder setzen angegeben werden, damit der aktuelle Wert dem formalen Parameter zugewiesen werden kann.
Rückgabe mehrerer Zeilen
Dieser Abschnitt bespricht, wie man eine Stored Procedure schreibt, die mehrere Zeilen zurückgibt, diese Stored Procedure in einem Java Programm aufruft und die Zeilen ausgibt.
Die erste Möglichkeit ist, einen Cursor auf eine Tabelle innerhalb der StoredProcedure zu öffnen und diesen Cursor zurückzugeben. Das Java Programm kann den Cursor abfragen und auf alle Zeilen der Tabelle zugreifen.http://www.enterprisedt.com/publications/oracle/result_set.html
Die zweite Möglichkeit (http://www.oracle.com/technology/sample_code/tech/java/codesnippet/jdbc/varray/index.html) ist, das die StoredProcedure Zeilen aus der Tabelle in eine Collection speichert und dann diese Collection zurückgibt. Das Java Programm kann dann lediglich auf die Zeilen in der Collection zugreifen.
Als Collection werden hier VArrays verwendet. VArrays erhalten die Ordnung, man kann Cursor auf sie bilden und ihre Größe muss bei der Deklaration angegeben werden. Vor dem Einfügen eines Objekts in einen VArray muss man die extends() Methode aufrufen, die Platz für das Objekt reserviert aber maximal so viel Platz reservieren kann, wie bei der Delaration der VArray Variable angegeben worden ist.
Zeilen werden in den VArray kopiert, ein Cursor wird auf den VArray gebildet und der Cursor wird zurückgegeben. Das Java Programm kann den Cursor verwenden um auf die Zeilen zuzugreifen.
Zunächst muss der Array deklariert werden. Er muss in einem Package und nicht auf Schemaebene (ohne Package) deklariert werden, da er auf eine Tabelle bezug nimmt. (Was genau der Grund dafür ist, dass ein Type auf Schemaeebene keinen Bezug auf eine Tabelle nehmen darf, weiß ich nicht). Folgender Aufruf wäre daher unzulässig:
CREATE OR REPLACE TYPE meattarray AS VARRAY(100) OF MANAGEDELEMENTATTRIBUTES%ROWTYPE;
/
Im Package sieht das ganze wie folgt aus:
create or replace
PACKAGE types
AS
TYPE meatt_array IS VARRAY(100) OF MANAGEDELEMENTATTRIBUTES%ROWTYPE;
END;
/
Nun muss die Stored Procedure definiert werden. Es handelt sich um eine Function, da sie den Array zurückgibt.
create or replace
FUNCTION getMEAtt RETURN types.meatt_array
AS
attArr types.meatt_array := types.meatt_array();
CURSOR c_att IS SELECT * FROM MANAGEDELEMENTATTRIBUTES;
--r1 MANAGEDELEMENTATTRIBUTES%ROWTYPE;
i INT := 0;
BEGIN
--FOR r1 IN c_att LOOP
-- meatt_array.extend;
-- meatt_array(meatt_array.count) := r1;
--END LOOP;
OPEN c_att;
loop
--FETCH c_att into r1;
attArr.extend;
FETCH c_att into attArr(attArr.count);
--exit when c_auftrag_pos%NOTFOUND;
i := i + 1;
exit when (i >= 100);
end loop;
CLOSE c_att;
RETURN attArr;
END;
/
Beide Dinge (Type und Stored Procedure) werden in ein Worksheet eingetragen, welches ausgeführt wird und die Dinge in die Datenbank einträgt. Die Stored Procedure erzeugt eine Variable vom Type des VArray aus dem types Packge. Sie ruft den Konstruktor des Typs auf, da ansonsten eine Fehler auftritt, da die Collection ansonsten uninitialisiert bleibt.
Danach definiert sie einen Cursor c_att auf die Tabelle MANAGEDELEMENTATTRIBUTES. Der cursor wird geöffnet und 100 Einträge werden aus der Tabelle in den VArray kopiert, welcher dann zurückgegeben wird.
Leider führt dieser Code dazu, dass das Java Programm den Typ meatt_array nicht kennt und das ganze daher nicht funktioniert. Man muss die Typen auf Schemaebene deklarieren. Da man auf Schemaebene nicht auf die Tabellentypen zugreifen darf (erst ab ORACLE 11g), muss man den Typ der Tabellenzeilen als Object nachbilden:
create or replace
TYPE meattrowtype AS OBJECT
(
MANAGEDELEMENT NUMBER(8,0),
ATTRIBUTETYPE VARCHAR2(30),
CONFIGURATION NUMBER(8,0),
ATTRIBUTEVALUE VARCHAR2(30)
);
/
CREATE OR REPLACE TYPE meattarray AS VARRAY(100) OF meattrowtype;
/
create or replace
FUNCTION getMEAtt RETURN meattarray
AS
attArr meattarray := meattarray();
CURSOR c_att IS SELECT * FROM MANAGEDELEMENTATTRIBUTES ORDER BY MANAGEDELEMENT;
r1 MANAGEDELEMENTATTRIBUTES%ROWTYPE;
i INT := 0;
BEGIN
OPEN c_att;
loop
attArr.extend;
FETCH c_att into r1;
attArr(attArr.count).MANAGEDELEMENT := r1.MANAGEDELEMENT;
attArr(attArr.count).ATTRIBUTETYPE := r1.ATTRIBUTETYPE;
attArr(attArr.count).CONFIGURATION := r1.CONFIGURATION;
attArr(attArr.count).ATTRIBUTEVALUE := r1.ATTRIBUTEVALUE;
i := i + 1;
exit when (i >= 100);
end loop;
CLOSE c_att;
RETURN attArr;
END;
/
Für ihre Tabelle müssen Sie den meattrowtype und die Funktion an ihre Tabellenspalten anpassen.
Das Java Programm sieht wie folgt aus:
import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleTypes;
import oracle.sql.ARRAY;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.eclipse.swt.widgets.*;
public class Main {
Connection conn = null;
public static void main(String[] args) throws SQLException {
Main m = new Main();
m.establishDBConnection();
OracleCallableStatement stmt
= (OracleCallableStatement)m.conn.prepareCall(
"begin ? := GETMEATT; end;" );
// The name we use below, EMPARRAY, has to match the name of the
// type defined in the PL/SQL Stored Function
stmt.registerOutParameter(1, OracleTypes.ARRAY, "MEATTARRAY");
stmt.executeUpdate();
// Get the ARRAY object and print the meta data assosiated with it
ARRAY simpleArray = stmt.getARRAY(1);
System.out.println("Array is of type " + simpleArray.getSQLTypeName());
System.out.println("Array element is of type code " + simpleArray.getBaseType());
System.out.println("Array is of length " + simpleArray.length());
// Print the contents of the array
Object[] values = (Object[])simpleArray.getArray();
for (int i = 0; i < values.length; i++) {
oracle.sql.STRUCT object = (oracle.sql.STRUCT)values[i];
//System.out.println(object.debugString());
Object[] obs = object.getAttributes();
int meid = Integer.parseInt(obs[0].toString());
System.out.println("ME ID: " + meid);
}
}
/**
* To retrieve the thin driver visit:
* http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html
*
* @throws ClassNotFoundException
* @throws SQLException
*/
public final void establishDBConnection() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
System.out.println("Nms.establishDBConnection() - Could not load jdbc driver class");
conn = null;
return;
}
try {
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@192.168.4.4:3332:wie", "gehts", "dir");
} catch (SQLException e) {
System.out.println("Nms.establishDBConnection() - Could not establish connection");
conn = null;
return;
}
}
Packages
http://tim.hec.ca/oracle/appdev.920/a96624/09_packs.htm
Einschränkungen von Paketen
- Object Types können nicht in Paketen definiert werden.
- Aus einem Java JDBC Programm kann man mittels Returnwerten von Functions nicht auf Datentypen zugreifen, die innerhalb eines Pakets definiert sind! Man muss diese Datentypen außerhalb eines Pakets definieren. Möchte man einen Returnwert mit einem Typ deklarieren, der in einem Paket definiert ist, und diese Function aus einem Java JDBC Program heraus aufrufen, dann erhält man eine Ungültiges Namensmuster: Exception
Pakete beinhalten PLSQL types, item und subprograms. Pakete können keine PLSQL Object types enthalten! Defining Object Types. Ein Package besteht as einer Spec und einem Body. Alles in der Spec ist für die Anwendung, die das Paket verwendet sichtbar, alles im Body ist für die Anwendung nicht sichtbar. In der Spec müssen subprograms am Ende nach allen anderen Objekten deklariert werden. Um auf Objekte zuzugreifen, die in einem Paket definiert sind, muss man den Namen des Pakets getrennt durch einen Punkt vor den Namen des Objekts schreiben. Der Body darf nicht leer sein.
Um ein Paket mit SQL Developer zu erstellen, muss man ein SQL Skript schreiben und in einer .sql Textdatei speichern. Dann öffnet man in SQL Developer ein worksheet und öffnet darin das SQL Skript. Jetzt führt man das Skript aus. Die SQL Befehle im Skript erzeugen das Paket. Dabei ist wichtig, dass man ein / hinter die Spec und hinter den Body einfügt. / führt einen vorhergehenden SQL Befehl im Skript aus. Ein Beispiel für ein Skript ist folgendes:
CREATE OR REPLACE TYPE merowtype AS OBJECT
(
ID NUMBER(8,0),
CONFIGURATION NUMBER(8,0),
NAME VARCHAR2(50),
LOCATION NUMBER(8,0),
PARENTMANAGEDELEMENT NUMBER(8,0),
TYPE VARCHAR2(20),
STATE NUMBER(8,0),
MANUFACTURER VARCHAR2(50),
MANAGEDELEMENTVERSION VARCHAR2(50)
);
/
-- bodies dürfen nicht leer sein
--CREATE OR REPLACE TYPE BODY merowtype AS
--END merowtype;
--/
CREATE OR REPLACE PACKAGE NmsEms
AS
TYPE mearray IS VARRAY(100) OF merowtype;
FUNCTION getME(startIndex in INTEGER, config in INTEGER) RETURN mearray;
END NmsEms;
/
CREATE OR REPLACE PACKAGE BODY NmsEms
AS
FUNCTION getME(startIndex in INTEGER, config in INTEGER) RETURN mearray
IS
arr mearray := mearray();
CURSOR cur IS SELECT * FROM MANAGEDELEMENT WHERE configuration = config ORDER BY ID;
r1 MANAGEDELEMENT%ROWTYPE;
moveToStart INT := 1;
i INT := 0;
BEGIN
OPEN cur;
-- navigate to start
loop
exit when ((moveToStart = startIndex) OR cur%NOTFOUND);
FETCH cur into r1;
exit when cur%NOTFOUND;
moveToStart := moveToStart + 1;
end loop;
-- store into array
loop
arr.extend;
arr(arr.count) := merowtype(0, 0, '', 0, 0, '', 0, '', '');
FETCH cur into r1;
arr(arr.count).MANAGEDELEMENT := r1.MANAGEDELEMENT;
arr(arr.count).ATTRIBUTETTYPE := r1.ATTRIBUTETYPE;
arr(arr.count).CONFIGURATION := r1.CONFIGURATION;
arr(arr.count).ATTRIBUTETVALUE := r1.ATTRIBUTEVALUE;
i := i + 1;
exit when ((i >= 100) OR cur%NOTFOUND);
end loop;
CLOSE cur;
RETURN arr;
END getME;
END NmsEms;
/
Um die Prozedur per SQL Skript auszuführen, verwenden Sie folgendes Skript
DECLARE
a NmsEms.mearray;
BEGIN
a := NmsEms.getME(1, 1);
END;
/
Object Types
http://download.oracle.com/docs/cd/B12037_01/appdev.101/b10807/10_objs.htm
Object types dürfen nicht in Packages definiert werden! Object Types sind Objekte im Sinne von Objektorientierten Programmiersprachen. Man kann Instanzen eines ObjectTypes erzeugen und verwenden. Man kann Object Types ableiten, Methoden überladen und generell Dinge mit Object Types tun, die man aus der OOP kennt.
Native Dynamic SQL in Java
Native Dynamic SQL http://download.oracle.com/docs/cd/B10500_01/appdev.920/a96624/11_dynam.htm ermöglicht die programmatische Formulierung und Ausführung von SQL-Statements zur Laufzeit. Das SQL-Statement wird in einen String der Programmiersprache gespeichert. Das SQL-Statement kann ein normales SQL-Statement oder auch PL/SQL sein. In die Native Dynamic SQL Statements können Variablen in Form von Fragezeichen eingebaut werden. Schemaobjekte wie Tabellen können leider nicht durch Variablen ersetzt werden. Schemaobjekte müssen immer in den SQL String eingesetzt werden und können variabel gehalten werden, indem man programmatisch einen String zusammenbaut.
Native Dynamic SQL in PL/SQL
Einleitung
In einer PLSQL Procedure oder Function kann man SQL Statements oder Blöcke als String Variablen definieren und diese Strings dann mit den Schlüsselwörtern EXECUTE IMMEDIATE ausführen.
CREATE PROCEDURE drop_table () AS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE employees';
END;
/
Damit ist es möglich SQL Statements im BEGIN END Bereich dynamisch zu formulieren. Ein Cursor muss beispielsweiße nicht mehr direkt bei seiner Deklaration festgelegt werden, sondern das Auswahlkriterium des Cursors kann dynamisch im Body der Procedure oder Function erstellt werden.
Bind Variables
SQL Statements oder Blöcke werden als String Variablen definiert um sie mit EXECUTE IMMEDIATE ausführen zu können. Dynamische Werte könnten durch String Konkatenation eingebunden werden.
CREATE PROCEDURE fire_employee (emp_id NUMBER) AS
BEGIN
EXECUTE IMMEDIATE
'DELETE FROM employees WHERE employee_id = ' || TO_CHAR(emp_id);
END;
/
Hier wird allerdings jedesmal ein neues Statement geparst und ein Ausführungsplan muss jedesmal erneut erstellt werden. Dies its vergleichbar mit einem Statement von JDBC. Eine Verbesserung bringen bind variablen. Eine Bindvariable wird in den Ausführungsplan eingebaut und dieser kann dann für unterschiedliche Werte der Variable wiederverwendet werden. Dies ist dann vergleichbar mit PreparedStatements von JDBC.
CREATE PROCEDURE fire_employee (emp_id NUMBER) AS
BEGIN
EXECUTE IMMEDIATE
'DELETE FROM employees WHERE employee_id = :id' USING emp_id;
END;
/
Das Statement wird als String notiert. Darin wird die Bind Variable :id mit Doppelpunkt notiert. Beim Aufruf von EXECUTE IMMEDIATE wird mit dem USING Schlüsselwert ein Wert an die Variable gebunden. ACHTUNG: Es können keine Schema Objekte durch Bind Variblen gebunden werden! Also Tabellen, Indizes, Constraints, ... Schemaobjekte müssen durch String Konkatenation eingebracht werden! ACHTUNG: In SQL Statements werden die Bindvariablen nicht per Name sondern per Position durch die USING Angaben mit Werten belegt. ACHTUNG: Wenn das SQL Statment einen PL/SQL Block beschreibt, werden die Bindvariablen nochmals auf andere Weise an die Werte der USING Angaben gebunden. Siehe http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/dynamic.htm.
Cursor in NativeDynamic PL/SQL
zum Seitenanfang
zur Hauptseite
Letzte Änderung: 20.01.2009