Seite 1 von 1
float + datenbank
Verfasst: Montag 8. Mai 2006, 13:34
von macmark
Hallo zusammen,
ne absolute Anfängerfrage aber ich find dazu nix :
Ich lese per ADO-Recordset aus einer SQL-Server Datenbank diverse Felder. Alles klappt meiner Meinung..... Nur :
sumU = rsK.Fields("Umsatz").Value
einproz = sumU / 100
liefert die Fehlermeldung :
TypeError: unsupported operand type(s) for /: 'tuple' and 'int'
Das Feld "Umsatz" ist ein Float Wert in der Datenbank..... warum wird dies als "tuple" interpretiert???
Vielen Dank für eure Hilfe!!
Gruss
Markus
Re: float + datenbank
Verfasst: Montag 8. Mai 2006, 13:43
von Leonidas
macmark hat geschrieben:Das Feld "Umsatz" ist ein Float Wert in der Datenbank..... warum wird dies als "tuple" interpretiert???
Weil ADO an der stelle eine Tupel zurückgibt, darum!
Mach mal
dann siehst du, was in der Tupel drin ist. Dann kannst du auf die Werte darin mit sumU[0] usw. zugreifen.
Edit: Achja, nicht zu vergessen das obligatorische "Willkommen"

Willkommen im Forum!
Verfasst: Montag 8. Mai 2006, 13:47
von Buell
genau, du hast alle "Umsätze" als Tupel in sumU
Verfasst: Montag 8. Mai 2006, 13:52
von macmark

..... Darauf hätte ich nun nicht getippt!!! Aber Danke!!
Übrigens auch für das "Willkommen"
Hast du evtl. ne Website wo erklärt wird warum das so ist?? Zu "Python + ADO" in Google findet sich nix.
Gruss
Markus
Verfasst: Montag 8. Mai 2006, 13:54
von macmark
Buell hat geschrieben:... alle "Umsätze" als Tupel in sumU
... würde ich ja verstehen wenn ich im SQL-String mehrere Zahlen zurückbekommen würde..... aber es geht da nur um EINE Float Zahl !
Verfasst: Montag 8. Mai 2006, 14:06
von Buell
stell dir die Datenbank vereinfacht als Tabelle vor:
Primärschlüssel | Umsatz | Spalte3 | Spalte 4| ...
diese Tabelle kann quasi unendlich viele Zeilen (Datensätze) enthalten. Mit:
erhälst du in einer Liste abgelegt alle Zeilen von Umsatz zB:
sumU = ['125.57','3415,23',...]
auch wenn du nur eine Zahl drin hast, liegt diese Zahl trotzdem in einer Liste, die in dem Fall nur ein Element enthält. Wie Leonidas schon richtig geschrieben hat, greifst du auf das 1. Element der Liste mit sumU[0] zu. Damit erhälst du dann die "Zahl" als float.
Also:
Code: Alles auswählen
sumU = rsK.Fields("Umsatz").Value
einproz = sumU[0] / 100.
Verfasst: Montag 8. Mai 2006, 14:08
von Leonidas
macmark hat geschrieben:Hast du evtl. ne Website wo erklärt wird warum das so ist?? Zu "Python + ADO" in Google findet sich nix.
Also ich habe
das und
das gefunden.
Warum da eine Tupel rauskommt kann ich dir auch nicht 100%ig sagen, das liegt einfach daran, wie die ADO-API ist.. die ist nunmal afair nicht
PEP 249, dh. DB-API 2 kompatibel, so haben die Macher von ADO einfach entschieden (und auch mit der DB-API 2 wäre das so wie es ist, eine Liste oder Tupel). Warscheinlich meinten sie, dass jede SQL-Anweisung mehrere Werte ausgeben
könnte, deswegen wäre es sinnvoller, an der Stelle einen Container (Tupel eben) auszugeben, in dem dann die eigentlichen Daten stecken.
Verfasst: Montag 8. Mai 2006, 14:25
von macmark
Cool... Danke!!
Das Beispiel auf
http://www.ecp.cc/ado_examples.shtml :
>>> y = r.Fields.Item(2).Value
>>> y
(0, 850000)
>>> z = y[1]/10000
>>> print 'this information costs $%.*f' % (2,z)
this information costs $85.00
... ist schon sehr vielsagend!!! Wenn man von VB auf Python umsteigt ist das recht gewöhnungsbedürftig....

... aber trotzdem ne coole Sprache!

