Aufgaben und Lösungen für PostgreSQL Fighter


Grüße an alle SQL-Liebhaber!

Im Internet habe ich selten Artikel gesehen, die verschiedene Arbeitspunkte und Feinheiten im Zusammenhang mit der Datenverarbeitung in SQL behandeln .
Ich mag es, wenn man viele Dinge gleichzeitig aus einem Artikel lernen kann, auch allgemein.
Aus diesem Grund habe ich beschlossen, meinen Artikel mit verschiedenen Aufgaben und Antworten mit Erläuterungen zu diesen zu schreiben.
Geeignet für diejenigen, die alle Grundfertigkeiten gut beherrschen und sich weiterentwickeln wollen.

Die Antworten sind für PostgreSQL geeignet (die meisten Aufgaben sind für andere DBMS geeignet , aber die Ergebnisse und Lösungen können unterschiedlich sein. Es ist sogar interessant, wo die Unterschiede auftreten).

Versuchen Sie, sich selbst zu antworten, bevor Sie den Spoiler öffnen.

Lass uns gehen!


Ich werde versuchen, etwas rein für PostgreSQL * mit einem Sternchen zu markieren (es gibt nicht viele solcher Momente).

1. Ein bisschen über numerische Operationen


1.1 Werden diese Anforderungen erfüllt? Welche Ergebnisse werden sie zurückgeben?

-- )     SELECT 3/2; -- ) SELECT min('- '::TEXT), avg('- '::TEXT); -- )*      FALSE,     ? SELECT 7.2 = (3.8::FLOAT + 3.4) -- ) SELECT (20/25)*25.0; 


Antworten zu 1.1
A) Antwort: 1
Es wird nur der ganze Teil gezeigt, weil Die Operation verwendet Ganzzahlen. Dies wird oft in anderen Sprachen gefunden.

B) Antwort: Die Anfrage wird nicht ausgeführt .

Durchschnitt gibt da einen Fehler aus akzeptiert nur Zahlen und Zeitintervalle *

Die Min / Max- Funktion kann jedoch für Textdaten ausgeführt werden (gemäß der alphabetischen Sortierung in der Datenbank).
Manchmal kann dies nützlich sein, wenn Sie sich zumindest eine Spalte ansehen müssen, die nicht in GROUP BY aufgeführt ist
Oder wenn Sie eine alphabetische Sortierung auf Zahlen anwenden müssen, in denen '10' <'2'

B) Antwort: FALSCH

Es mag seltsam erscheinen, aber das ist akzeptabel , weil Dies ist eine Funktion eines Computers, der einige Gleitkommazahlen darstellt. Eine Zahl kann die Form 7.1 (9) annehmen.
Ich erinnere mich, wie ich einmal lange mit einer Anfrage umgegangen bin, ohne es zu wissen.

D) Antwort: 0 . Der Haken ist, dass der Ausdruck in Klammern = 0 ist

SELECT (20 / 25.0) * 25 würde korrekter funktionieren


1.2 Ausgehend von der Tabelle " table_2 " (mit einer einzelnen Spalte " value " (INTEGER)) bestehend aus den folgenden 5 Zeilen:
Wert
5
5
Null
5
5

Welches Ergebnis gibt die Abfrage zurück:
 SELECT (avg(value)*count(*)) - sum(value) FROM table_2; 

Antwortoptionen
  • -4
  • 0
  • Null
  • 5
  • Es wird einen Fehler verursachen, weil nicht angegeben GROUP BY
  • Keine der aufgelisteten


Antwort 1.2
Antwort: 5

Auf eine bestimmte Spalte angewendete Aggregatfunktionen ignorieren NULL , jedoch zählt count (*) alle Zeilen
5 * 5 - 20


2. Allgemeine Fragen


2.1 In welchen Fällen kann eine Abfrage nicht den gesamten Inhalt einer Tabelle zurückgeben? ( parent_id INTEGER, die Tabelle ist mit einer Vielzahl von Daten gefüllt)

  SELECT * FROM any_table WHERE parent_id = parent_id; 

Wie wird sich die unten stehende Anfrage verhalten? Welche Daten werden ausgegeben? * PostgreSQL

  SELECT * FROM any_table WHERE parent_id IS NOT DISTINCT FROM parent_id; 

Antworten zu 2.1
Die erste Abfrage zeigt alle Einträge mit Ausnahme derjenigen an, bei denen parent_id NULL ist

Die zweite Abfrage zeigt alle Tabelleneinträge. IS DISTINCT FROM ähnelt logisch dem Operator ! = In dem NULL mit NULL identisch ist
IS NOT DISTINCT FROM verwandelt logischerweise Ungleichheit in Gleichheit

2.2. Was wird das Ergebnis der Anfrage sein?

 -- ) SELECT * FROM ( SELECT 1 UNION ALL SELECT 1 ) x(y) UNION ( SELECT 2 UNION ALL SELECT 2 ); 

Antwort auf 2.2
Das Ergebnis sind 2 Zeilen mit den Werten 1 und 2. UNION entfernt alle Duplikate in der resultierenden Auswahl und nicht nur zwischen den beiden verknüpften Tabellen. Mir ist aufgefallen, dass dies nicht für alle offensichtlich ist.

2.3 Schreiben Sie eine Abfrage, die das Datum von morgen anzeigt.

Antwort auf 2.3
 SELECT CAST((now()+ INTERVAL '1 DAY') AS DATE) 

Nicht jeder arbeitet oft mit Daten, aber es lohnt sich, ein Minimum zu beherrschen
* Postgres-Lösung, aber ich denke, andere DBMS sind nicht viel anders

Wenn Ihnen die Arbeit mit Daten neu ist, empfehle ich Ihnen, mit der Anfrage zu experimentieren
Zum Beispiel:
- Ersetzen Sie DAY durch (Woche, Monat, Jahr usw.)
- Ersetzen Sie +1 durch -9000
- DATUM durch ZEIT ersetzen
- CAST entfernen
- nur JETZT lassen ()
usw.

Und, inspiriert von einigen Ergebnissen, lesen Sie HANDBUCH . Alle dortigen Themen werden ausführlich beschrieben


2.4 Die Anweisungen UPDATE , DELETE , INSERT und MERGE dienen zum Bearbeiten von Daten in Tabellen. Ist die Ausführung von SELECT .. "sicher"? Kann eine Abfrage die Daten in der Tabelle beeinflussen?
Antwort auf 2.4
Die Frage mag jedoch primitiv erscheinen ...

Gleich zu Beginn des SQL-Lernens war ich der Meinung, dass diese Anweisung nur Daten anzeigen kann, aber:

Neben der Tatsache, dass SELECT die Tabelle für Änderungen sperren kann (BEGIN; SELECT ... FOR UPDATE) *
SELECT kann Funktionen aufrufen, die nahezu jede Manipulation ausführen können.

Anfänger müssen dies sofort verstehen und nicht, nachdem sie die Anforderung „kleiner Informationen“ auf dem Produktionsserver abgeschlossen haben


3. Nur PostgreSQL


3.1 Beschreiben Sie, was passiert, wenn diese Abfrage im SQL-Dialogfeld ausgeführt wird:

 SELECT * INTO wtf FROM pg_stat_activity; 

Antwort auf 3.1
In der Regel wird SELECT INTO in plpgsql- Funktionen verwendet, um einen Wert in eine Variable zu schreiben.

Außerhalb von plpgsql ähnelt der Effekt des Befehls der folgenden Abfrage:

 CREATE TABLE wtf AS SELECT * FROM pg_stat_activity; 


3.2 was diese "einfache" Anfrage zeigen wird

 SELECT wtf_ FROM pg_stat_activity AS wtf_ ; 

Antwort auf 3.2
pg_stat_activity Systemansicht (VIEW) der aktiven Prozesse in der Datenbank.

Die Besonderheit der Abfrage besteht darin, dass eine Spalte mit Zeilen (ROW) mit dem TYP pg_stat_activity (oder einer anderen Tabelle) angezeigt wird. Für diejenigen, die Funktionen schreiben, müssen Sie dies früher wissen. Weitere Informationen finden Sie im Handbuch.
Die Frage wurde hinzugefügt, weil ein Anfänger leicht versehentlich ein solches Ergebnis erzielen kann und nicht versteht, worum es geht

4. Arbeiten Sie mit Text. Reguläre Ausdrücke


Ich denke, Sie müssen in der Lage sein, nicht nur Abfragen zu erstellen, sondern die Ergebnisse auch richtig darzustellen.
Reguläre Ausdrücke sind ein eigenständiges großes Thema mit vielen hochwertigen Artikeln. Daher werde ich nur Beispiele ohne detaillierte Erklärungen zeigen.

4.1. Angenommen, es gibt eine Tabelle " table_5 " mit einer Textspalte " X " und vielen verschiedenen Zeilen. Welche Abfrage kann die letzten 10 Zeichen jeder Zeile erhalten?

Antwort auf 4.1
Mit SQL können Sie viele Lösungen für dasselbe Problem finden, zum Beispiel:
das einfachste, was mir in den Sinn kommt, ist richtig (X, 10)
Regex kann verwendet werden: Teilzeichenfolge (X, '. {0,10} $')
Sie können sogar nakostylyat "ausweichen" (in allen Sinnen) wie folgt : umgekehrt (Teilzeichenfolge (umgekehrt (X) für 10))


4.2 Es gibt eine Tabelle "table_6" mit einer Textspalte "X". Die Tabelle enthält eine Zeile (alle Texte nur in Englisch und Russisch):
 'Lorem 3 Ipsum 23 standard 7 dummy 17 text Ultimate Answer of Life ?? 777' 

A) Schreiben Sie eine Abfrage, die das 42. bis 68. Zeichen dieser Zeichenfolge zurückgibt
B) Wie extrahiere ich mit SQL nur GROSSBUCHSTABEN (Russisch oder Englisch) in einer Zeichenfolge?
C) Wie berechnet man die Summe der Zahlen ( keine Ziffern ) in einer Zeichenfolge mit SQL?

SQL-Skizze
 WITH table_6(X) AS( SELECT 'Lorem 3 Ipsum 23 standard 7 dummy 17 text Ultimate Answer of Life ?? 777'::TEXT ) SELECT X FROM table_6 

Antworten zu 4.2
  --    WITH  "SQL " -- ) SELECT SUBSTRING(LEFT(X,68) FROM 42 ) FROM table_6 -- 1  SELECT SUBSTRING(X, 42, (68-42)+1) FROM table_6 -- 2  -- 3    -- )  ,        SELECT regexp_replace(X,'[^A-Z-]', '','g') FROM table_6 --  ''      - --   'g'    1  -- )        --   regexp_matches   **     ,      SELECT sum(x[1]::INT) FROM ( SELECT regexp_matches(X,'[0-9]+','g') FROM table_6 ) AS y(x) -- *        -- **   +,     (   1 ,     ) 


4.3. Wie ersetze ich alle doppelten (dreifachen oder mehr) Leerzeichen durch ein einzelnes Leerzeichen im Text (Tabellenzelle)? (Traditionell: die Tabelle " table_7 " mit der Spalte " X ") (PS: Es reicht aus, SELECT zu schreiben, um das gewünschte Ergebnis zurückzugeben, und nicht UPDATE table_7 ... )

Antwort auf 4.3
 WITH table_7(X) AS (SELECT 'Lorem 3 Ipsum 23 standard 7 dummy 11 text'::TEXT) -- 1 .    (2   ) SELECT regexp_replace(X, '( ){2,}', ' ', 'g') FROM table_7 -- 2 .     (,  ,    ..)   ,      SELECT regexp_replace(X, '\s+', ' ', 'g') FROM table_7 --  !  ,  -    ,    "" .    .. --   ,    , ,        --    ,      ,    SELECT replace(replace(replace(X, ' ', '<>'), '><', ''), '<>', ' ') FROM table_7 


4.4 Es gibt eine Zeichenfolge " X ", in der Tippfehler zulässig sind. Anstelle der russischen Buchstaben (e, o, s, C) wurden äußerlich ähnliche Zeichen des englischen Alphabets verwendet. Ersetzen Sie diese Zeichen durch SQL.

PS Die Zeile sollte nur russische Zeichen enthalten, und Sie sollten sich keine Sorgen über eine mögliche Änderung der englischen Wörter machen.

(Wenn Sie Schwierigkeiten haben, alle Zeichen zu ersetzen, ersetzen Sie mindestens eines.)

Beispielzeile:

X = 'Coeo eoc oe'

Antwort auf 4.4
 -- , Replace(Replace(Replace(..  ,  --        (1   1 ) SELECT TRANSLATE('Coeo  eoc oe', 'Cceo', '') 

4.5 Schreiben Sie eine Abfrage, die eine Zeichenfolge konvertiert:
' Ivan Ivanov und Ivanovich' zur Art 'Ivan Ivanov

Antwort auf 4.5
 --  ,     SELECT initcap('  ') *      

Bonusquest für diejenigen, die es geschafft haben
Großartig, wenn es eine vorgefertigte Funktion gibt
Können Sie umgekehrt konvertieren? (vorzugsweise ohne Polsterung zu verlieren).
Vielleicht ist die Aufgabe nicht typisch, aber sie wird für die Entwicklung nützlich sein.

'IVANOV IVAN IVANOVICH' konvertieren zu 'IVANOV IVAN IVANOVICH'
und Fall umkehren?

Antwort auf die Bonus-Herausforderung
 SELECT string_agg(LOWER(LEFT(x,1)) || UPPER(SUBSTRING(x from 2)), '' ORDER BY rn) FROM (SELECT * FROM regexp_split_to_table('    4 TesT', '\y') WITH ORDINALITY y(x, rn) ) AS z -- *  PostgreSQL,      --    ,     --      ,      --      . -- WITH ORDINALITY      (   9.4) --      --          -- .. 

5. Ein bisschen über Transaktionen


Transaktionen sind eine sehr wichtige Sache in einem DBMS. Es ist wichtig, die wichtigsten Punkte zu verstehen.

Ich werde versuchen, ein Beispiel zu simulieren:

Angenommen, es gibt eine Tabelle „Waren“, mit der zwei Benutzer arbeiten werden.
Es hat eine ganzzahlige Rabattspalte von 10 für alle Zeilen.
Die Datenbankeinstellungen sind Standard (READ COMMITTED - Lesen festgeschriebener Daten).

Benutzer Benutzer_1 öffnet eine Transaktion und führt die folgende Anforderung aus:

 BEGIN; UPDATE goods SET discount = discount + 5; 

Eine Sekunde später ein anderer Benutzer ( User_2 )
Es führt fast dieselbe Anforderung aus, ohne eine Transaktion zu öffnen:
 UPDATE goods SET discount = discount + 10; 

Was wird Ihrer Meinung nach in den folgenden Situationen passieren:

A) Welches Ergebnis erhält Benutzer_2, wenn Benutzer_1 die Transaktion offen lässt (d. H. Die Transaktion nicht bestätigt / die Änderungen nicht rückgängig macht)?
Was User_1 auf Anfrage sehen wird:

 SELECT discount FROM goods LIMIT 1; 

B) Was passiert, wenn User_1 ROLLBACK ausführt? Welche Ergebnisse erhält User_2?

F) Was passiert, wenn User_1 COMMIT ausführt? Welche Ergebnisse erhält User_2?

Die Antworten
Soweit ich weiß, wird READ UN COMMITTED in PostgreSQL nicht unterstützt, und fehlerhafte Daten (nicht bestätigt) können nicht gelesen werden

Die Antworten lauten wie folgt:

A) Die Anforderung Benutzer_2 wartet auf COMMIT oder ROLLBACK von Benutzer_1. (Die Anfrage scheint einzufrieren)
Benutzer_1 in seiner Transaktion sieht seine Version des Datenbank-Snapshots, wobei der Rabatt bereits 15 beträgt

B) Wenn Benutzer_1 ROLLBACK ausführt, bleibt der Rabattwert gleich, und Benutzer_2 wird ausgeführt, wodurch der Rabatt um 10 erhöht wird und der Rabatt 20 beträgt

C) Wenn Benutzer_1 COMMIT ausführt, erhöht sich der Rabattwert um 5, und dann wird Benutzer_2 ausgeführt, wodurch der Rabatt um 10 erhöht wird und der Rabatt 25 beträgt

Eine andere Version dieser Aufgabe
Eine etwas andere Version von Task 13 als Benutzer kirill_petrov bei READ COMMITTED
 --      CREATE TABLE goods (discount) AS (SELECT 10::INT UNION ALL SELECT 15); -- 1. User_1   (  ): BEGIN; UPDATE goods SET discount = discount + 5; --2. User_2  : UPDATE goods SET discount = discount + 100 WHERE discount = 15 --3. User_1  COMMIT; 
Welche Daten werden in der Tabelle enthalten sein?

Fazit


Ich denke, das hat ziemlich interessante Punkte berührt.

Ich hoffe, dass die Aufgaben dazu beitragen, Anfänger zu motivieren, denn es ist langweilig, etwas ohne bestimmte Ziele zu lernen.

Ich kann mich für diejenigen freuen, die alle Fragen leicht beantworten konnten. Und diejenigen, die Schwierigkeiten hatten, haben hoffentlich einen Kick in Richtung Entwicklung bekommen. Wer nicht viel versteht, aber SQL lernen will, lade den PostgreSQL Young Fighter Kurs zu meinem letzten Artikel ein.

Ich freue mich auf Ergänzungen, Lösungen für besonders interessante Probleme (Sie können meine) und andere Kommentare!

Vielen Dank für Ihre Aufmerksamkeit! Ich wünsche Ihnen viel Erfolg beim Erlernen von SQL!

Source: https://habr.com/ru/post/de423097/


All Articles