Abfragen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Mathmos
User
Beiträge: 36
Registriert: Dienstag 10. August 2010, 21:31

hallo

ich habe eine datenbangeintrag ausgelesen.
die ausgabe sieht dann so aus.

Code: Alles auswählen

((1L, 'teelichter-effects.html', 0L),
(2L, 'chump_and_clump.html', 0L),
(3L, 'versaute_comiczeichnungen1.html', 0L),
(4L, 'versaute_comiczeichnungen2.html', 0L),
(5L, '8-bit waterslide.html', 0L),
(6L, 'schreibmaschine-vorlesung.html', 0L),
(8L, 'test.html', 0L), (10L, 'testgall.html', 0L),
(12L, 'coleader.html', 0L),
(13L, 'die-einzig-richtige-wm-hymne.html', 0L),
(14L, 'Schland_ohh_Schland.html', 0L),
(16L, 'suppe.html', 0L), (17L, 'testgall2.html', 0L),
(18L, 'maprating.html', 0L),
(19L, 'Happiest_Wedding_Cry_In_The_World.html', 0L))
wie kann ich nun nach der höchsten id suchen? (in dem fall 19L)
wenn ich dann die höchste id ermittelt habe, wie bekomme ich dann den dazugehörigen titel raus? (in dem fall Happiest_Wedding_Cry_In_The_World.html)

noch eine frage am rande, wieso wird hinter jede zahl ein L geschrieben?

vielen dank schonmal =)
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Die Funktion max mit dem Parameter key.
Zuletzt geändert von derdon am Donnerstag 12. August 2010, 19:57, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Das sollte alles beantworten:

Code: Alles auswählen

>>> import operator                                                                     
>>> spam = ((1L, 'teelichter-effects.html', 0L),
... (2L, 'chump_and_clump.html', 0L),                                                   
... (3L, 'versaute_comiczeichnungen1.html', 0L),                                        
... (4L, 'versaute_comiczeichnungen2.html', 0L),                                        
... (5L, '8-bit waterslide.html', 0L),                                                  
... (6L, 'schreibmaschine-vorlesung.html', 0L),                                         
... (8L, 'test.html', 0L), (10L, 'testgall.html', 0L),                                  
... (12L, 'coleader.html', 0L),
... (13L, 'die-einzig-richtige-wm-hymne.html', 0L),
... (14L, 'Schland_ohh_Schland.html', 0L),
... (16L, 'suppe.html', 0L), (17L, 'testgall2.html', 0L),
... (18L, 'maprating.html', 0L),
... (19L, 'Happiest_Wedding_Cry_In_The_World.html', 0L))
>>> max(spam, key=operator.itemgetter(0))
(19L, 'Happiest_Wedding_Cry_In_The_World.html', 0L)
>>> long(42)
42L
Gibt es einen Grund, warum du die Abfrage nicht direkt über die Datenbank machst?

Sebastian
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mathmos hat geschrieben:noch eine frage am rande, wieso wird hinter jede zahl ein L geschrieben?
Weil das `long`s sind.

Code: Alles auswählen

>>> long(42)
42L
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Mathmos hat geschrieben:wie kann ich nun nach der höchsten id suchen? (in dem fall 19L)
wenn ich dann die höchste id ermittelt habe, wie bekomme ich dann den dazugehörigen titel raus?
Ich würde direkt auf der Datenbank arbeiten.

Code: Alles auswählen

SELECT * FROM tabelle WHERE id = (
  SELECT MAX(id) FROM tabelle
  )
Benutzeravatar
Mathmos
User
Beiträge: 36
Registriert: Dienstag 10. August 2010, 21:31

so, also ich habe es jetzt so

Code: Alles auswählen

c.execute('SELECT * FROM webs_static WHERE staticID = (SELECT MAX(staticID) FROM webs_static')
leider bekomm ich dann nur ne fehlermeldung, die dann wie folgt aussieht.

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1403, in __call__
    return self.func(*args)
  File "C:\Python25\xX Beispeile Xx\test.py", line 94, in Upload
    c.execute('SELECT * FROM webs_static WHERE staticID = (SELECT MAX(staticID)
FROM webs_static')
  File "C:\Python25\lib\site-packages\MySQLdb\cursors.py", line 166, in execute
    self.errorhandler(self, exc, value)
  File "C:\Python25\lib\site-packages\MySQLdb\connections.py", line 35, in defau
lterrorhandler
    raise errorclass, errorvalue
ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual
 that corresponds to your MySQL server version for the right syntax to use near
'' at line 1")
@ EyDu nein gibts es nicht, aber ich wusste nicht das man das direkt abfragen. und dann noch den dazugehörien titel rausbekommt.


also so sieht die datenbank aus
Bild
BlackJack

@Mathmos: Wie die Fehlermeldung schon sagt: Da ist ein Syntaxfehler in der SQL-Anweisung. Zähl mal die öffnenden und die schliessenden Klammern.
Benutzeravatar
Mathmos
User
Beiträge: 36
Registriert: Dienstag 10. August 2010, 21:31

also ich habe es jetzt so gelöst, anders hatte er immerne fehlermeldung ausgespuckt.

Code: Alles auswählen

auslesen = "SELECT * FROM webs_static WHERE staticID = (SELECT MAX(staticID) FROM webs_static)"
c.execute(auslesen)
die ausgabe sieht momentan so aus, das ist aufjedenfall schonmal besser als vorher.

Code: Alles auswählen

((19L, 'Happiest_Wedding_Cry_In_The_World.html', 0L),)
wie muss ich nun die die zeilen oben ändern, damit einmal die ID und der name einzeln ausgegeben werden kann?
ich blick das momentan noch nicht so ganz wie das auslesen funktioniert. kennt da jemand n gutes tut vllt?
BlackJack

@Mathmos: Du hast doch in dem Beispiel bloss 'ne Klammer innerhalb der SQL-Anweisung vergessen. Ob Du die Zeichenkette vorher an einen Namen bindest, oder direkt im Aufruf von `execute()` stehen hast, macht keinen Unterschied.

In der Python-Dokumentation ist ein Tutorial, das man mal durchgearbeitet haben sollte. Danach weisst Du auch was für einen Typ Du da vor Dir hast und wie Du an die einzelnen Elemente kommst.

Was mich bei dem Ergebnis ein wenig wundert sind die äussersten Klammern. Bei der Anfrage kann ja höchstens *ein* Datensatz als Ergebnis kommen. Da solltest Du auch nur den *einen* Datensatz einzeln von dem Cursor holen.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Wobei

Code: Alles auswählen

select staticID, name, accesslevel from webs_static order by staticID desc limit 1
deutlich effizienter als die Abfrage mit dem Subselect sein sollte.Und * Selects sollte man genauso wenig machen, wie * Importe ;)
BlackJack

@frabron: ``LIMIT`` ist soweit ich weiss kein Standard-SQL, das funktioniert also nur auf Datenbanken, die diese Erweiterung unterstützen. Und wenn man mal ganz naiv lineares Suchen nach dem grössten Wert und sortieren aller Werte vergleicht, komme ich bei ``MAX`` mit einer besseren O-Laufzeit raus. Wie kommst Du auf "deutlich effizienter"!? Eine schlauer Anfrageoptimierer würde aus Deiner Anfrage vielleicht sogar genau das Äquivalent vom Vorschlag von /me machen.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Mal ein Beispiel aus meiner Postgresql Datenbank (OpenStreetMap Linientabelle mit 11976474 Datensätzen)

Code: Alles auswählen

explain analyse select osm_id from planet_osm_line where osm_id=(select max(osm_id) from planet_osm_line)
ergibt einen Query Plan von

Code: Alles auswählen

"Index Scan using planet_osm_line_pkey on planet_osm_line  (cost=2.47..17.57 rows=2 width=4) (actual time=0.044..0.046 rows=1 loops=1)"
"  Index Cond: (osm_id = $1)"
"  InitPlan"
"    ->  Result  (cost=2.46..2.47 rows=1 width=0) (actual time=0.028..0.030 rows=1 loops=1)"
"          InitPlan"
"            ->  Limit  (cost=0.00..2.46 rows=1 width=4) (actual time=0.019..0.020 rows=1 loops=1)"
"                  ->  Index Scan Backward using planet_osm_line_pkey on planet_osm_line  (cost=0.00..29544353.76 rows=12012160 width=4) (actual time=0.016..0.016 rows=1 loops=1)"
"                        Filter: (osm_id IS NOT NULL)"
"Total runtime: 0.086 ms"
Mein Beispiel:

