Verhindern Sie, dass MySql Abfragen entstellt, indem Sie einen String in int umwandeln

7

In einer meiner Tabellen befindet sich ein automatisch inkrementierendes ID-Feld. Es gibt auch ein anderes Feld (richter_code) mit einer eindeutigen Einschränkung, aber im Laufe der Jahreszeiten kann sich dieses Feld ändern - deshalb verwende ich es nicht als Primärschlüssel.

Im Code meines Programms habe ich eine Ladefunktion. Überprüfen Sie zunächst das Feld richter_code auf den Suchparameter. Wenn nichts zurückgegeben wird, durchsucht es das ID-Feld nach demselben Parameter.

Das Problem ist, dass der Wert abgeschnitten zu werden scheint, sobald er auf ein Alpha-Zeichen stößt. Ich bekomme also vollständigen Müll von meiner Abfrage. Siehe zum Beispiel Screenshot. Kann ich verhindern, dass MySQL die Abfrage ändert?

Bildschirmfoto

Shane
quelle
Ich weiß nicht über Autocasting und Abschneiden, aber versuchen Sie es mitSELECT * FROM cloths WHERE CAST(id AS VARCHAR) = "3R100C"
wässrig
Ich kann es nicht zu Varchar machen. Syntaxfehler :(
Shane
Hat die automatisch inkrementierte IdSpalte eine geschäftliche Bedeutung? Warum sollte das Programm überhaupt versuchen, es für eine Suche zu verwenden?
Mathieu Guindon
1
Sie können, ich habe nur den falschen Typ vorgeschlagen (ich habe die Dokumente nicht überprüft ). Ersetzen Sie VARCHARdurch CHARund Sie sollten bereit sein zu gehen.
wässrig

Antworten:

7

Muss MySql lieben;)

Ich suchte im Stapelüberlauf nach einer MySQL- isnumericFunktion, die einer Funktion entspricht , und fand diese .

Diese ziemlich verschlungene WHERE-Klausel würde die erwarteten 0 Zeilen zurückgeben:

where Id = case when concat('','3R100C'*1) = '3R100C' then '3R100C' else null end

Die Idee ist, den Parameter nur dann abzugleichen, Id wenn es sich um einen gültigen numerischen Wert handelt . Ich hoffe es hilft!


Ich würde eine tatsächliche isintegerFunktion erstellen, um diesen Wahnsinn zu abstrahieren:

CREATE FUNCTION `isinteger`(v varchar(255)) RETURNS bit(1)
BEGIN

    RETURN CASE WHEN CONCAT('', v * 1) = v THEN 1 ELSE 0 END;

END

Trotzdem halte ich es nicht für richtig, ein automatisch inkrementiertes IdFeld als Such-Fallback-Spalte zu verwenden - diese ID ist der Primärschlüssel Ihrer Tabelle, ihre Bedeutung gehört ausschließlich der Datenbankseite, kein Programm sollte sich jemals darum kümmern, noch weniger Benutzer eines Programms.

Mathieu Guindon
quelle
Beachten Sie, dass diese Funktion im Falle eines Ganzzahlüberlaufs 0 zurückgibt. Dies ist technisch nicht falsch;)
Mathieu Guindon
1
Ich denke, Sie könnten else nullanstelle vonelse -1
ypercubeᵀᴹ
1
Ich würde mir Sorgen machen, wenn eine benutzerdefinierte Funktion aufgerufen wird (Leistungseinbußen, die ich gegebenenfalls nicht kenne). Ein Benchmark beider Lösungen wäre interessant.
wässrig
@ypercube guter Punkt, bearbeitet;)
Mathieu Guindon
Neben dem * 1-Trick könnte dies auch funktionieren:WHEN CAST(CAST('3R100C' AS int) AS char) = '3R100C'
ypercubeᵀᴹ
5

Das Problem hierbei ist, dass MySQL beim Vergleich eine implizite Konvertierung von der Zeichenfolge in eine int durchführt.

SELECT * FROM cloths WHERE id = "3R100C"

Wenn Sie die Konvertierung explizit machen, macht MySQL Folgendes:

SELECT * FROM cloths WHERE id = CAST("3R100C" as int)

Stattdessen möchten Sie die ID in eine Zeichenfolge umwandeln und auf diese Weise vergleichen. Die Lösung ist einfach:

SELECT * FROM cloths WHERE CAST (id as varchar(10)) = "3R100C"

Dadurch entfällt die Notwendigkeit für die Behandlung / Analyse von Ganzzahlen auf der Zeichenfolgenseite.

rolfl
quelle
Dies wäre richtig, aber für die Leistung ziemlich schrecklich.
Ypercubeᵀᴹ
@ypercube - Sie haben Recht, es wird ein Index-Scan für alle Datensätze erforderlich sein. Die Alternative besteht darin, die Prüfung der Zeichenfolge als Ganzzahl durchzuführen und sie gegebenenfalls umzuwandeln und dann die Indexsuche damit durchzuführen. Abhängig vom Plan kann es durchaus sein, dass die Besetzung durchgeführt und sogar nach Werten gesucht wird, die nicht-stelligen Inhalt haben. Tatsächliche Tests in der tatsächlichen Umgebung sind wichtig.
Rolfl