SQL erweitert und Bruno hinzugefügt
This commit is contained in:
@@ -585,6 +585,26 @@ To extract data from a database table, use the SELECT statement with the FROM cl
|
||||
|
||||
SELECT column1, column2, column3 FROM table_name
|
||||
|
||||
#####################################################
|
||||
|
||||
|
||||
## Mathematical Columns
|
||||
|
||||
|
||||
|
||||
### Verfügbare Tabellen und Spalten:
|
||||
|
||||
products: id, price, quantity
|
||||
Erstellen Sie eine Abfrage, die Folgendes berechnet:
|
||||
|
||||
1. Eine Spalte namens total_value, die den Preis mit der Menge multipliziert und eine feste Versandpauschale von 15 hinzufügt
|
||||
2. Eine Spalte namens discounted_value, die:
|
||||
- Zuerst den Preis mit der Menge multipliziert
|
||||
- Dann einen 20%-Rabatt anwendet (multipliziert mit 0.8)
|
||||
- Schließlich eine feste Versandpauschale von 10 hinzufügt
|
||||
|
||||
Versuchen Sie, Klammern angemessen zu verwenden, um sicherzustellen, dass die Berechnungen in der richtigen Reihenfolge durchgeführt werden!
|
||||
|
||||
|
||||
#####################################################
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# Bruno: Session zur i-doit aufbauen
|
||||
|
||||
In Bruno bekommst du eine "Session" über eine Kombination aus **Environment-Variablen** und dem **API-Key-Login von i-doit**. i-doit selbst nutzt keine klassischen Cookie-Sessions für die JSON-RPC-API, sondern authentifiziert jeden Request per Header – der "Session-Charakter" kommt also über gespeicherte Variablen, die alle Requests teilen.
|
||||
|
||||
## 1. Environment anlegen
|
||||
|
||||
Anlegen eines Environment `demo-idoit` mit:
|
||||
|
||||
```
|
||||
base_url: https://demo.i-doit.com/src/jsonrpc.php
|
||||
apikey: c1ia5q
|
||||
username: admin
|
||||
password: admin
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
## 2. Login-Request (holt die Session-ID)
|
||||
|
||||
i-doit unterstützt eine echte Session über `idoit.login`. Der Response liefert einen `X-RPC-Auth-Session`-Header, den du für Folge-Requests wiederverwendest.
|
||||
|
||||
**POST** `{{base_url}}`
|
||||
|
||||
Headers:
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
X-RPC-Auth-Username: {{username}}
|
||||
X-RPC-Auth-Password: {{password}}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
Body (JSON):
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.0",
|
||||
"method": "idoit.login",
|
||||
"params": { "apikey": "{{apikey}}" },
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
|
||||
Im **Script → Post Response** die Session-ID in eine Variable schreiben:
|
||||
|
||||
```javascript
|
||||
bru.setEnvVar("session_id", res.getHeader("x-rpc-auth-session"));
|
||||
```
|
||||
|
||||
## 3. Folge-Requests mit der Session
|
||||
|
||||
Alle weiteren Requests nutzen dann statt Username/Passwort nur noch:
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
X-RPC-Auth-Session: {{session_id}}
|
||||
```
|
||||
|
||||
Body z. B. für eine Objektabfrage:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.0",
|
||||
"method": "cmdb.objects.read",
|
||||
"params": { "apikey": "{{apikey}}", "filter": { "type": 5 } },
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Logout (optional)
|
||||
|
||||
```json
|
||||
{ "version": "2.0", "method": "idoit.logout", "params": { "apikey": "{{apikey}}" }, "id": 1 }
|
||||
```
|
||||
|
||||
mit Header `X-RPC-Auth-Session: {{session_id}}`.
|
||||
|
||||
---
|
||||
|
||||
**Kernpunkt:** Die Session-ID aus dem Login-Response wird per Post-Response-Script als Environment-Variable gespeichert und von allen Requests im selben Environment geteilt. Damit sparst du dir den Login-Roundtrip pro Abfrage und hast quasi eine durchgehende Session.
|
||||
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,160 @@
|
||||
# MySQL Binary Search – Fehlerhafte Zeile automatisch finden
|
||||
|
||||
## Hintergrund
|
||||
|
||||
Bei der Migration von Daten zwischen zwei Tabellen treten gelegentlich Fehler auf. Mit `LIMIT` und `OFFSET` lässt sich der fehlerhafte Bereich manuell eingrenzen – dieser Prozess kann jedoch durch einen Binary-Search-Ansatz vollständig automatisiert werden.
|
||||
|
||||
---
|
||||
|
||||
## Einfaches Skript (SELECT *)
|
||||
|
||||
Für ein simples `SELECT *` ohne komplexe Query:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Konfiguration
|
||||
DB_USER="root"
|
||||
DB_PASS="password"
|
||||
DB_NAME="datenbank"
|
||||
|
||||
SOURCE_TABLE="quelle"
|
||||
TARGET_TABLE="ziel"
|
||||
|
||||
# Gesamtanzahl Zeilen ermitteln
|
||||
TOTAL=$(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -sNe \
|
||||
"SELECT COUNT(*) FROM $SOURCE_TABLE;")
|
||||
|
||||
echo "Gesamt Zeilen: $TOTAL"
|
||||
|
||||
LOW=0
|
||||
HIGH=$TOTAL
|
||||
|
||||
while [ $((HIGH - LOW)) -gt 1 ]; do
|
||||
MID=$(( (LOW + HIGH) / 2 ))
|
||||
FETCH=$((MID - LOW))
|
||||
|
||||
echo "Teste OFFSET=$LOW LIMIT=$FETCH ..."
|
||||
|
||||
ERROR=$(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" 2>&1 <<EOF
|
||||
INSERT INTO $TARGET_TABLE
|
||||
SELECT * FROM $SOURCE_TABLE
|
||||
LIMIT $FETCH OFFSET $LOW;
|
||||
EOF
|
||||
)
|
||||
|
||||
if echo "$ERROR" | grep -qi "error"; then
|
||||
HIGH=$MID
|
||||
echo " → Fehler gefunden, eingrenzen bis Zeile $HIGH"
|
||||
else
|
||||
LOW=$MID
|
||||
echo " → OK, weiter ab Zeile $LOW"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Fehlerhafte Zeile gefunden ==="
|
||||
echo "OFFSET: $LOW"
|
||||
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e \
|
||||
"SELECT * FROM $SOURCE_TABLE LIMIT 1 OFFSET $LOW;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Erweitertes Skript (komplexe Query mit JOINs, MAX etc.)
|
||||
|
||||
Wenn die Source-Query komplex ist (JOINs, Aggregatfunktionen, GROUP BY), wird sie als Variable definiert und als Subquery genutzt.
|
||||
|
||||
> **Wichtig:** Ein `ORDER BY` ist zwingend erforderlich, damit die Zeilenreihenfolge zwischen den Aufrufen deterministisch bleibt.
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Konfiguration
|
||||
DB_USER="root"
|
||||
DB_PASS="password"
|
||||
DB_NAME="datenbank"
|
||||
|
||||
# Deine Source-Query OHNE LIMIT/OFFSET – als Subquery nutzbar
|
||||
SOURCE_QUERY="SELECT a.id, MAX(b.wert), a.name
|
||||
FROM quelle a
|
||||
JOIN andere b ON a.id = b.ref_id
|
||||
GROUP BY a.id, a.name
|
||||
ORDER BY a.id"
|
||||
|
||||
TARGET_TABLE="ziel"
|
||||
|
||||
# Gesamtanzahl Zeilen der Query ermitteln
|
||||
TOTAL=$(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -sNe \
|
||||
"SELECT COUNT(*) FROM ($SOURCE_QUERY) AS _count_query;")
|
||||
|
||||
echo "Gesamt Zeilen: $TOTAL"
|
||||
|
||||
LOW=0
|
||||
HIGH=$TOTAL
|
||||
|
||||
while [ $((HIGH - LOW)) -gt 1 ]; do
|
||||
MID=$(( (LOW + HIGH) / 2 ))
|
||||
FETCH=$((MID - LOW))
|
||||
|
||||
echo "Teste OFFSET=$LOW LIMIT=$FETCH ..."
|
||||
|
||||
ERROR=$(mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" 2>&1 <<EOF
|
||||
INSERT INTO $TARGET_TABLE
|
||||
$SOURCE_QUERY
|
||||
LIMIT $FETCH OFFSET $LOW;
|
||||
EOF
|
||||
)
|
||||
|
||||
if echo "$ERROR" | grep -qi "error"; then
|
||||
HIGH=$MID
|
||||
echo " → Fehler, eingrenzen bis Zeile $HIGH"
|
||||
else
|
||||
LOW=$MID
|
||||
echo " → OK, weiter ab Zeile $LOW"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Fehlerhafte Zeile ==="
|
||||
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e \
|
||||
"$SOURCE_QUERY LIMIT 1 OFFSET $LOW;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Gezielten Wert aus der fehlerhaften Zeile ausgeben
|
||||
|
||||
### Variante 1 – Subquery-Wrapping
|
||||
|
||||
```bash
|
||||
echo "=== Fehlerhafte Zeile ==="
|
||||
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e \
|
||||
"SELECT a.id, a.name FROM ($SOURCE_QUERY) AS _fehler LIMIT 1 OFFSET $LOW;"
|
||||
```
|
||||
|
||||
### Variante 2 – Direkte Query (empfohlen bei Aggregaten)
|
||||
|
||||
```bash
|
||||
echo "=== Fehlerhafte Zeile – Detailansicht ==="
|
||||
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e \
|
||||
"SELECT
|
||||
a.id AS 'ID',
|
||||
a.name AS 'Name',
|
||||
MAX(b.wert) AS 'Max-Wert'
|
||||
FROM quelle a
|
||||
JOIN andere b ON a.id = b.ref_id
|
||||
GROUP BY a.id, a.name
|
||||
ORDER BY a.id
|
||||
LIMIT 1 OFFSET $LOW;"
|
||||
```
|
||||
|
||||
Variante 2 ist bei `MAX()` und anderen Aggregatfunktionen übersichtlicher, da die Rohwerte direkt aus der Query kommen und nicht erst durch ein Subquery-Wrapping gehen.
|
||||
|
||||
---
|
||||
|
||||
## Hinweise
|
||||
|
||||
- **ORDER BY** ist Pflicht für deterministische Ergebnisse bei wiederholten Aufrufen.
|
||||
- Die erfolgreichen INSERT-Blöcke bleiben in der Zieltabelle erhalten – bei Bedarf kann jeder Block in eine Transaktion mit `ROLLBACK` bei Fehler gekapselt werden.
|
||||
- Der Binary Search reduziert die Anzahl der Testläufe auf `log₂(n)` – bei 1000 Zeilen also maximal 10 Schritte.
|
||||
@@ -0,0 +1,161 @@
|
||||
# PHP & CSS – Tabellen und Formulare
|
||||
|
||||
## 1. Input-Feld mit vorausgefülltem Wert
|
||||
|
||||
**Problem:** `$value=` ist kein gültiges HTML-Attribut.
|
||||
|
||||
**Lösung:**
|
||||
```html
|
||||
<input name="ls" value="<?= htmlspecialchars($row['ls']) ?>">
|
||||
```
|
||||
|
||||
Doppelte Anführungszeichen außen verwenden, damit die einfachen Anführungszeichen im PHP-Array (`$row['ls']`) nicht kollidieren.
|
||||
|
||||
Weiterer Fehler im Original: doppeltes `</td></td>` und fehlendes schließendes `</td>`.
|
||||
|
||||
**Korrekter Block:**
|
||||
```html
|
||||
<form method="post">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Ticket-Nr.</th>
|
||||
<td><?= htmlspecialchars($row['tt']) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Auftraggeber</th>
|
||||
<td><input name="ls" value="<?= htmlspecialchars($row['ls']) ?>"></td>
|
||||
<th>Bearbeiter</th>
|
||||
<td><?= htmlspecialchars($row['bearbeiter']) ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Spaltenbreite in Tabellen
|
||||
|
||||
### Option 1 – Inline Style
|
||||
```html
|
||||
<th style="width: 150px;">Auftraggeber</th>
|
||||
```
|
||||
|
||||
### Option 2 – CSS-Klasse
|
||||
```css
|
||||
table th { width: 150px; }
|
||||
table th:first-child { width: 100px; }
|
||||
```
|
||||
|
||||
### Option 3 – `<col>`-Element (zentral für jede Spalte)
|
||||
```html
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 150px;">
|
||||
<col style="width: 250px;">
|
||||
<col style="width: 150px;">
|
||||
<col style="width: 250px;">
|
||||
</colgroup>
|
||||
...
|
||||
</table>
|
||||
```
|
||||
|
||||
> **Wichtig:** `table-layout: fixed` ist erforderlich, damit die Breiten zuverlässig greifen.
|
||||
|
||||
```css
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Spaltenbreiten zentral für mehrere Tabellen
|
||||
|
||||
Jeder Tabelle eine eigene Klasse geben:
|
||||
|
||||
```html
|
||||
<table class="tabelle-ticket">
|
||||
<table class="tabelle-adressen">
|
||||
```
|
||||
|
||||
CSS in einer zentralen `.css`-Datei:
|
||||
|
||||
```css
|
||||
table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tabelle-ticket col:nth-child(1) { width: 150px; }
|
||||
.tabelle-ticket col:nth-child(2) { width: 250px; }
|
||||
.tabelle-ticket col:nth-child(3) { width: 150px; }
|
||||
.tabelle-ticket col:nth-child(4) { width: 250px; }
|
||||
|
||||
.tabelle-adressen col:nth-child(1) { width: 100px; }
|
||||
.tabelle-adressen col:nth-child(2) { width: 300px; }
|
||||
```
|
||||
|
||||
Einbinden per:
|
||||
```html
|
||||
<link rel="stylesheet" href="style.css">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Tabelle ignoriert Spaltenbreiten (Auto-Breite)
|
||||
|
||||
**Ursache:** Fehlendes `table-layout: fixed`.
|
||||
|
||||
```css
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed; /* ← das fehlte */
|
||||
}
|
||||
```
|
||||
|
||||
Außerdem: `max-width: auto` ist ungültig. Entweder weglassen oder konkreten Wert setzen:
|
||||
```css
|
||||
.content {
|
||||
max-width: 1200px; /* oder weglassen */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Input-Breite sprengt Tabellenlayout
|
||||
|
||||
**Ursache:** `input { width: 100%; }` greift auch auf Inputs in Tabellenzellen.
|
||||
|
||||
**Lösung:** Inputs in Tabellen explizit ausschließen:
|
||||
|
||||
```css
|
||||
/* Inputs nur im Formular-Bereich */
|
||||
.form-bereich input,
|
||||
.form-bereich select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Inputs in Tabellen zurücksetzen */
|
||||
td input, td select {
|
||||
width: auto;
|
||||
padding: 2px 4px;
|
||||
margin-top: 0;
|
||||
}
|
||||
```
|
||||
|
||||
Oder Formular-Bereich per Klasse kapseln:
|
||||
|
||||
```html
|
||||
<div class="form-bereich">
|
||||
<label>...</label>
|
||||
<input ...>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
... <!-- inputs hier bleiben unberührt -->
|
||||
</table>
|
||||
```
|
||||
Reference in New Issue
Block a user