Code: Alles auswählen

explain analyse select osm_id from planet_osm_line order by osm_id desc limit 1
ergibt einen Query Plan

Code: Alles auswählen

"Limit  (cost=0.00..2.46 rows=1 width=4) (actual time=0.021..0.023 rows=1 loops=1)"
"  ->  Index Scan Backward using planet_osm_line_pkey on planet_osm_line  (cost=0.00..29544353.76 rows=12012160 width=4) (actual time=0.017..0.017 rows=1 loops=1)"
"Total runtime: 0.049 ms"
Auch wenn die Laufzeit an sich evt. vernachlässigbar ist, sieht man doch ganz gut, dass ein wesentlich effizienterer Queryplaner genutzt wird, der mit deutlich weniger Schritten zum Ziel kommt. Was auch logisch ist, denn im ersten Beispiel mit dem Subselect muss ja erst einmal die Tabelle durchlaufen werden, um Max() zu ermitteln, bevor der eigentliche Query ausgeführt werden kann.


Wg. LIMIT: ist kein Standard, aber zumindest Mysql und Postgresql haben eine Limit Version ... und da der Screenshot nach phpMysql aussah, hab ich's halt eingebaut, auch wenn meine Syntax die von Postgresql ist. Mysql benutz ich nicht ;)
BlackJack

@frabron: Es läuft in beiden Fällen auf einen Zugriff auf den sortierten Index hinaus. In der ersten Abfrage ist nur *ein* Schritt mehr, nämlich wieder über den Index auf den Datensatz zuzugreifen. Zwei schnelle Indexzugriffe vs. ein schneller Indexzugriff ist IMHO kein allzu deutlicher Unterschied.

Interessant wäre der Unterschied, wenn es keinen bereits sortierten Index gäbe.

Edit: Und warum PostgreSQL das im ersten Fall nicht weiter optimiert -- der Schritt eine ID nachzuschlagen die man schon gefunden hat, sollte man an der Stelle erkennen können. Und wie sieht das aus, wenn man nicht nur die ID haben möchte, sondern auch noch Daten aus dem Datensatz, die man nicht über den Index schon in die Finger bekommt. Dann muss im zweiten Fall ja auch noch auf die Tabelle zugegriffen werden. Wie gross ist der Unterschied dann noch?
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Das interessiert mich jetzt auch mal. Gut dass ich meine temporären Tabellen noch nicht gelöscht habe :D

Tabelle mit 270789 Einträgen

Code: Alles auswählen

CREATE TABLE boundary_line
(
  gid integer,
  osm_id integer,
  "name" text,
  admin_level text,
  boundary text,
  way geometry
)
SQL

Code: Alles auswählen

explain analyse select osm_id from boundary_line order by osm_id desc limit 1
Plan

Code: Alles auswählen

"Limit  (cost=24451.83..24451.84 rows=1 width=4) (actual time=946.569..946.571 rows=1 loops=1)"
"  ->  Sort  (cost=24451.83..25128.81 rows=270789 width=4) (actual time=946.565..946.565 rows=1 loops=1)"
"        Sort Key: osm_id"
"        Sort Method:  top-N heapsort  Memory: 25kB"
"        ->  Seq Scan on boundary_line  (cost=0.00..23097.89 rows=270789 width=4) (actual time=0.010..484.949 rows=271478 loops=1)"
"Total runtime: 946.611 ms"
SQL

Code: Alles auswählen

explain analyse select osm_id from boundary_line where osm_id=(select max(osm_id) from boundary_line)
Plan

Code: Alles auswählen

"Seq Scan on boundary_line  (cost=23774.87..47549.74 rows=2 width=4) (actual time=947.986..967.312 rows=1 loops=1)"
"  Filter: (osm_id = $0)"
"  InitPlan"
"    ->  Aggregate  (cost=23774.86..23774.87 rows=1 width=4) (actual time=910.259..910.261 rows=1 loops=1)"
"          ->  Seq Scan on boundary_line  (cost=0.00..23097.89 rows=270789 width=4) (actual time=0.002..463.268 rows=271478 loops=1)"
"Total runtime: 967.356 ms"
Macht imho dann keinen Unterschied mehr, sind beide gleich ineffizient :)

