float + datenbank

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.
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

float + datenbank

Beitragvon macmark » Montag 8. Mai 2006, 13:34

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
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Re: float + datenbank

Beitragvon Leonidas » Montag 8. Mai 2006, 13:43

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

Code: Alles auswählen

print sumU
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!
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

Beitragvon Buell » Montag 8. Mai 2006, 13:47

genau, du hast alle "Umsätze" als Tupel in sumU
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Montag 8. Mai 2006, 13:52

:shock: ..... Darauf hätte ich nun nicht getippt!!! Aber Danke!!
Übrigens auch für das "Willkommen" :D

Hast du evtl. ne Website wo erklärt wird warum das so ist?? Zu "Python + ADO" in Google findet sich nix.

Gruss
Markus
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Montag 8. Mai 2006, 13:54

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 !
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

Beitragvon Buell » Montag 8. Mai 2006, 14:06

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:

Code: Alles auswählen

sumU = rsK.Fields("Umsatz").Value


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.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 8. Mai 2006, 14:08

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.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Montag 8. Mai 2006, 14:25

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! :D
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Montag 8. Mai 2006, 14:33

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

Code: Alles auswählen

rsK.Fields("Umsatz")

, ob mit oder ohne "Value" sollte den Inhalt des Feldes ausgeben. Und das komplett ohne diesen vorher in ein Tupel zu setzen.

Code: Alles auswählen

rsK.Fields.Item("Umsatz").Value

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Montag 8. Mai 2006, 14:42

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
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Montag 8. Mai 2006, 14:43

Buell hat geschrieben:

Code: Alles auswählen

sumU = rsK.Fields("Umsatz").Value

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Montag 8. Mai 2006, 14:48

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Montag 8. Mai 2006, 14:53

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.
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5554
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Telfs (Tirol)
Kontaktdaten:

Beitragvon gerold » Montag 8. Mai 2006, 23:13

macmark hat geschrieben:

Code: Alles auswählen

sumU = rsK.Fields("Umsatz").Value[1] / 10000

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
:-)
http://halvar.at | Kleiner Bascom AVR Kurs

Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
macmark
User
Beiträge: 12
Registriert: Montag 8. Mai 2006, 13:15
Wohnort: Köln

Beitragvon macmark » Mittwoch 10. Mai 2006, 17:16

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. :? :roll:

Wer Lust hat kann das ja auch mal bei seiner DB simulieren ob sich Python/ADO da ähnlich verhält.

Schönen Gruss
Markus
"Humor ist der Knopf, der verhindert, dass einem der Kragen platzt"

Wer ist online?

Mitglieder in diesem Forum: brainstir