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


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