Gruß

Frank


Edit zu deinem Edit:
k.A, wieso das nicht anders optimiert wird. Dazu kenne ich mich nicht genug mit den Interna der Datenbank aus. Ich schau aber mal, was mit weiteren Spalten im Query passiert ...

Nochmal ein Edit:
Wie man an den costs sehen, kann ist der initiale seq-scan am teuersten, bei beiden queries. Was bei dem mit Max() halt mehr kostet, sind die zusätzlichen "Abfragen" oder wie man das nennen soll, die durchgeführt werden. Die kosten ja nicht mehr die Welt (2.x), tragen aber zur längeren Laufzeit bei. Wenn postgresql noch einmal seq-scan durchführen würde, um, wie du vermustest, die gefundene ID noch einmal zu holen, würde der Query deutlich länger dauern. Was dem Query das Genick meiner Meinung nach bricht, ist das doppelte Abfragen der Tabelle mit zwei Selects statt einem.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

So, jetzt mal wieder planet_osm_line, mit zwei weiteren Spalten (Typ Text), wobei auf einer ein Index liegt ("name") und auf der anderen nicht (barrier)

SQL

Code: Alles auswählen

explain analyse select osm_id, barrier, "name" from planet_osm_line order by osm_id desc limit 1
Plan

Code: Alles auswählen

"Limit  (cost=0.00..2.46 rows=1 width=25) (actual time=0.017..0.019 rows=1 loops=1)"
"  ->  Index Scan Backward using planet_osm_line_pkey on planet_osm_line  (cost=0.00..29544353.76 rows=12012160 width=25) (actual time=0.014..0.014 rows=1 loops=1)"
"Total runtime: 0.042 ms"
SQL

Code: Alles auswählen

explain analyse select osm_id, barrier, "name" from planet_osm_line where osm_id=(select max(osm_id) from planet_osm_line)
Plan

Code: Alles auswählen

"Index Scan using planet_osm_line_pkey on planet_osm_line  (cost=2.47..17.57 rows=2 width=25) (actual time=0.035..0.037 rows=1 loops=1)"
"  Index Cond: (osm_id = $1)"
"  InitPlan"
"    ->  Result  (cost=2.46..2.47 rows=1 width=0) (actual time=0.023..0.025 rows=1 loops=1)"
"          InitPlan"
"            ->  Limit  (cost=0.00..2.46 rows=1 width=4) (actual time=0.015..0.017 rows=1 loops=1)"
"                  ->  Index Scan Backward using planet_osm_line_pkey on planet_osm_line  (cost=0.00..29544353.76 rows=12012160 width=4) (actual time=0.011..0.011 rows=1 loops=1)"
"                        Filter: (osm_id IS NOT NULL)"
"Total runtime: 0.069 ms"
Ändert jetzt nichts gross an der bekannten Lage. Und der Threadstarter weiss jetzt mehr über OpenStreetMap Datenbanktabellen und Abfragetheorie, als er jemals wissen wollte :lol:

Frank
Benutzeravatar
Mathmos
User
Beiträge: 36
Registriert: Dienstag 10. August 2010, 21:31

so, erstmal danke für mehr informationen die ich eigentlich ganricht haben wollt^^

aber ich hatte rausgefunden, das wenn man das mit * macht, die ganze zeile ausgeben wird...
ich werde aber bei dem beispiel bleiben was ich jetzt benutze, das versteh ich nun dank galileo =)

Code: Alles auswählen

c = verbindung.cursor()
name_auslesen = "SELECT name FROM webs_static WHERE staticID = (SELECT MAX(staticID) FROM webs_static)"
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Mathmos hat geschrieben: ich werde aber bei dem beispiel bleiben was ich jetzt benutze, das versteh ich nun dank galileo =)
Wenn Du das OpenBook meinst, dann nimm lieber ein anders. Dazu gibts hier im Forum einiges an Infos, wieso das ganze Ding ziemlich schlecht ist.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten