SELECT Befehl gibt einen unerwarteten Resultat

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
omissoni
User
Beiträge: 4
Registriert: Mittwoch 28. Juli 2021, 16:46

System:
Linuxmint 19.3
Python 3.7.10
Mysql Ver 14.14 Distrib 5.7.34

Von folgender Tabelle 'parts' möchte ich den höchsten 'NumberOfHoles' und den entsprechenden 'Reference' Wert, also 8 und B725 erfahren.

Code: Alles auswählen

+----+-----------+----------+---------+---------+---------------+-------------+-------------+-------+
| ID | Reference | PartName | MinArea | MaxArea | NumberOfHoles | MinDiameter | MaxDiameter | Count |
+----+-----------+----------+---------+---------+---------------+-------------+-------------+-------+
|  1 | W482      | Washer   |   29021 |   29300 |             4 |       204.7 |       207.4 |     3 |
|  2 | N154      | Mount    |   26600 |   26800 |             4 |         230 |         232 |     2 |
|  3 | B785      | Bolt     |    3900 |    4100 |             3 |        90.5 |          92 |     4 |
|  4 | W895      | Washer   |   35000 |   35100 |             7 |         127 |       128.5 |     4 |
|  5 | W811      | Missis   |   31000 |   32100 |             1 |         166 |         231 |     6 |
|  6 | B725      | Bolt     |   31900 |   41100 |             8 |       390.5 |         392 |     9 |
|  7 | Q312      | Missis   |    1265 |    1367 |             3 |        23.3 |        25.9 |    12 |
|  8 | Q322      | Bolt     |    3265 |    4367 |             5 |       233.3 |       235.9 |     2 |
+----+-----------+----------+---------+---------+---------------+-------------+-------------+-------+
Warum gibt mir folgender Code aber 8 und W482 aus? r1[1] ist immer W482 :-(

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import mysql.connector

db = mysql.connector.connect(host ="localhost",
                             user='root',
                             password='nononomypasswdunreadable',
                             database='GUIcourse')
cursor=db.cursor()         
cursor.execute("SELECT MAX(NumberOfHoles), Reference from parts")
r1 = cursor.fetchone()
print(r1[0], r1[1]) 
db.close()
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weil du einfach nur eine Aggregation für eine Spalte machst. Aber ansonsten einfach die Zeilen in einer internen Reihenfolge ausgegeben werden. Statt Max solltest du einfach absteigend sortieren nach der Spalte, und dann bekommst du die gewünschte Zeile als erstes zurück.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Was soll passieren, wenn mehrere Einträge 8 Holes haben?
Warum heißt `r1` `r1`? Warum nicht result, oder gleich `(max_number_of_holes, reference)`.
omissoni
User
Beiträge: 4
Registriert: Mittwoch 28. Juli 2021, 16:46

Sirius3 hat geschrieben: Mittwoch 28. Juli 2021, 19:46 Was soll passieren, wenn mehrere Einträge 8 Holes haben?
Warum heißt `r1` `r1`? Warum nicht result, oder gleich `(max_number_of_holes, reference)`.
Macht nichts wenn mehrere Produkte 8 Löcher haben. r1 weil ich es vom Kurs so übernommen habe. Aber result is lesbarer.
omissoni
User
Beiträge: 4
Registriert: Mittwoch 28. Juli 2021, 16:46

__deets__ hat geschrieben: Mittwoch 28. Juli 2021, 19:09 Weil du einfach nur eine Aggregation für eine Spalte machst. Aber ansonsten einfach die Zeilen in einer internen Reihenfolge ausgegeben werden. Statt Max solltest du einfach absteigend sortieren nach der Spalte, und dann bekommst du die gewünschte Zeile als erstes zurück.
Danke, das hat mich weitergebracht. Der code sieht jetzt so aus aber der "Maximum"-Teil geht nicht:

Code: Alles auswählen

cursor=db.cursor()  

# Minimum 
cursor.execute("SELECT  NumberOfHoles, Reference FROM parts ORDER BY Numberofholes")
result = cursor.fetchone()
print(result[0], result[1]) 

cursor2=db.cursor()  # hier erscheint die Fehlermeldung: self.handle_unread_result(prepared)

#Maximum
cursor2.execute("SELECT  NumberOfHoles, Reference  FROM parts ORDER BY Numberofholes DESC")
result = cursor2.fetchone()
print(result[0], result[1])
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was heißt geht nicht?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du nur ein Element brauchst, dann benutze LIMIT:

Code: Alles auswählen

cursor.execute("SELECT  NumberOfHoles, Reference FROM parts ORDER BY Numberofholes LIMIT 1")
number_of_holes, reference = cursor.fetchone()
print(number_of_holes, reference)
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

omissoni hat geschrieben: Mittwoch 28. Juli 2021, 18:57 Warum gibt mir folgender Code aber 8 und W482 aus? r1[1] ist immer W482 :-(
If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. This causes MySQL to accept the preceding query. In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are nondeterministic, which is probably not what you want.
https://dev.mysql.com/doc/refman/5.7/en ... dling.html

Mit anderen Worten du solltest eigentlich einen Fehler bekommen aber weil deine MySQL Datenbank fragwürdig konfiguriert ist bekommst du Unsinn oder wie die MySQL Dokumentation so euphemistisch sagt "wahrscheinlich nicht was du willst".

Man beachte auch dass nondeterministic hier, __deets__ Aussage dass es basierend auf der internen Reihenfolge ist mag richtig sein ist aber nicht durch die Dokumentation garantiert, dementsprechend sollte man sich darauf nicht verlassen.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

@DasIch ich hatte mich schon gewundert, warum das überhaupt ging. Aber meine SQL Zeiten liegen schon etwas zurück…
omissoni
User
Beiträge: 4
Registriert: Mittwoch 28. Juli 2021, 16:46

Danke allen für die wertvollen Vorschläge. Mit den Vorschlägen habe ich das gebastelt und dann das bekommen, was ich eigentlich wollte. Aber ich habe das schlecht kommuniziert . Ich wollte ,von eine nach einem Feld geordnete Liste nur der erster und letzter Datensatz.

ich hab es so erreicht:

Code: Alles auswählen

   
        cursor=db.cursor()                
        min_hls = "SELECT  NumberOfHoles, Reference  from parts order by Numberofholes"
        cursor .execute(min_hls)
        result = cursor .fetchone()
        
        #Minimum
        print (result[0], result[1])

        result = cursor.fetchall()
        result = result[len(result) - 1]

         #maximum
        print (result[0], result[1])
Danke/Thank you
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@omissoni: `result` wird an viel zu viele verschiedene Werte mit unterschiedlichen Bedeutungen und Typen gebunden. Das ist verwirrend.

Ich würde da auch nicht erst `fetschone()` und dann `fetchall()` machen. Es macht nicht wirklich einen grossen Unterschied einfach nur `fetchall()` aufzurufen und davon dann das erste und letzte Element zu nehmen.

Wobei hier die Sonderfälle kein Ergebnis und nur ein Ergebnis nicht berücksichtigt werden vom Code!

Beim ``len(result) - 1`` ist das ``len(result)`` überflüssig.

Code: Alles auswählen

from contextlib import closing

...

        with closing(db.cursor()) as cursor:
            cursor.execute(
                "SELECT numberofholes, reference"
                " FROM parts"
                " ORDER BY numberofholes"
            )
            rows = cursor.fetchall()
            if len(rows) < 2:
                raise ValueError("less than two results for min and max")

            minimum, maximum = rows[0], rows[-1]
            print(minimum[0], minimum[1])
            print(maximum[0], maximum[1])
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten