Händler-Datenbank (SQL-Beispiel)/Selektion: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Zeile 280: Zeile 280:


===Weitere – eher sinnlose – Anfragen an die <code>liefert</code>-Tabelle===
===Weitere – eher sinnlose – Anfragen an die <code>liefert</code>-Tabelle===
Für welche <code>liefert</code>-Tupel ist die Lieferzeit gleich (<code>=</code>) <code>NULL</code>?


Für welche <code>liefert</code>-Tupel ist die Lieferzeit und Händler-ID überein?
<source lang="sql">
<source lang="sql">
SELECT *  
SELECT *  
FROM  liefert  
FROM  liefert  
WHERE   l_lieferzeit =  NULL; -- an Stelle von l_lieferzeit IS  NULL
WHERE h_id = l_lieferzeit;
</source>
</source>
<table>
<table>
<tr><td><math>σ_{\texttt{ l_lieferzeit =  NULL}}(\texttt{liefert})</math></td></tr>
<tr><td><math>σ_{\texttt{h_id = l_lieferzeit}}(\texttt{liefert})</math></td></tr>
<tr>
<tr>
<td><table class="datatable-sql">
<td><table class="datatable-sql">
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
<tr><td> 1 </td><td> 1 </td><td align="right"> 200.00 </td><td> 1 </td></tr>
<tr><td> 1 </td><td> 4 </td><td align="right"> 10.00 </td><td> 1 </td></tr>
<tr><td> 1 </td><td> 5 </td><td align="right"> 5.00 </td><td> 1 </td></tr>
</table></td>
</table></td>
</tr>
</tr>
</table>
</table>
Der Test auf Gleicheit eines Wertes mit <code>NULL</code> liefert stets den Wert <code>UNKNOWN</code>. Daher ist das Ergebnis der Anfrage leer.
Korrekt wäre der Test <code>l_lieferzeit IS NULL</code>.


Für welche <code>liefert</code>-Tupel ist die Lieferzeit und Händler-ID überein?
Für welche <code>liefert</code>-Tupel ist unbekannt, ob die Lieferzeit und Händler-ID übereinstimmen?
 
<source lang="sql">
<source lang="sql">
SELECT *  
SELECT *  
FROM  liefert  
FROM  liefert  
WHERE  h_id = l_lieferzeit;
WHERE  (h_id = l_lieferzeit) IS UNKNOWN;
</source>
</source>
<table>
<table>
<tr><td><math>σ_{\texttt{h_id = l_lieferzeit}}(\texttt{liefert})</math></td></tr>
<tr><td><math>σ_{\texttt{(h_id = l_lieferzeit) IS UNKNOWN}}(\texttt{liefert})</math></td></tr>
<tr>
<tr>
<td><table class="datatable-sql">
<td><table class="datatable-sql">
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
  <tr><td> 1 </td><td> 1 </td><td align="right"> 200.00 </td><td> 1 </td></tr>
  <tr><td> 1 </td><td> 2 </td><td align="right"> 100.00 </td><td> NULL </td></tr>
  <tr><td> 1 </td><td> 4 </td><td align="right"> 10.00 </td><td> 1 </td></tr>
  <tr><td> 2 </td><td> 1 </td><td align="right"> 160.00 </td><td> NULL </td></tr>
  <tr><td> 1 </td><td> 5 </td><td align="right"> 5.00 </td><td> 1 </td></tr>
  <tr><td> 2 </td><td> 2 </td><td align="right"> 180.00 </td><td> NULL </td></tr>
</table></td>
</table></td>
</tr>
</tr>
</table>
</table>


Für welche <code>liefert</code>-Tupel ist unbekannt, ob die Lieferzeit und Händler-ID übereinstimmen?
Für welche <code>liefert</code>-Tupel ist die Lieferzeit gleich (<code>=</code>) <code>NULL</code>?


<source lang="sql">
<source lang="sql">
SELECT *  
SELECT *  
FROM  liefert  
FROM  liefert  
WHERE  (h_id = l_lieferzeit) IS UNKNOWN;
WHERE   l_lieferzeit = NULL; -- an Stelle von l_lieferzeit IS NULL
</source>
</source>
<table>
<table>
<tr><td><math>σ_{\texttt{(h_id = l_lieferzeit) IS UNKNOWN}}(\texttt{liefert})</math></td></tr>
<tr><td><math>σ_{\texttt{ l_lieferzeit = NULL}}(\texttt{liefert})</math></td></tr>
<tr>
<tr>
<td><table class="datatable-sql">
<td><table class="datatable-sql">
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
  <tr><th> h_id </th><th> w_id </th><th> l_preis </th><th> l_lieferzeit </th></tr>
<tr><td> 1 </td><td> 2 </td><td align="right"> 100.00 </td><td> NULL </td></tr>
<tr><td> 2 </td><td> 1 </td><td align="right"> 160.00 </td><td> NULL </td></tr>
<tr><td> 2 </td><td> 2 </td><td align="right"> 180.00 </td><td> NULL </td></tr>
</table></td>
</table></td>
</tr>
</tr>
</table>
</table>
Der Test auf Gleicheit eines Wertes mit <code>NULL</code> liefert stets den Wert <code>UNKNOWN</code>. Daher ist das Ergebnis der Anfrage leer.
Korrekt wäre der Test <code>l_lieferzeit IS NULL</code>.
===Noch einmal Tests mit <code>NULL</code>===
<source lang="sql">
SELECT  1 AS ergebnis
WHERE  5 + NULL IS  NULL;
</source>
<table>
<tr><td><math>\texttt{leere_tabelle}</math></td><td>→&nbsp;&nbsp;</td><td><math>σ_{\bot}(\texttt{haendler})</math></td></tr>
<tr>
<td><table class="datatable-sql">
<tr><th></th></tr>
</table></td>
<td>→&nbsp;&nbsp;</td>
<td><table class="datatable-sql">
<tr><th>ergebnis</th></tr>
<tr><td> 1 </td></tr>
</table></td>
</tr>
</table>
<source lang="sql">
SELECT  1 AS ergebnis
WHERE  5 + NULL I=  NULL;
</source>
<table>
<tr><td><math>\texttt{leere_tabelle}</math></td><td>→&nbsp;&nbsp;</td><td><math>σ_{\bot}(\texttt{haendler})</math></td></tr>
<tr>
<td><table class="datatable-sql">
<tr><th></th></tr>
</table></td>
<td>→&nbsp;&nbsp;</td>
<td><table class="datatable-sql">
<tr><th>ergebnis</th></tr>
</table></td>
</tr>
</table>
Diese Anfragen sind nicht standard-konform, werden aber sowohl von Postgres als auch von SQLite unterstützt. Laut SQL-Standard muss eine Select-Anweisung eine From-Klausel enthalten.<ref>{{Quelle|ISO 9075-2 (2013)}}, <code>&lt;query specification&gt;</code>, S. 437, <code>&lt;table expression&gt;</code>, S. 368</ref>. Laut SQL-Standard
müsste man eine Tabelle ({{zB}} mit Namen <code>one</code>) definieren, die genau Zeile enthält, und in diese beiden Queries die FROM-Klausel <code>FROM one</code> einfügen.


==Quellen==
==Quellen==

Version vom 15. Oktober 2019, 08:31 Uhr

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 1
(zu gering)
Quellenangaben: 4
(fast vollständig vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 5
(ausgezeichnet)

Die nachfolgenden Beispiele können beispielsweise mit SQLite oder PostgreSQL getestet werden. Installieren Sie dazu die zugehörige Händler-Datenbank.

Die Selektionsfunktion

Eine Selektionsfunktion entfernt Zeilen (= Tupel) aus einer Tabelle.

In jeder Relationalen Algebra gibt es unendlich viele (üblicherweise abzählbar viele) partielle Selektionsfunktionen.

Es sein $ b $ eine Funktion, die jedem Tupel der Art $ (a_1:v_1, \ldots, a_n:v_n) $ einen booleschen Wert (true/$ \top $, false/$ \bot $, unknown/$ U $) zuweist. Dabei seien $ a_1, \ldots a_n $ Attributnamen und $ v_1, \ldots v_n $ Werte der zugehörigen Domänen $ D_1, \ldots D_n $. Die Selektionsfunktion

$ σ_b: R \rightharpoonup R $

überprüft für jedes Tupel $ (a_1:v_1, \ldots, a_n:v_n) $ einer Relation $ r $, die nur Tupel dieser Art enthält, ob die Bedingungsfunktion $ b $ für das jeweilige Tupel den Wert true liefert:

$ b((a_1:v_1, \ldots, a_n:v_n)) = \top $

Ist dies der Fall, so wird das entsprechende Tupel in die Ergebnisrelation eingefügt, anderenfalls wird es „entfernt“.

Für Relationen, die Tupel anderer Bauart enthalten, d. h. andere Attribute oder gleichnamige Attribute mit nicht-kompatiblen Domänen, ist die Selektionsfunktion $ σ_b $ nicht definiert.

Beispiele bezüglich der Händler-Datenbank

In SQL muss in der SELECT-Klausel immer eine Projektionsliste angegeben werden, auch wenn gar keine Projektion benötigt wird. Da es in den folgenden Beispielen nur um die Selektion geht (WHERE-Klausel), wird jeweils die Projektionsklausel SELECT * verwendet. In produktivem Code sollte man dies vermeiden und in SELECT-Klausel immer alle benötigten Attribute explizit aufzählen, da sich die Anzahl und die Reihenfolge der Attribute einer Tabelle im Laufe der Zeit ändern kann (Schemaevolution).

Selektion aller Tupel der Tabelle haendler (Identität)

SELECT *
FROM   haendler
WHERE  true
$ \texttt{haendler} $→  $ σ_{\top}(\texttt{haendler}) $
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg
→  
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg

Selektion von keinem einzigen Tupel der Tabelle haendler

SELECT h_id, h_name, h_ortschaft
FROM   haendler
WHERE  false
SELECT h_id, h_name, h_ortschaft
FROM   haendler
WHERE  null
$ \texttt{haendler} $→  $ σ_{\bot}(\texttt{haendler}) $
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg
→  
h_idh_nameh_ortschaft

Selektion aller Händler aus Königsbrunn

SELECT *
FROM   haendler
WHERE  h_ortschaft = 'Königsbrunn'
$ \texttt{haendler} $→  $ σ_{\texttt{h_ortschaft} = \texttt{'Königsbrunn'}}(\texttt{haendler}) $
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg
→  
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn

Selektion aller Händler, deren Name mit 'M' beginnt

SELECT *
FROM   haendler
WHERE  h_name LIKE 'M%'
SELECT *
FROM   haendler
WHERE  h_name SIMILAR TO 'M_*'
-- POSIX Regular Expressions (Postgres)
SELECT * 
FROM   haendler
WHERE  h_name ~ '^M'
$ \texttt{haendler} $→  $ σ_{\texttt{h_name LIKE 'M%'}}(\texttt{haendler}) $
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg
→  
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg

Selektion aller Händler, deren Ortschaft auf 'burg' endet

SELECT *
FROM   haendler
WHERE  h_ortschaft LIKE '%burg'
SELECT *
FROM   haendler
WHERE  h_ortschaft SIMILAR TO '_*burg'
-- POSIX Regular Expressions (Postgres)
SELECT * 
FROM   haendler
WHERE  h_ortschaft ~ 'burg$'
$ \texttt{haendler} $→  $ σ_{\texttt{h_ortschaft LIKE '%burg'}}(\texttt{haendler}) $
h_idh_nameh_ortschaft
1 Maier Königsbrunn
2 Müller Königsbrunn
3 Maier Augsburg
4 Huber NULL
5 Schmidt Hamburg
→  
h_idh_nameh_ortschaft
3 Maier Augsburg
5 Schmidt Hamburg

Achtung: Dies ist eine teure Operation, da die Gesamte Händler-Tabelle durchlaufen und jeder Händlername überprüft werden muss. Endtrunkierung sollte grundsätzlich vermieden werden. Stattdessen sollte man einen Volltextindex verwenden, der Endtrunkierung unterstützt.

Selektion aller liefert-Tupel, bei denen die Lieferzeit bekannt ist

SELECT * 
FROM   liefert 
WHERE  l_lieferzeit IS NOT NULL;
$ \texttt{liefert} $→  $ σ_{\texttt{l_lieferzeit IS NOT NULL}}(\texttt{liefert}) $
h_id w_id l_preis l_lieferzeit
1 1 200.00 1
1 1 194.00 6
1 2 100.00 NULL
1 3 150.00 7
1 4 10.00 1
1 5 5.00 1
2 1 160.00 NULL
2 1 190.00 1
2 2 180.00 NULL
2 3 170.00 4
3 1 195.00 2
3 2 190.00 1
4 1 150.00 3
4 3 180.00 5
4 3 199.00 1
→  
h_id w_id l_preis l_lieferzeit
1 1 200.00 1
1 1 194.00 6
1 3 150.00 7
1 4 10.00 1
1 5 5.00 1
2 1 190.00 1
2 3 170.00 4
3 1 195.00 2
3 2 190.00 1
4 1 150.00 3
4 3 180.00 5
4 3 199.00 1

Selektion aller liefert-Tupel, bei denen die Lieferzeit unbekannt ist

SELECT * 
FROM   liefert 
WHERE  l_lieferzeit IS NOT NULL;
$ \texttt{liefert} $→  $ σ_{\texttt{l_lieferzeit IS NOT NULL}}(\texttt{liefert}) $
h_id w_id l_preis l_lieferzeit
1 1 200.00 1
1 1 194.00 6
1 2 100.00 NULL
1 3 150.00 7
1 4 10.00 1
1 5 5.00 1
2 1 160.00 NULL
2 1 190.00 1
2 2 180.00 NULL
2 3 170.00 4
3 1 195.00 2
3 2 190.00 1
4 1 150.00 3
4 3 180.00 5
4 3 199.00 1
→  
h_id w_id l_preis l_lieferzeit
1 2 100.00 NULL
2 1 160.00 NULL
2 2 180.00 NULL

Weitere – eher sinnlose – Anfragen an die liefert-Tabelle

Für welche liefert-Tupel ist die Lieferzeit und Händler-ID überein?

SELECT * 
FROM   liefert 
WHERE  h_id = l_lieferzeit;
$ σ_{\texttt{h_id = l_lieferzeit}}(\texttt{liefert}) $
h_id w_id l_preis l_lieferzeit
1 1 200.00 1
1 4 10.00 1
1 5 5.00 1

Für welche liefert-Tupel ist unbekannt, ob die Lieferzeit und Händler-ID übereinstimmen?

SELECT * 
FROM   liefert 
WHERE  (h_id = l_lieferzeit) IS UNKNOWN;
$ σ_{\texttt{(h_id = l_lieferzeit) IS UNKNOWN}}(\texttt{liefert}) $
h_id w_id l_preis l_lieferzeit
1 2 100.00 NULL
2 1 160.00 NULL
2 2 180.00 NULL

Für welche liefert-Tupel ist die Lieferzeit gleich (=) NULL?

SELECT * 
FROM   liefert 
WHERE   l_lieferzeit =  NULL; -- an Stelle von l_lieferzeit IS  NULL
$ σ_{\texttt{ l_lieferzeit = NULL}}(\texttt{liefert}) $
h_id w_id l_preis l_lieferzeit

Der Test auf Gleicheit eines Wertes mit NULL liefert stets den Wert UNKNOWN. Daher ist das Ergebnis der Anfrage leer. Korrekt wäre der Test l_lieferzeit IS NULL.

Noch einmal Tests mit NULL

SELECT  1 AS ergebnis
WHERE   5 + NULL IS  NULL;
$ \texttt{leere_tabelle} $→  $ σ_{\bot}(\texttt{haendler}) $
→  
ergebnis
1
SELECT  1 AS ergebnis
WHERE   5 + NULL I=  NULL;
$ \texttt{leere_tabelle} $→  $ σ_{\bot}(\texttt{haendler}) $
→  
ergebnis

Diese Anfragen sind nicht standard-konform, werden aber sowohl von Postgres als auch von SQLite unterstützt. Laut SQL-Standard muss eine Select-Anweisung eine From-Klausel enthalten.[1]. Laut SQL-Standard müsste man eine Tabelle (z. B. mit Namen one) definieren, die genau Zeile enthält, und in diese beiden Queries die FROM-Klausel FROM one einfügen.

Quellen

  1. , <query specification>, S. 437, <table expression>, S. 368
  1. Kowarschick (MMDB-Skript): Wolfgang Kowarschick; Vorlesung Multimedia-Datenbanksysteme – Sommersemester 2018; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 4 (Skript)
  2. Kowarschick (MMDB): Wolfgang Kowarschick; Vorlesung „Multimedia-Datenbanksysteme“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2016; Quellengüte: 3 (Vorlesung), https://kowa.hs-augsburg.de/mmdb/mmdb-beispiele/haendler-datenbank/

Siehe auch