SQL-Tipps und -Tricks
(github.com/ben-n93)- Eine Sammlung häufig genutzter SQL-Schreibgewohnheiten und Query-Patterns aus der Datenanalyse; mit dem Vorbehalt, dass sie nicht auf alle RDBMS gleichermaßen anwendbar sind
- Für bessere Lesbarkeit werden führende Kommata,
WHERE 1=1, Einrückung, CTEs, Kommentare undUSINGempfohlen, um Queries leichter lesbar und änderbar zu machen - Bei der Datenverarbeitung werden anhand von Beispielen Konstrukte wie Anti-Joins,
QUALIFY,GROUP BY ROLLUPundEXCEPTbehandelt, die in der Praxis zum Filtern von Ergebnissen, Erzeugen von Summen und Prüfen von Tabellenunterschieden genutzt werden - Bei Performance und Korrektheit können
NOT INmitNULL-Werten, implizite Typumwandlungen und Alias-Konflikte bei berechneten Feldern Query-Ergebnisse oder Geschwindigkeit beeinträchtigen - Bei komplexen Queries sind grundlegende Gewohnheiten wie das Verständnis der Ausführungsreihenfolge, das Prüfen der Dokumentation, das explizite Angeben der Spaltenherkunft und aussagekräftige Namen für gespeicherte Queries wichtig, um Debugging und Wiederverwendbarkeit zu verbessern
Gewohnheiten für besser lesbares SQL
- Dieses Repository ist eine Sammlung von SQL-Tipps und -Tricks, die über mehrere Jahre gesammelt wurden. Im Mittelpunkt stehen Dinge, die im Alltag von Datenanalysten nützlich sind, sowie Dinge, die man gern schon beim ersten Schreiben von SQL gewusst hätte
- Einige Tipps passen möglicherweise nicht zu jedem RDBMS
-
Führende Kommata und führendes
AND- Für die Trennung von Feldern in der
SELECT-Klausel wird empfohlen, statt nachgestellter Kommata führende Kommata zu verwenden - So ist klarer zu erkennen, ob es sich um eine neue Spalte oder um umgebrochenen Code handelt
- Auch bei unterschiedlich langen Zeilen lässt sich leichter erkennen, ob ein Komma fehlt
- Aus demselben Grund kann man Bedingungen in der
WHERE-Klausel ebenfalls ein führendesANDvoranstellen
- Für die Trennung von Feldern in der
-
Bedingungen mit
WHERE 1=1leichter testen- Wenn man in die
WHERE-Klausel die Dummy-Bedingung1=1einfügt, bricht die Query beim Testen nicht, auch wenn Bedingungen auskommentiert werden - Selbst wenn alle Bedingungen auskommentiert werden, bleibt
1=1übrig und die Query kann weiter ausgeführt werden
- Wenn man in die
-
Einrückung und Formatter
-
Bei komplexen Queries CTEs in Betracht ziehen
- Wenn inline views über zwei bis drei Ebenen oder mehr verschachtelt werden, entstehen leicht Queries, die nach einigen Wochen nur schwer wieder zu verstehen sind
- CTEs werden als Möglichkeit dargestellt, lange Queries besser zu strukturieren und Wiederverwendung sowie Debugging zu erleichtern
-
Kommentare sollten das „Warum“ erklären
- Nach einiger Zeit kann es schwerfallen, sich zu erinnern, warum eine bestimmte Verarbeitung vorgenommen wurde
- Kommentare sollten in der Regel eher erklären, warum Code etwas tut, statt wie er funktioniert
- Das Beispiel versieht eine Bedingung zum Ausschließen von Archiv-Inhalten mit einem Kommentar, weil ein neues CMS das Archive-Videoformat nicht verarbeiten kann
-
Joins auf gleichnamige Spalten mit
USING- Wenn zwei Tabellen über Spalten mit demselben Namen gejoint werden, lässt sich der Join mit
USINGeinfacher ausdrücken als mitON USINGentfernt die gemeinsame Spalte im Ergebnis als Duplikat und gibt sie nur einmal zurück- Wenn bei
ONdie gemeinsame Spalte nicht explizit angegeben wird, kann ein Fehlerambiguous column nameauftreten
- Wenn zwei Tabellen über Spalten mit demselben Namen gejoint werden, lässt sich der Join mit
Nützliche Konstrukte für die Datenverarbeitung
-
Mit Anti-Joins Zeilen finden, die in einer anderen Tabelle fehlen
- Ein Anti-Join wird verwendet, um Zeilen zurückzugeben, die in einer Tabelle vorhanden sind, aber in einer anderen keine Entsprechung haben
- Das Beispiel behandelt den Fall, nur die
video_idvon nicht archivierten Inhalten abzurufen - Es gibt mehrere Implementierungsvarianten
- Nach einem
LEFT JOINnur Zeilen filtern, bei denen der Schlüssel der gematchten TabelleNULList NOT INmit einer Subquery verwendenNOT EXISTSmit einer korrelierten Subquery verwendenNOT INwird nicht empfohlen, da es wegenNULL-Werten möglicherweise nicht wie beabsichtigt funktioniert
-
Ergebnisse von Window Functions mit
QUALIFYfilternQUALIFYermöglicht es, Query-Ergebnisse anhand der Ergebnisse von Window Functions zu filtern- Dadurch kann ohne inline view gefiltert und die Anzahl der Codezeilen reduziert werden
- Das Beispiel wählt mit
DENSE_RANK()die Top-10-Märkte je Produkt aus und filtert anschließend mitQUALIFY - Als Einschränkung gilt, dass
QUALIFYoffenbar nur in großen Data Warehouses wie Snowflake, Amazon Redshift und Google BigQuery verfügbar ist
-
GROUP BYundORDER BYanhand der Spaltenposition- Statt Spaltennamen kann man die Spaltenposition verwenden, etwa
GROUP BY 1oderORDER BY 2 - Für temporäre oder einmalige Queries kann das nützlich sein
- Für Produktionscode wird empfohlen, immer direkt auf Spaltennamen zu verweisen
- Statt Spaltennamen kann man die Spaltenposition verwenden, etwa
-
Summen mit
GROUP BY ROLLUPerzeugenGROUP BY ROLLUPkann genutzt werden, um Zwischensummen und Gesamtsummen zu erzeugen- Das Beispiel berechnet Gehaltssummen nach Abteilung und erzeugt zugleich eine Zeile mit der gesamten Gehaltssumme
- Die Transact-SQL-Dokumentation erklärt, dass
ROLLUPGruppen für Kombinationen von Spaltenausdrücken erzeugt und die Anzahl der Gruppen von rechts nach links reduziert, um Zwischen- und Gesamtsummen zu bilden - Mit
COALESCEkann die Summenzeile alsTotalangezeigt werden - Man muss auf die Sortierspalte achten, damit die Summenzeile am Ende des Ergebnisses erscheint
-
Unterschiede zwischen zwei Ergebnismengen mit
EXCEPTfindenEXCEPTgibt Zeilen zurück, die im Ergebnis der ersten Query enthalten sind, aber nicht im Ergebnis der zweiten- Mit
EXCEPTzusammen mitUNION ALLkann geprüft werden, ob zwei Tabellen dieselben Daten enthalten - Wenn keine Zeilen zurückgegeben werden, sind die beiden Tabellen identisch
- Wenn Zeilen zurückgegeben werden, sind diese Zeilen die Ursache der Unterschiede
Patterns, die Performance und Korrektheit beeinträchtigen
-
Bei Spalten, die
NULLenthalten können, istNOT EXISTSbesser alsNOT IN- Wenn die Vergleichsspalte
NULLzulässt, kannNOT INin der Regel langsamer sein alsNOT EXISTS - Dieses Phänomen trat in Snowflake auf; das PostgreSQL-Wiki schreibt in Don’t Do This, dass
NOT IN (SELECT ...)nicht gut optimiert wird NOT INfunktioniert nicht wie beabsichtigt, wenn die VergleichswerteNULLenthalten- Dass eine Spalte
NULLzulässt, bedeutet nicht, dass tatsächlichNULL-Werte vorhanden sind. Wenn man jedoch mit Tabellen arbeitet, die man nicht ändern kann, kannNOT EXISTShelfen, die Geschwindigkeit zu verbessern
- Wenn die Vergleichsspalte
-
Implizite Typumwandlungen können verlangsamen oder fehlschlagen
- Wenn in einer Bedingung ein Wert mit einem anderen Datentyp als die Spalte verwendet wird, kann die Datenbank eine implizite Typumwandlung versuchen
- Das Beispiel behandelt den Fall, dass die String-Spalte
video_idmit der Integer-Zahl200050verglichen wird - Sich auf implizite Typumwandlungen zu verlassen, kann Probleme verursachen
- Wenn Werte vorhanden sind, die sich nicht umwandeln lassen, kann ein Fehler auftreten
- Die zusätzliche Arbeit, jeden Wert in den angegebenen Typ umzuwandeln, kann Queries verlangsamen
- Man sollte denselben Datentyp wie die Spalte verwenden oder, um Fehler zu vermeiden, Funktionen wie Snowflakes
TRY_TO_NUMBERnutzen - Die Auswirkungen auf die Geschwindigkeit hängen von der Größe des verarbeiteten Datensatzes ab
Häufige Fehler
-
NOT INundNULLNOT INfunktioniert nicht, wenn die VergleichswerteNULLenthalten- Da
NULLfür Unknown steht, kann die SQL-Engine nicht verifizieren, dass der geprüfte Wert nicht in der Liste enthalten ist - In diesem Fall ist die Verwendung von
NOT EXISTSeine Alternative
-
Alias-Konflikte bei berechneten Feldern
- Wenn ein berechnetes Feld denselben Namen wie eine vorhandene Spalte erhält, kann unerwartetes Verhalten entstehen
- Die
GROUP BY-Dokumentation von Snowflake schreibt, dass bei einem Namen in derGROUP BY-Klausel, der sowohl zu einem Spaltennamen als auch zu einem Alias passt, der Spaltenname verwendet wird - Wenn im Beispiel mit
LEFT(product, 1) AS productein Alias erzeugt undGROUP BY productverwendet wird, wird nicht nach dem ersten Buchstaben, sondern nach der ursprünglichen Spalteproductgruppiert, sodass drei Zeilen zurückgegeben werden - Es gibt zwei Lösungen
- Einen eindeutigen Alias wie
product_letterverwenden - Den Ausdruck explizit angeben, etwa
GROUP BY LEFT(product, 1) - Auch bei Window Functions können Alias-Probleme auftreten
- Im Beispiel wird der Revenue von
RobotperCASEauf 0 gesetzt, aber dies wird erst nach der Ausführung der Window Function angewendet, wodurch das Ranking anders ausfällt als erwartet - Wo möglich, sollte man eindeutige Aliasse verwenden oder den berechneten Ausdruck direkt in das
ORDER BYder Window Function schreiben
-
Angeben, zu welcher Tabelle eine Spalte gehört
- In komplexen Queries mit mehreren Joins sollte es möglich sein, Probleme mit Werten bis zur Ursprungstabelle zurückzuverfolgen
- Wenn zwei Tabellen denselben Spaltennamen teilen und die Spaltenzugehörigkeit nicht angegeben wird, kann das RDBMS einen Fehler ausgeben
- Das Beispiel macht die Herkunft der Spalten durch Tabellenaliase wie
vc.video_idundmetadata.seasoneindeutig
Ausführungsreihenfolge, Dokumentation und gespeicherte Namen
-
SQL-Ausführungsreihenfolge verstehen
- Als einer der wichtigsten Ratschläge für SQL-Lernende wird genannt, die Ausführungsreihenfolge der Klauseln zu verstehen
- Wer die Ausführungsreihenfolge kennt, schreibt Queries möglicherweise deutlich anders
- Als Referenz wird A beginner’s guide to the true order of SQL operations genannt
-
Dokumentation vollständig lesen
- Es gibt einen Fall, in dem in Snowflake
GREATEST()verwendet wurde, um aus mehreren Datumsspalten das neueste Datum zurückzugeben GREATEST()gibtNULLzurück, wenn eines der ArgumenteNULList- Hätte man die Dokumentation weitergelesen, hätte man statt
COALESCE(GREATEST(...), ...)GREATEST_IGNORE_NULLS()verwenden können - In vielen Fällen dauert das Überfliegen der Dokumentation weniger als eine Minute und kann den Aufwand reduzieren, die Ursache für unerwartetes Verhalten zu finden
- Es gibt einen Fall, in dem in Snowflake
-
Gespeicherte Queries aussagekräftig benennen
- Um zu vermeiden, dass man Queries, die erneut ausgeführt oder referenziert werden müssen, nicht wiederfindet, sollte man sie mit aussagekräftigen Namen speichern
- Der gespeicherte Name enthält üblicherweise das Thema der Query, den Ausführungsmonat und den Namen der anfragenden Person
- Das Beispiel hat das Format
Lapsed users analysis - 2023-09-01 - Olivia Roberts
2 Kommentare
Die führenden Kommas sind in diesem Beitrag alle als nachgestellte Kommas geschrieben. Im Original stehen sie führend.
Hacker-News-Kommentare
Mein zusätzlicher Tipp wäre folgender: Lernt den DB-Server richtig kennen und prüft Ausführungspläne regelmäßig. Es können überraschende Ergebnisse herauskommen, daher sollte man anpassen und erneut prüfen.
In der Regel ist
EXISTSschneller alsIN, undNOT EXISTSverhält sich bei der Behandlung vonNULLanders alsEXCEPT. Statt nach einem Tabellen-Join Zeilen mit etwas wieDISTINCTherauszufiltern, kann es oft deutlich schneller sein, Subquery-Spalten in derSELECT-Liste zu verwenden. Das kann sogar dann gelten, wenn man mehr als 10 Werte aus derselben Tabelle holt, und auch dann, wenn der DB-Server Lateral Joins unterstützt. Die Subquery darf allerdings höchstens eine Zeile zurückgeben.Abfragen, die nicht einmalig sind, sollten keinen Full Table Scan auslösen. Der Table Scan von heute kann der Ausfall von morgen sein, daher sollte man Indizes hinzufügen. Merkt euch auch, dass die
GROUP BY-Klausel oft darüber entscheidet, ob ein Index genutzt wird.Wenn man nach einem Ausdruck filtern muss, etwa wenn geprüft werden soll, ob ein Teilstring einem bestimmten Wert entspricht, kann man eine berechnete Spalte hinzufügen und darauf einen Index legen. Manche DBs unterstützen auch direkt Ausdrucksindizes. Wenn man statt
ORUNION ALLverwendet, wird es bei komplexen Abfragen oder mehrerenOR-Bedingungen oft deutlich schneller.Wenn die DB die Filterreihenfolge nicht intelligent genug festlegt, kann es auch hilfreich sein, eine Subquery zu
JOINen, um die Reihenfolge zu erzwingen.Interessant bei Postgres war für mich, dass sich
INSERT (SELECT ...)-Vorgänge nahezu linear beschleunigen lassen, wenn man sie passend zur Zahl der CPU-Kerne manuell shardet; möglicherweise gilt das auch für andere DBs. Das funktionierte sogar mit ungefähr 10 Joins. Man schaut sich zuerst mitEXPLAINden innersten oder äußersten Join an und führt dann für jeden Zeilenbereich eine separate parallele Abfrage aus (id >= start AND id < end). Ich habe das vor 6 Jahren in einem Projekt aus merkwürdigen Gründen sehr oft gemacht. Postgres 10+ hat Parallelität hinzugefügt, aber soweit ich weiß, ist sie noch nicht so weit entwickelt.SELECT-Liste Subquery-„Spalten“ zu verwenden.Wenn ich zum Beispiel
SELECT column1, (SELECT column2, column3, ... FROM table_b WHERE table_a.id = table_b.a_id) FROM table_aausführe, bekomme ich erwartungsgemäß „subquery must return only one column“. Ist gemeint, mehrere Spalten als Record-/Composite-Typ zurückzugeben?Mir war auch nicht sofort klar, warum die
GROUP BY-Klausel oft die Indexnutzung bestimmt; für Interessierte erklärt dieser Artikel das Schritt für Schritt gut: https://www.brentozar.com/archive/2015/06/indexing-for-group...EXPLAINverwenden und lernen, es mit dem bevorzugten Tool zu interpretieren. Außerdem sollte man Abfragen überwachen.In einem früheren Startup habe ich PgHero installiert, und das war wirklich eine große Hilfe bei Performance-Optimierung und Priorisierung.
Es gibt Abfragen, bei denen ein Full Table Scan die effizienteste Zugriffsstrategie ist. Das gilt meist für analytische oder aggregierende Abfragen über die ganze Tabelle, und manchmal ist ein Table Scan sogar besser, wenn nur 50 % aller Zeilen geholt werden.
Ich sehe auch nicht, wie ein schreibgeschützter Table Scan zu einem Ausfall führen soll. Er blockiert keinen konkurrierenden Zugriff. Der Nachteil ist nur die höhere I/O-Last; wenn der Server das nicht verkraftet, ist er ohnehin gravierend unterdimensioniert.
Die 3 Beispiele im Abschnitt „Lesbarkeit“ wirken seltsam. Die ersten beiden opfern buchstäblich Lesbarkeit, um das Schreiben zu erleichtern, und das letzte ist selbst mit Einrückung kaum zu retten, so schwer lesbar und monströs ist es.
Ich denke, Entwickler schauen sich Commit-Historien fast genauso oft an wie den eigentlichen Quellcode.
Ich sehe sie inzwischen oft genug, dass sie mich kaum noch stören.
Ich sehe daran kein Problem.
Falsch wirkt daran auch nichts.
SELECT-Block die Spalten auf einzelne Zeilen auf und lässt dann trotzdem 150 Zeichen lange Zeilen stehen? Das ist eine kaputte Definition von Lesbarkeit. Von den Kommas will ich gar nicht erst anfangen.In Code Reviews schaut sich niemand lange Zeilen wirklich gründlich an. Das war das größte Problem von AngularJS. Merges wurden falsch durchgeführt und alles ging kaputt, weil einem ungefähr ab Spalte 90 die Augen zufallen. Ich war in mehr als einem halben Dutzend Teams mit Code Reviews, und es war immer dasselbe. Selbst wenn man sich dieses Problems sehr bewusst ist und versucht, es zu vermeiden, mache ich solche Fehler immer noch ungefähr halb so oft wie andere.
Schreibt es etwas aufgeteilter. Besonders dann, wenn ihr anderen Beispiele zeigt.
Tipps für den Umgang mit komplexen Stored Procedures:
WHERE-Klausel. Wenn manJOINs oder komplexe Operationen versucht, kommt es wahrscheinlich zu TimeoutsWenn man Punkt 5 ohne Punkt 6 anwendet, merkt man womöglich gar nicht, dass man etwas Nichtoptimales tut. Mein Rat ist, vorzeitige Optimierung zu vermeiden, zunächst auf die intuitivste Weise zu schreiben und nur bei Bedarf zu optimieren. Am wichtigsten ist, SQL nicht prozedural zu schreiben. Man beschreibt die gewünschten Daten, statt der Engine vorzuschreiben, wie sie sie holen soll
Andererseits versieht Microsoft das Thema ständig mit Warnungen, als ob der Query Planner es am besten wüsste und man nicht versuchen sollte, daran zu tunen
Auch die Version der DB kann Einfluss haben
Ich mag keine Entwicklung „für alle Fälle“. Das gilt für Interfaces genauso wie für Platzhalter wie
where 1=1Mach es, wenn es gebraucht wird. Tu es nicht nur, weil man es vielleicht irgendwann in der Zukunft brauchen könnte. Produktionscode ist kein Ort, um Entwicklungshilfen stehen zu lassen. Während der Entwicklung kannst du machen, was du willst, aber in Produktionscode sind Lesbarkeit und klare Intention viel wichtiger
Noch etwas zu „Anti-Joins“. Wenn man nur prüfen will, ob in einer anderen großen Tabelle oder Unterabfrage Zeilen existieren, die eine Bedingung erfüllen, sollte man EXISTS statt
INoderLEFT JOINverwendenEXISTSliefert wahr, sobald ein passender Eintrag gefunden wird. BeiLEFT JOINundINsammelt die Engine vor der Auswertung alle Ergebnisse(NOT) EXISTSeinen besseren oder denselben Ausführungsplan wie(LEFT) JOINoder(NOT) INAußerdem ist die Absicht klarer
Zum Thema „Code kommentieren“ wird zumindest bei MSSQL oft empfohlen, in Kommentaren
/**/statt--zu verwenden. Das liegt daran, dass Funktionen wie der Query Store Queries oft ohne Zeilenumbrüche speichern; wenn man die Query von dort holt, muss man dann alles manuell korrigieren, statt direkt den Formatter der IDE zu verwendenOBJECT_DEFINITIONselect name,cast((select OBJECT_DEFINITION(object_id) for xml path('')) as xml) from sys.proceduresDa Zeilenumbrüche erhalten bleiben, kann das das Aufräumen erleichtern. Allerdings werden andere XML-Zeichen zerstört, so wie
>zu>wird. Eine weitere Option wäre die Verwendung vonVARBINARYund irgendetwas, das es wieder zurückwandeltAlle regen sich über den Komma-Vorschlag auf, aber halten
1=1in derWHERE-Klausel für eine gute Idee? Wenn ich das in einem Code-Review sehe, weiß ich nicht, was ich von der Person halten sollWHERE-Anweisung wirken sich nicht auf andere Zeilen aus, wodurch Code-Reviews einfacher werdenAber wenn der Grund wie hier das spätere Hinzufügen dynamischer Bedingungen ist, würde man dort, wo ich arbeite, ganz sicher gefeuert werden
Kann jemand allgemeine Richtlinien dazu teilen, wo man die Grenze ziehen sollte zwischen Leistungssteigerungen durch DB-Konfiguration – also einem Ansatz, der fast schon einem „Kauf“ gleichkommt – und einem „Build“-Ansatz, bei dem man Dinge faktisch manuell implementiert? Nach meiner begrenzten Erfahrung landet diese Arbeit oft bei App-Entwicklern, weil fähige DBAs deutlich besser bezahlt werden und anderswo arbeiten. Wie oben gesagt: Es ist wichtig, die DB zu verstehen
Ein typisches Beispiel sind Daten, die sich im Laufe der Zeit in großen Mengen ansammeln und bei denen auf die neuesten Daten am häufigsten zugegriffen wird. Ein DBA kann den Zugriff mit Partitionierung oder partiellen Indizes schnell halten, während ein App-Entwickler Datensätze im Hintergrund in separate Archivtabellen verschieben und dabei weiterhin Dinge wie die endgültige Suche über den gesamten Datenbestand unterstützen kann. Es fühlt sich auch so an, als könnten Tools die anfängliche Arbeit, eine Tabelle zum richtigen Zeitpunkt in mehrere aufzuteilen, ziemlich stark automatisieren, etwa wenn man durch fehlende Funktionen einer Cloud-DB eingeschränkt ist
Eine weitere Verwaltungsoption ist, große Blobs/Dateien komplett in einer separaten Datenbank oder im Dateisystem zu speichern, um andere Storage-Einstellungen zu nutzen. Auch das ist etwas, das die DB übernehmen kann oder das man manuell behandelt
Im Extremfall könnte man sogar so weit gehen, Indizes selbst zu implementieren. Man hat eine riesige Tabelle mit einem einzigen autoinkrementierenden Primärschlüssel und unzähligen Spalten und erstellt dann separat eine Tabelle mit dieser ID und einigen durchsuchbaren Spalten. Das könnte bis hin zu Full-Text-Suche oder Vektoren gehen
Ein nützlicher Tipp für die manuelle Umsetzung des Materialized-View-Patterns in MSSQL 2016+ ist die kombinierte Nutzung von Partition Switching. Das wird unter https://github.com/cajuncoding/SqlBulkHelpers?tab=readme-ov-... gut beschrieben und implementiert. Es war eine kleine Bibliothek, die ich zufällig gefunden habe, kommerziell aber als besonders nützlich empfand, obwohl sie im Ranking weit unten stand und nur wenige Sterne hatte; sie konzentriert sich auf Bulk Inserts in MSSQL mit .NET. Ich halte das für ein gutes Beispiel dafür, die Grenze zwischen Buy und Build durch die Automatisierung von Partition Switching sinnvoll zu ziehen
Was fehlt: Man sollte aufhören,
SELECT *zu verwenden. Mit ziemlicher Sicherheit braucht man nicht die volle Tabellenbreite, und so erhöht man nur die Datenmenge, die gefiltert und übertragen werden muss, und verhindert außerdem das schöne Feature Semi JoinWenn man Entwickler ist, dann ja.
SELECT *hat Fallstricke, und man sollte fast immer Spalten explizit angeben oder stattdessen einen Query Builder verwenden, der das für einen übernimmtWenn man aber Analyst ist, ist das Leben kurz, und manchmal möchte man nicht jede einzelne Spalte eintippen. Dann ist
SELECT *auch okayVielleicht etwas off-topic, aber ist es akzeptabel, wenn ein Maintainer einen Pull Request einfach schließt, ohne irgendwelche Kommentare oder Diskussion?
Ich frage aus der Perspektive von jemandem, der gelegentlich zu dem Repository beigetragen hat oder beitragen wollte
Beispiel: https://github.com/ben-n93/SQL-tips-and-tricks/pulls?q=is%3A...