Verfasst: Montag 8. Mai 2006, 14:33
von gerold
Leonidas hat geschrieben:Warscheinlich meinten sie, dass jede SQL-Anweisung mehrere Werte ausgeben könnte, deswegen wäre es sinnvoller, an der Stelle einen Container (Tupel eben) auszugeben, in dem dann die eigentlichen Daten stecken.
Hi @all!
Ich bin überfragt, aber eines weiß ich gewiss. Die Anweisung
, ob mit oder ohne "Value" sollte den Inhalt des Feldes ausgeben. Und das komplett ohne diesen vorher in ein Tupel zu setzen.
Sollte sich exakt gleich wie der oben aufgezeigte Code verhalten.
Eventuell hilft es PyWin32 und ADO auf den neuesten Stand zu bringen.
Hier ein Test mit einer Artikeltabelle in einer MS SQL-Datenbank:
Code: Alles auswählen
>>> import win32com.client
>>> conn = win32com.client.Dispatch('ADODB.Connection')
>>> DSN = "Provider=SQLOLEDB.1;Password=IrgendeinPasswort;Persist Security Info=True;User ID=SWA;Initial Catalog=dbSWALokal;Data Source=(local)"
>>> conn.Open(DSN, "sa", "EinPasswort")
>>> rs = win32com.client.Dispatch('ADODB.Recordset')
>>> rs.Open("Select top 10 * from tArtikel", conn, 1, 3)
>>> print rs.Fields("ArtikelNr")
1
>>> print rs.Fields("ArtikelNr").Value
1
>>> print rs.Fields.Item("ArtikelNr").Value
1
>>> print rs.Fields.Item("ArtikelNr")
1
>>> rs.MoveNext()
>>> print rs.Fields.Item("ArtikelNr")
2
>>> print rs.Fields("VKP_Brutto")
0.0
>>> rs.Close()
>>> conn.Close()
>>>
Wie man an
print rs.Fields("VKP_Brutto") sieht, wird eine Float-Zahl auch wirklich als Float-Zahl und nicht in einem Tupel ausgegeben.
@macmark: Das ist das normale Verhalten von ADO. Es stimmt also leider irgendetwas bei dir nicht.
lg
Gerold

Verfasst: Montag 8. Mai 2006, 14:42
von macmark
gerold hat geschrieben:
Eventuell hilft es PyWin32 und ADO auf den neuesten Stand zu bringen.
@macmark: Das ist das normale Verhalten von ADO. Es stimmt also leider irgendetwas bei dir nicht.
.... mmmmhhh!! Sollte ich beides auf einem aktuellen Stand haben. PyWin32 habe ich erst vor 2 Wochen runtergeladen : pywin32-208.win32-py2.4 und ADO ist auch auf dem aktuellen Stand! Verwende auf meiner Dev-Maschine den SQL-Server 2005 Express.
Ich probiers mal auf anderen Maschinen..... vielleicht hängt es ja damit zusammen.
Poste auf jeden Fall das Ergebnis....
Gruss
Markus
Verfasst: Montag 8. Mai 2006, 14:43
von gerold
Buell hat geschrieben:
erhälst du in einer Liste abgelegt alle Zeilen von Umsatz zB:
sumU = ['125.57','3415,23',...]
Hi Buell!
Leider muss ich dich da unterbrechen. ADO kennt einen Datensatzzeiger, der nach dem Ausführen einer SQL-Abfrage direkt auf dem ersten Datensatz liegt. Mit rs.MoveNext() wird der DS-Zeiger zum nächsten Datensatz verschoben.
Ist der DS-Zeiger auf der ersten Zeile, dann werden nur Werte der ersten Zeile zurück gegeben. Auf keinen Fall wird eine Liste aller Werte eines Feldes mit
rs.Fields("Feldname") zurück gegeben. Was der Normalfall ist, sollte mein Beispiel im letzten Beitrag von mir ziemlich gut aufzeigen.
@macmark: Ein bischen mehr Code von dir würde uns den Fehler sicher schnell finden lassen.
lg
Gerold

Verfasst: Montag 8. Mai 2006, 14:48
von gerold
macmark hat geschrieben:Verwende auf meiner Dev-Maschine den SQL-Server 2005 Express.
Hi Markus!
Alles was ich bis jetzt geschrieben habe, gilt bis zum
SQL-Server 2000. Ob sich ADO beim
SQL-Server 2005 Express anders verhält, das kann ich nicht sagen, da ich beim Umsteigen auf PostgreSQL bin und wahrscheinlich den Rest meines Lebens kein Bedarf mehr für den 2005er besteht.
Außerdem setze ich derzeit die ADO-Version 2.8 ein. Vielleicht verhält sich eine neuere Version anders.
mfg
Gerold

Verfasst: Montag 8. Mai 2006, 14:53
von macmark
ok..... hier grob der Code der derzeit klappt :
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Tkinter import *
import sys
import win32com.client
root = Tk()
lblstatus=StringVar(root)
root.l=Label(root,textvariable=lblstatus)
root.l.pack()
DSN = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog="
DSN = DSN + "TestDB;Data Source=SQLEXPRESS;Use Procedure for Prepare=1"
DSN = DSN + ";Auto Translate=True;Packet Size=4096;Workstation ID="
DSN = DSN + "DEV;Use Encryption for Data=False;"
DSN = DSN + "Tag with column collation when possible=False"
lblstatus.set("DB öffnen .... ")
root.update()
monat = 1
monat = 2006
conn = win32com.client.Dispatch(r'ADODB.Connection')
conn.Open(DSN)
sumU = 0
sqlk = " SELECT Sum(Umsatz1)+Sum(Umsatz2)+Sum(Umsatz3) AS Umsatz "
sqlk = sqlk + " FROM tbStatistik "
sqlk = sqlk + " where month(Datum) = " + str(monat)
sqlk = sqlk + " and year(Datum) = " + str(jahr)
rsK = win32com.client.Dispatch(r'ADODB.Recordset')
rsK.Open(sqlk, conn, 1, 3)
if not rsK.eof:
sumU = rsK.Fields("Umsatz").Value[1] / 10000
rsK.Close()
einproz = sumU / 100
print einproz
print sumU
conn.Close()
lblstatus.set("Fertig .... ")
root.update()
Edit (Leonidas): Code in Python-Tags gesetzt.
Verfasst: Montag 8. Mai 2006, 23:13
von gerold
Hi macmark!
Es lässt mir keine Ruhe -- Kann es wirklich sein, dass es von einer SQL-Server Version zur nächsten, so einen extremen Unterschied im Verhalten gibt?
Was kommt eigentlich als Ergebnis dieses Programmes raus? (Vielleicht musst du es noch anpassen, falls ich irgendwo noch einen Syntaxfehler drinnen habe.)
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import win32com.client
DSN = (
"Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;"
"Initial Catalog=TestDB;Data Source=SQLEXPRESS;Use Procedure for Prepare=1;"
"Auto Translate=True;Packet Size=4096;Workstation ID=DEV;"
"Use Encryption for Data=False;Tag with column collation when possible=False"
)
monat = 1
monat = 2006
conn = win32com.client.Dispatch(r'ADODB.Connection')
conn.Open(DSN)
rsK = win32com.client.Dispatch(r'ADODB.Recordset')
sqlk = \
"""SELECT
Sum(Umsatz1) as sum_umsatz1,
Sum(Umsatz2) as sum_umsatz2,
Sum(Umsatz3) as sum_umsatz3,
Sum(Umsatz1) + Sum(Umsatz2) + Sum(Umsatz3) AS sum_umsatz
FROM
tbStatistik
WHERE
(month(Datum) = %s) And
(year(Datum) = %s)
""" % (monat, jahr)
rsK.Open(sqlk, conn, 1, 3)
print "1: %s" % rsk.Fields("sum_umsatz1")
print "2: %s" % rsk.Fields("sum_umsatz2")
print "3: %s" % rsk.Fields("sum_umsatz3")
print "sum: %s" % rsk.Fields("sum_umsatz")
rsK.Close()
conn.Close()
mfg
Gerold

Verfasst: Mittwoch 10. Mai 2006, 17:16
von macmark
Hi Gerold,
das Thema hat mich nicht so ganz losgelassen und ich habe mit dem SQL-Server mal folgendes getestet :
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Tabelle im SQL-Server
#CREATE TABLE [testtab](
# [testdecimal] [decimal](18, 2) NULL,
# [testfloat] [float] NULL,
# [testmoney] [money] NULL,
# [testnum] [numeric](18, 2) NULL,
# [testreal] [real] NULL,
# [testsm] [smallmoney] NULL,
# [id] [int] NULL
#) ON [PRIMARY]
import win32com.client
DSN = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog="
DSN = DSN + "TestDB;Data Source=SQLEXPRESS"
conn = win32com.client.Dispatch(r'ADODB.Connection')
conn.Open(DSN)
sql = 'select id, testdecimal, testfloat, testmoney, testnum, testreal, testsm from testtab order by id '
rs = win32com.client.Dispatch(r'ADODB.Recordset')
rs.Open(sql, conn, 1, 3)
if not rs.eof:
print "testdecimal: %s" % rs.Fields("testdecimal")
print "testfloat: %s" % rs.Fields("testfloat")
print "testmoney: %s" % rs.Fields("testmoney")
print "testnumeric: %s" % rs.Fields("testnum")
print "testreal: %s" % rs.Fields("testreal")
print "testsmallmoney: %s" % rs.Fields("testsm")
rs.Close()
conn.Close()
Mit Testdaten versorgt kam folgendes dabei raus :
testdecimal: 12,34
testfloat: 14.56
testmoney: (0, 132000)
testnumeric: 14,4
testreal: 12.6000003815
testsmallmoney: (0, 608000)
D.h. nur bei einigen Datentypen reagiert wird das Ergebnis als Tuple zurückgegeben. Bei der mir vorliegenden Datenbank waren die Felder wirklich als Money definiert. In deiner Datenbank sind die wahrscheinlich anders definiert. Daher also der Unterschied.
Wer Lust hat kann das ja auch mal bei seiner DB simulieren ob sich Python/ADO da ähnlich verhält.
Schönen Gruss
Markus