# SQL

## Conditions Basics

Manchmal möchten wir Datensätze abrufen, die eine bestimmte Bedingung erfüllen.

Zum Beispiel

- alle Datensätze abrufen, die den Familiennamen „Aothly“ haben 

- alle Datensätze abrufen, bei denen der Betrag größer als 5 ist

- Alle Datensätze mit dem Land „Mexico“ abrufen

Um Bedingungen hinzuzufügen, können wir das `WHERE`-Schlüsselwort verwenden

Zum Beispiel hier ist eine **Verkäufe**-Tabelle:

| Münze | Menge |
| ----- | ----- |
| AGK   | 13    |
| GOL   | 21    |
| KLA   | 15    |
| AGK   | 18    |

Um alle Datensätze mit der Coin „AGK“ abzurufen, schreibt man:

```sql
SELECT * FROM sales WHERE coin = 'AGK'
```

Um alle Datensätze mit `amount` kleiner oder gleich 20 abzurufen, schreibt man:

```sql
SELECT * FROM sales WHERE amount <= 20
```



### Unique values

Angenommen man hat die folgende Tabelle:

**Verkäufe**

|      | Land        | Stadt    | Betrag |
| ---- | ----------- | -------- | ------ |
| 1    | Polen       | Warschau | 13     |
| 2    | Deutschland | Berlin   | 24     |
| 3    | Polen       | Katowice | 56     |

Man möchte  alle Länder wissen, in denen das Produkt verkauft wurde.

Wenn man die normale Abfrage, die man kennt, verwendet: `SELECT country from sales` liefert sie `Poland`, `Germany`, `Poland`. Das ist nicht das, wonach man sucht, weil Polen zweimal wiederholt wird.

Um es zu lösen, kann man das `DISTINCT`-Schlüsselwort verwenden:

### NOT

Das `NOT`-Schlüsselwort bedeutet, dass man nicht möchte, dass die Bedingung erfüllt wird.

Zum Beispiel betrachte man die folgende **people**-Tabelle:

| Name   | Alter | Geschlecht |
| ------ | ----- | ---------- |
| Joas   | 13    | männlich   |
| Holwa  | 17    | männlich   |
| Nohlas | 24    | weiblich   |
| Polar  | 23    | männlich   |
| Loopa  | 18    | weiblich   |

```sql
SELECT * FROM people WHERE NOT gender = 'male'
```

Dies wird das Ergebnis sein:

| Name   | Alter | Geschlecht |
| ------ | ----- | ---------- |
| Nohlas | 24    | weiblich   |
| Loopa  | 18    | weiblich   |

Das `NOT`-Schlüsselwort kehrt die Bedingung im Wesentlichen um. Zum Beispiel sind die folgenden Abfragen gleich:

```sql
WHERE age > 20```

```sql
WHERE NOT age <= 20```

### AND

Das `AND`-Schlüsselwort bedeutet, dass **beide** Bedingungen wahr sein müssen; wenn eine von ihnen nicht der Fall ist, wird die Bedingung nicht erfüllt.

Zum Beispiel ist hier eine `people`-Tabelle:

| Name   | Alter | Geschlecht |
| ------ | ----- | ---------- |
| Joas   | 13    | männlich   |
| Holwa  | 17    | männlich   |
| Nohlas | 24    | weiblich   |
| Polar  | 23    | männlich   |
| Loopa  | 18    | weiblich   |

Die folgende Abfrage:

```sql
SELECT * FROM people WHERE gender = "female" AND age < 20
```

bedeutet, dass man nach allen Datensätzen sucht, bei denen das Geschlecht „female“ ist und das Alter kleiner als 20 ist.

Dies wird das Ergebnis sein:

| Name  | Alter | Geschlecht |
| ----- | ----- | ---------- |
| Loopa | 18    | weiblich   |

### OR

Das `OR`-Schlüsselwort bedeutet, dass eine der Bedingungen wahr sein soll.

Zum Beispiel betrachtet man die folgende **people**-Tabelle:

| name   | age  | gender |
| ------ | ---- | ------ |
| Joas   | 13   | male   |
| Holwa  | 17   | male   |
| Nohlas | 24   | female |
| Polar  | 23   | male   |
| Loopa  | 18   | female |

```sql
SELECT * FROM people WHERE gender = 'female' OR age < 20
```

Diese Abfrage bedeutet, dass man nach allen Datensätzen sucht, bei denen entweder das Geschlecht weiblich ist oder das Alter unter 20 liegt.

Das wird das Ergebnis sein:

| Name   | Alter | Geschlecht |
| ------ | ----- | ---------- |
| Joas   | 13    | männlich   |
| Holwa  | 17    | männlich   |
| Nohlas | 24    | weiblich   |
| Loopa  | 18    | weiblich   |

###################
## Kombination von Conditions

Das Erstellen einer Abfrage mit nur einer Bedingung ist nicht ausreichend. Manchmal möchte man etwas Komplizierteres überprüfen. Dafür haben SQL (und viele andere Programmiersprachen) die AND-, OR- und NOT-Schlüsselwörter, um unsere Fähigkeit zu verbessern, das gewünschte Ergebnis abzurufen.

Die AND und OR Schlüsselwörter werden wie folgt verwendet:

```sql
SELECT col1, col2 FROM table1 WHERE condition1 AND condition2 OR condition3 ...
```

Man kann so viele Bedingungen wie man will zusammen stapeln.
###################

## Sortierung (ORDER BY)

`... ORDER BY ASC`, das wird standardmäßig gesetzt

`ASC` --> Aufsteigend --> kleinster Wert zuerst

`DESC` --> Absteigend --< Größter Wert zuerst
### Beispiele und Erklärung
Beim Abfragen einer Datenbank kann die Organisation der Ergebnisse in einer sinnvollen Reihenfolge die Datenanalyse erheblich effizienter machen. Um das Ergebnis zu sortieren, verwendet man das ORDER BY-Schlüsselwort und danach sollte man angeben, nach welchem Feld man sortiert. Standardmäßig sortiert es in aufsteigender Reihenfolge.

Zum Beispiel betrachten Sie die folgende **competition**-Tabelle:

| runner_id | age  | avg_speed |
| --------- | ---- | --------- |
| 1         | 47   | 3.65      |
| 2         | 62   | 3.07      |
| 3         | 57   | 6.82      |
| 4         | 56   | 4.34      |
| 5         | 25   | 4.93      |
| 6         | 40   | 3.94      |
| 7         | 23   | 6.58      |
| 8         | 40   | 3.43      |



`SELECT * FROM competition WHERE age > 50 ORDER BY avg_speed`

Dies ist das Ergebnis

| runner_id | age  | avg_speed |
| --------- | ---- | --------- |
| 2         | 62   | 3.07      |
| 4         | 56   | 4.34      |
| 3         | 57   | 6.82      |

Um anzugeben, wie diese Daten sortiert werden sollen, können wir die `DESC`- oder `ASC`-Schlüsselwörter nach dem Namen der Spalte hinzufügen.

`ORDER BY avg_speed ASC`

## Eigenschaften einer Tabelle
`DESCRIBE <tabelle>`
oder 
`SHOW COLUMNS FROM <tabelle>`

## Neuer Datensatz
INSERT INTO <tabelle> (<spalte><spalte>,...) VALUES (<wert>,<wert>,...)

## Update Datensatz
```sql
UPDATE <tabelle> set <spalte> = <wert>,  <spalte> = <wert>, ... WHERE <Bedingung>
```

## Anlegen eines Users mit Rechten

```sql
CREATE USER 'sammy'@'localhost' IDENTIFIED BY 'password';
```

## Rechte setzen

```sql
GRANT PRIVILEGE ON database.table TO 'username'@'host';
```

- `CREATE`: Er­mög­licht es Benutzern, eine Datenbank oder Tabelle zu erstellen.
- `SELECT`: Erlaubt Benutzern, Daten abzurufen.
- `INSERT`: Er­mög­licht es Benutzern, neue Einträge in Tabellen hin­zu­zu­fü­gen.
- `UPDATE`: Er­mög­licht es Benutzern, be­stehen­de Einträge in Tabellen zu ändern.
- `DELETE`: Er­mög­licht es Benutzern, Ta­bel­len­ein­trä­ge zu löschen.
- `DROP`: Benutzer können ganze Da­ten­bank­ta­bel­len löschen.

Somit also

```sql
GRANT SELECT, CREATE  ON database.table TO 'username'@'host';
```

## Einlesen der Berechtigungstabellen

Aktivieren mit 
```sql
FLUSH PRIVILEGES;
```

## Entziehen von Rechten
```sql
REVOKE type_of_permission ON database_name.table_name FROM 'username'@'host';
```

## Anzeigen der aktuellen Berechtigungen

```sql
SHOW GRANTS FOR 'username'@'host';
```

## User löschen

```sql
DROP USER 'username'@'localhost';
```

## IN

IN ist die vereinfachte Schreibweise für OR. Hier wird jeder Begriff, die per Kommata getrennt sind, der in der Klammer nach dem IN steht per OR abgefragt

## BETWEEN

Anstatt zu schreiben:

```sql
WHERE col1 >= 5 AND col1 <= 10
```

Kann man folgendes schreiben:

```sql
WHERE col1 BETWEEN 5 AND 10
```

Der `BETWEEN`-Operator ist inklusiv, was bedeutet, dass er die Grenzwerte (in diesem Fall 5 und 10) in die Ergebnisse einschließt. Dies macht die SQL-Abfragen sauberer und lesbarer, insbesondere bei der Arbeit mit Datumsbereichen oder numerischen Intervallen.

## LIKE

Das `LIKE`-Schlüsselwort wird verwendet, um Ähnlichkeiten von Zeichenketten zu prüfen. Beispielsweise, wenn wir alle Datensätze abrufen möchten, deren Name mit dem Buchstaben `a` beginnt, dann verwenden wir das `LIKE`-Schlüsselwort.

Zwei Hauptwildcards werden verwendet:

- `%` - steht für eine beliebige Anzahl von Zeichen
- `_` - steht für genau ein Zeichen

Zum Beispiel:

- `%a` - bedeutet jede Zeichenkette, die mit `a` endet
- `a%` - bedeutet jede Zeichenkette, die mit `a` beginnt

- `%a%` - bedeutet jeder String, der `a` enthält
- `_a%` - bedeutet, dass der Buchstabe `a` der zweite Buchstabe im String ist

- `%a__` - bedeutet, dass der String `a` an der drittletzten Stelle enthält

 Um es zu verwenden, schreiben wir:

```sql
SELECT col1, col2, ...
FROM table1
WHERE col1 LIKE '%a__'
```

**Beispiel**

Suche aller Personen deren Name mit Gross-K beginnt und mit klein-a endet, sortiert nach Name in absteigender Reihenfolge

```sql
select * from people where name like 'K%a' order by name desc;
```



## Tabelle anlegen

CREATE TABLE Persons (
 PersonID int PRIMARY KEY AUTO_INCREMENT,
 LastName varchar(255) NOT NULL,
 FirstName varchar(255),
 Address varchar(255),
 City varchar(255)
);





|                     **Datentyp**                      |               **MySQL-Format**               |            **PostgreSQL-Format**             |                   **INSERT INTO Beispiel**                   |
| :---------------------------------------------------: | :------------------------------------------: | :------------------------------------------: | :----------------------------------------------------------: |
|      **Zeichenkette (TEXT, VARCHAR, CHAR usw.)**      | Eingeschlossen in einfache Anführungszeichen | Eingeschlossen in einfache Anführungszeichen |  `INSERT INTO tableName (columnName) VALUES ('John Doe');`   |
| **Zahl (Ganzzahl, Dezimalzahl, Gleitkommazahl usw.)** |           Keine Anführungszeichen            |           Keine Anführungszeichen            |      `INSERT INTO tableName (columnName) VALUES (25);`       |
|                  **Boolescher Wert**                  |       WAHR oder FALSCH (oder 1 und 0)        |               WAHR oder FALSCH               |     `INSERT INTO tableName (columnName) VALUES (TRUE);`      |
|          **Datum, Uhrzeit und Zeitstempel**           |             JJJJ-MM-TT HH:MM:SS              |             JJJJ-MM-TT HH:MM:SS              | `INSERT INTO tableName (dateTimeColumn) VALUES ('2023-08-18 12:45:00');` |

## Bestimmte Zeilen aus einer Tabelle kopieren

Wenn man bestimmte Zeilen basierend aus einer Bedingung kopieren möchten, kann man die `SELECT`Anweisung mit . kombinieren `INSERT INTO`.

**Syntax** :

```sql
INSERT INTO table_name1
SELECT columns FROM table_name2 WHERE condition;
```

## Import einer Datenbank

mysql <DB> < <SQL-File>

## Rechte für die Datenbank 

```sql
CREATE USER 'benutzer'@'localhost' IDENTIFIED BY 'passwort';
```

```sql
GRANT ALL PRIVILEGES ON <DB>.* to 'benutzer'@'localhost';
```

```sql
FLUSH PRIVILEGES;
```

## Fetch / Offset

Hiermit kann man sich eine Anzahl von Zeilen ausgeben lassen, welche zwischen Offset und Limit liegen, oder aber über den zweiten Weg mit Fetch 

SELECT
  first_name,
  last_name,
FROM
  employees
ORDER BY
  first_name,
   last_name
OFFSET
  5 ROWS
FETCH NEXT
  5 ROWS ONLY;
  
Hier werden die ersten fünf Zeilen übersprungen und die nächsten fünf ausgegeben.

### Abfrage einer bestimmten Anzahl von Zeilen
Beispiel: von Zeile 10 (Offset) 10 Zeilen weiter (LIMIT)

select * from .... limit 10 offset 10

oder 

offset 228 --Skipping the first 228 rows in the result set
--Fetching the next 10 rows only after the offset
FETCH NEXT 10 ROWS ONLY;


#### Notizen bei Fehlersuche 
Hier sollen Werte aus eriner Tabelle in eine andere transferiert werden, jedoch es knallt:

INSERT INTO isys_catg_sid_stid_list(custom_fields__data__id,isys_catg_sid_stid_list__isys_obj__id,isys_catg_sid_stid_list__sid,isys_catg_sid_stid_list__mm,isys_catg_sid_stid_list__rh,isys_catg_sid_stid_list__rha,isys_catg_sid_stid_list__status,isys_catg_sid_stid_list__description)     

#Wo ist der Fehler --> suchen 
SELECT          
isys_catg_custom_fields_list__data__id,         isys_catg_custom_fields_list__isys_obj__id,CASE WHEN `sid`=-1 THEN NULL ELSE `sid` END,
CASE WHEN `mm`=-1 THEN NULL ELSE `mm` END,CASE WHEN `rh`=-1 THEN NULL ELSE `rh` END,CASE WHEN `rha`=-1 THEN NULL ELSE `rha` END,`status`,`description` 
FROM         (
SELECT              
isys_catg_custom_fields_list__data__id,             
isys_catg_custom_fields_list__isys_obj__id,                 
MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1465994230999' THEN isys_catg_custom_fields_list__field_content end) AS `sid`,                 
MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1465994236923' THEN isys_catg_custom_fields_list__field_content end) AS `mm`,                 
MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1519901667982' THEN isys_catg_custom_fields_list__field_content end) AS `rh`,                 
MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1603882415038' THEN isys_catg_custom_fields_list__field_content end) AS `rha`,             
MAX(CASE WHEN isys_catg_custom_fields_list__field_key LIKE 'C__CMDB__CAT__COMMENTARY%' THEN isys_catg_custom_fields_list__status END) AS `status`,             
MAX(CASE WHEN isys_catg_custom_fields_list__field_key LIKE 'C__CMDB__CAT__COMMENTARY%' THEN isys_catg_custom_fields_list__field_content END) AS `description`         
FROM isys_catg_custom_fields_list         
WHERE isys_catg_custom_fields_list__isysgui_catg_custom__id = 4         
GROUP BY isys_catg_custom_fields_list__data__id)
ref1  offset 247 rows fetch
next 1 rows only;




## Hier knallt es 
INSERT INTO isys_catg_sid_stid_list(custom_fields__data__id,isys_catg_sid_stid_list__isys_obj__id,isys_catg_sid_stid_list__sid,isys_catg_sid_stid_list__mm,isys_catg_sid_stid_list__rh,isys_catg_sid_stid_list__rha,isys_catg_sid_stid_list__status,isys_catg_sid_stid_list__description)
    SELECT 
        isys_catg_custom_fields_list__data__id,
        isys_catg_custom_fields_list__isys_obj__id,CASE WHEN `sid`=-1 THEN NULL ELSE `sid` END,CASE WHEN `mm`=-1 THEN NULL ELSE `mm` END,CASE WHEN `rh`=-1 THEN NULL ELSE `rh` END,CASE WHEN `rha`=-1 THEN NULL ELSE `rha` END,`status`,`description` FROM
        (SELECT 
            isys_catg_custom_fields_list__data__id,
            isys_catg_custom_fields_list__isys_obj__id,
                MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1465994230999' THEN isys_catg_custom_fields_list__field_content end) AS `sid`,
                MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1465994236923' THEN isys_catg_custom_fields_list__field_content end) AS `mm`,
                MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1519901667982' THEN isys_catg_custom_fields_list__field_content end) AS `rh`,
                MAX(CASE WHEN isys_catg_custom_fields_list__field_key = 'c_1603882415038' THEN isys_catg_custom_fields_list__field_content end) AS `rha`,
            MAX(CASE WHEN isys_catg_custom_fields_list__field_key LIKE 'C__CMDB__CAT__COMMENTARY%' THEN isys_catg_custom_fields_list__status END) AS `status`,
            MAX(CASE WHEN isys_catg_custom_fields_list__field_key LIKE 'C__CMDB__CAT__COMMENTARY%' THEN isys_catg_custom_fields_list__field_content END) AS `description`
        FROM isys_catg_custom_fields_list
        WHERE isys_catg_custom_fields_list__isysgui_catg_custom__id = 4
        GROUP BY isys_catg_custom_fields_list__data__id
        )ref1 offset 247 rows fetch
next 100 rows only;

