Python programele darbui su MySQL'u

O
  • 17 Vas '10

Sveiki,

Turiu tokia problemele, ne uz kalnu reiks gana daznai ir intensyviai dirbti su SQL failiukais.

Tarkime yra lentele, su 5 stulpeliais ir ~30000 eiluciu. O reiks atlikti tokius veiksmus kaip pvz:

jeigu 1 stulpelio, arba 1 ir 2 stulpelio, ar bet kokios kito ar kitu stulpeliu reiksme yra X istrinti ta eilute is DB.

Nesu programuotojas ir nesitikiu, kad uz mane kazkas kazka parasys, tiesiog norejau pasiteirauti, ar labai sudetinga butu tokia programele parasyti? Ar galbut cia metu reikia mokslu, kad tokio sudetingumo programas rasyti? Jeigu ne gal kas nors galite nukreipti teisinga linkme? Nuo ko pradeti?

Aciu

D
  • 17 Vas '10

http://www.kitebird.com/articles/pydbapi.html va čia trumpas beginneris kaip prisijungt prie mysqlo ir gauti table`us.

o dėl mysql paprastai, atlieki paiešką ir delete, čia mysql`o užklausa.

Nelabai supratau kaip čia nori daryt, bet mąstau, kad būtų taip

DELETE tavo_x_įrašas FROM lentelė
S
  • 18 Vas '10

Šiaip, jei esi pradedantysis ir nori išbandyti darbą tik su duomenų baze, tai gali naudoti OpenOffice Base, kuris yra pakankamai draugiškas naujokams ir t.t.

Su juo galima jungtis ir prie MySQL ir prie kitų duomenų bazių. Jei nori jungtis prie egzistuojančios MySQL duomenų bazės, tai reikia nurodyti „Connect to an existing databse“, kai paleidi patį OO Base. Tada iš sąrašo pasirenki MySQL, next, next, suvedi viską, ko prašo ir viskas.

S
  • 25 Vas '10

norejau pasiteirauti zinanciu apie darba su mysql ir python. mysql'e turiu db, ten viskas lyg tvarkoj, taciau sunkiai sekas i ja isvesti kintamuju reiksmes is programos. skirptukas paprastas:

try:
     database = MySQLdb.connect (host = "localhost", user = "root", passwd = "labas123", db = "btcast")
     cursor= database.cursor()
     cursor.executemany("INSERT INTO Sent VALUES (%s, %s, %s)" % (address, serviceport, sourcefile)
     print "Number of rows inserted: %d" % cursor.rowcount
     cursor.close ()
     conn.close ()

except MySQLdb.Error, e:
     print "Error %d: %s" % (e.args[0], e.args[1])

problema su cursor.executemany. manau tai tik sintakses problemos, taciau ismeginau ivarius aprasymo budus ir nesuveikia nei vienas. vykdant sita skripta problemos tokios:

File "./btspam.py", line 154, in <module>
cursor.executemany("INSERT INTO Sent VALUES (%s, %s, %s)" % (address, serviceport, sourcefile))
TypeError: executemany() takes exactly 3 arguments (2 given)

meginau aprasyti ir nurodant duombazes lauku vardus, bet erroras toks pat. kazko pythonui iki pilnos laimes dar truksta. gal kas turesit kokiu minciu. aciu uz pagalba.

C
  • 25 Vas '10

Na šiaip neteko naudoti tos funkcijos, bet pagal duotą kodą, tai trūksta vieno uždarančio skliausto funkcijos kvietime, o kitas dalykas, kad klaidos pranešimas gan aiškiai pasako kame bėda, kad ta funkcija tikisi dviejų parametrų, tu paduodi tik vieną.

Pabandyk tiesiog taip:

cursor.executemany("INSERT INTO Sent VALUES (%s, %s, %s)", (address, serviceport, sourcefile))
S
  • 25 Vas '10

O kam naudoti executemany? Kaip suprantu, šiuo atveju, labiau tinka tiesiog execute:

cursor.execute("INSERT INTO Sent VALUES (%s, %s, %s)" , (address, serviceport, sourcefile))

Tuo tarpu su executemany reikėtų rašyti taip:

cursor.executemany("INSERT INTO Sent VALUES (%s, %s, %s)" , [
  (address1, serviceport1, sourcefile1),
  (address2, serviceport2, sourcefile2),
])
S
  • 25 Vas '10

aciu uz atsakymus. jei idomu tai problema isprendziau tokiu budu:

database = MySQLdb.connect (host = "localhost", user = "root", passwd = "labas123", db = "btcast")
cursor= database.cursor()
query="""INSERT INTO Sent (Address, Port, File) VALUES (%s, %s, %s)"""
cursor.execute(query, (address, serviceport, sourcefile))
cursor.close ()
database.close ()

toks kodas veikia ir nebemeta klaidu. kodel pythonui patinka taip, o ne kaip anksciau rasiau atsakymo neturiu, bet svarbiausia sukasi

S
  • 4 Kov '10

iskilo dar viena problemele dirbant su mysql. pradzioj gal pateikiu koda o po to paaiskinsiu ko nepadaro.. itariu kad siuo atveju bus logikos klaidos kode:

for i in range(nrsp):
                addr = bluez.ba2str( pkt[1+6*i:1+6*i+6] )
                rssi = struct.unpack("b", pkt[1+13*nrsp+i])[0]

                cursor= database.cursor()
                cursor.execute ("SELECT BDADDR, RSSI FROM Devices")
                rows = cursor.fetchall ()
                index = 1
                print "Rows %s" %(len(rows))
                if len(rows) == 0:
                    now = datetime.datetime.now()
                    query="""INSERT INTO Devices (BDADDR, Seen, RSSI) VALUES (%s, %s, %s)"""
                    cursor.execute(query, (addr, now, rssi))
                    index = 0
                elif len(rows) != 0:
                    for row in rows:
                        cursor.execute ("SELECT BDADDR, RSSI FROM Devices")
                        if addr == row[0]:
                            if rssi < row[1]:
                                query="UPDATE Devices SET RSSI = %s WHERE BDADDR = %s"
                                cursor.execute(query, (rssi, addr))
                                query="UPDATE Devices SET Seen = %s WHERE BDADDR = %s"
                                now = datetime.datetime.now()
                                cursor.execute(query, (now, addr))
                                index = 0
                cursor.close ()    
                if index == 1:
                    cursor= database.cursor()
                    now = datetime.datetime.now()
                    query="""INSERT INTO Devices (BDADDR, Seen, RSSI) VALUES (%s, %s, %s)"""
                    cursor.execute(query, (addr, now, rssi))
                    cursor.close ()    
                results.append( ( addr, rssi ) )
                print "[%s] RSSI: [%d]" % (addr, rssi)

esme tokia.. yra ciklas kuris skanuoja irenginius ir kiekvieno periodo metu pateikia du kintamuosius addr ir rssi. man reikia alikti suvedima i db. is pradziu as duombazej visiem rssi kintamiesiem priskiriu reiksme 100, o cikle tikrinu: jei lentele tuscia (rows yra 0) tai ivedu pirma irasa. jei lentele ne tuscia (rows ne nulis) tada tikrinu ar lentelej jau yra toks adresas. jei yra tikrinu ar rssi mazesnis uz esama ir jei mazesnis atnaujinu. cia viskas lyg veikia, taciau man reik ivertint trecia atveji. tarkim lentele ne tuscia bet tokio irenginio joje irgi nera.. tada man reik ivest nauja irasa. tam naudoju kintamaji index.. bet sita dalis arba ne vietoj arba neveikia nes buna iveda po kelis kartus ta pati ir pan.. nes man ciklas pateikia kruva atsitiktiniu reiksmiu pvz:
[00:21:FE:C5:82:A3] RSSI: [52]
[00:21:FE:C5:82:A3] RSSI: [46]
[00:21:FE:C5:82:A3] RSSI: [59]
[00:1A:92:AC:F4:D6] RSSI: [43]
[00:1A:92:AC:F4:D6] RSSI: [36]
[00:1A:92:AC:F4:D6] RSSI: [43]
[00:21:FE:C5:82:A3] RSSI: [46]
[00:1A:92:AC:F4:D6] RSSI: [43]
man reik kad is visu ju i duombaze butu surasyti tik unikalus adresai t.y. 00:21:FE:C5:82:A3 ir 00:1A:92:AC:F4:D6 po viena karta ir maziausios tu atitinkamu adresu rssi vertes.

S
  • 4 Kov '10

Sunku suprasti, kai pateiki neveikiančią programą, bet testinių duomenų...

Būtų galima aiškintis, jei būtum pateikęs lentelės aprašą ir kažkokius tai testinius masyvus.

Kiek apžiūrėjau tavo kodą, tai susidaro įspūdis, kad pirmą kartą susidūrei su SQL?

Jei teisingai supratau, tai tau reikėtų daryti panašiai taip:

Visų pirma lentelės aprašas:

CREATE TABLE Devices (
    `BdAddr` VARCHAR(255) NOT NULL DEFAULT '',
    `Seen` TIMESTAMP NOT NULL,
    `Rssi` VARCHAR(255) NOT NULL DEFAULT '',
    UNIQUE KEY (`BdAddr`)
);

Toliau, kažkas panašaus į tai:

for i in range(nrsp):
    addr = bluez.ba2str( pkt[1+6*i:1+6*i+6] )
    rssi = struct.unpack("b", pkt[1+13*nrsp+i])[0]

    cursor= database.cursor()
    cursor.execute("""
        SELECT `Rssi`
        FROM `Devices`
        WHERE `BdAddr` = %s
    """, (addr,))
    row = cursor.fetchone()

    if not row:
        cursor.execute("""
            INSERT INTO `Devices`
                (`BdAddr`, `Seen`, `Rssi`)
            VALUES
                (%s, NOW(), %s)
        """, (addr, rssi))

    else if row[0] > rssi:
        cursor.execute("""
            UPDATE `Devices`
            SET
                `Rssi` = %s,
                `Seen` = NOW()
            WHERE
                `BdAddr` = %s
        """, (rssi, addr))

    cursor.close ()   

    results.append( ( addr, rssi ) )
    print "[%s] RSSI: [%d]" % (addr, rssi)
S
  • 9 Kov '10

dar vienas klausimas i ta pacia tema. kodel pythone gali neveikti sort by? na situacija tokia kad sudarau lentele is dvieju stulpeliu BDADDR ir RSSI. i juos surasomi tam tikri duomenys na ir sakykim lentele atrodo taip:

BDADRR RSSI
00:1A:AB:CD:AA 37
00:BC:AD:1F:CA 22

as naudoju tokia komanda, kad man surikiuotu visa lentele RSSI didejimo tvarka:

cursor.execute("SELECT BDADDR, RSSI FROM Temp ORDER BY RSSI ASC")

jokiu klaidu nemeta, taciau lentele lieka nesurikiuota, o tokia kokia buvo kai i ja baigti rasyti duomenys. ar gali blogai but kazkas su cursor, nes pries tai juo buvo atlikta daug veiksmu t.y. trinama letele, surasomi ir atnaujinami duomenys.

S
  • 10 Kov '10

net keista ir nebezinau ka daryti. per mysql query browser ivedus

SELECT * FROM Temp order by RSSI

viska surikiuoja kaip turi buti, tuo tarpu pythone eilute

cursor.execute ("SELECT * FROM Temp order by RSSI")

nerikiuoja nieko ir pati duombaze lieka nepakitusi. absurdiska situacija, gal kas minciu kaip issprest ja turit?

S
  • 10 Kov '10

Gal gali prikabinti SQL failą, su lentelės aprašu ir testiniais duomenimis? Pasibandyčiau.

S
  • 10 Kov '10

Ką tik išbandžiau:

import MySQLdb
db = MySQLdb.connect(user='root', db='mydb')
cr = db.cursor()
cr.execute('select username from users order by username limit 10') 
cr.fetchall()

Rūšiuoja normaliai.

C
  • 11 Kov '10

O aš teisingai supratau, kad nori surūšiuoti pačią DB, o ne rezultatus? Nes order by rikiuoja rezultatus, bet ne pačią DB, ko manau tau ir reikia... ir šiaip select'as nekeičia DB būsenos, tai po select'o DB ir neturi pasikeisti..

S
  • 12 Kov '10

nu o man vis tiek nerusiuoja. pateikiu gal visa funkcija, gal kas nors ne taip su kursoriais. pirma karta dirbu su mysql todel galbut nesigaudau kada kursorius sukurt, kada panaikint ir pan. esme kad prasukus sita funkcija ir ivykdzius si koda:

cursor = database.cursor()
cursor.execute ('SELECT RSSI FROM Temp order by RSSI limit 50')
cursor.fetchall()
cursor.close ()

duomenu bazes irasu RSSI didejimo/mazejimo tvarka nerikiuoja. Taigi funkcijos kodas:

def device_inquiry_with_rssi(sock):

    cursor= database.cursor()
    cursor.execute ("DELETE FROM Temp")
    cursor.close ()
    database.commit ()

    # issaugomas esamas filtras
    old_filter = sock.getsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, 14)

    # kad atlikti inquiry mobiliajame terminale
    # ji turi testis 8 * 1.28 = 10.24 sekundziu (pagal inquiry teorine trukme)
    # before the inquiry is performed, bluez should flush its cache of
    # previously discovered devices
    flt = bluez.hci_filter_new()
    bluez.hci_filter_all_events(flt)
    bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
    sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, flt )

    duration = 4
    max_responses = 255
    cmd_pkt = struct.pack("BBBBB", 0x33, 0x8b, 0x9e, duration, max_responses)
    bluez.hci_send_cmd(sock, bluez.OGF_LINK_CTL, bluez.OCF_INQUIRY, cmd_pkt)

    results = []

    done = False
    while not done:
        pkt = sock.recv(255)
        ptype, event, plen = struct.unpack("BBB", pkt[:3])
        if event == bluez.EVT_INQUIRY_RESULT_WITH_RSSI:
            pkt = pkt[3:]
            nrsp = struct.unpack("B", pkt[0])[0]
            for i in range(nrsp):
                addr = bluez.ba2str( pkt[1+6*i:1+6*i+6] )
                rssi = struct.unpack("b", pkt[1+13*nrsp+i])[0]

                cursor= database.cursor()
                cursor.execute ("SELECT BDADDR, RSSI FROM Temp")
                rows = cursor.fetchall ()
                index = 1
                if len(rows) == 0:
                    query="""INSERT INTO Temp (BDADDR, RSSI) VALUES (%s, %s)"""
                    cursor.execute(query, (addr, rssi))
                    index = 0
                elif len(rows) != 0:
                    for row in rows:
                        if addr == row[0]:
                            index = 0
                            if rssi < row[1]:
                                index = 0
                                query="UPDATE Temp SET RSSI = %s WHERE BDADDR = %s"
                                cursor.execute(query, (rssi, addr))

                if index == 1:
                    query="""INSERT INTO Temp (BDADDR, RSSI) VALUES (%s, %s)"""
                    cursor.execute(query, (addr, rssi))

                cursor.close ()
                results.append( ( addr, rssi ) )
                print "[%s] RSSI: [%d]" % (addr, rssi)

        elif event == bluez.EVT_INQUIRY_COMPLETE:
            done = True
        elif event == bluez.EVT_CMD_STATUS:
            status, ncmd, opcode = struct.unpack("BBH", pkt[3:7])
            if status != 0:
                print "uh oh..."
                printpacket(pkt[3:7])
                done = True
        else:
            print "unrecognized packet type 0x%02x" % ptype


    # atkuriamas buves filtras
    sock.setsockopt( bluez.SOL_HCI, bluez.HCI_FILTER, old_filter )
    cursor = database.cursor()
    cursor.execute ('SELECT RSSI FROM Temp order by RSSI limit 50')
    cursor.fetchall()
    cursor.close ()
    sys.exit (1)
    return results

reik paminet kad duombaze atidaroma ir uzdaroma main'e, o funkcijoje su ja tik dirbama. visa kita duombazej padaroma t.y. istrina viska is Temp, o po to suraso unikalius adresus ir maziausias RSSI vertes kiekvienam. paskutiniame etape reikia kad viska kas buvo surasyta i DB (adresas ir atitinkama RSSI verte) butu surikiuota RSSI didejimo tvarka. Na pvz jei buvo surasyta:

BDADDR------------------------------------RSSI
00:1A:92:AC:F4:D6-----------------------46
00:21:FE:C5:82:A3------------------------36

tai reik kad surikiuotu visus irasus taip:

BDADDR---------------------------------- RSSI
00:21:FE:C5:82:A3-----------------------36
00:1A:92:AC:F4:D6-----------------------46

S
  • 13 Kov '10

problema isspresta. padejo cassell pasisakymas, supratau kame buvo blogai. idomu ar galima rikiuoti pacia DB, kad keistusi jos busena?

S
  • 13 Kov '10

beje taip pat norejau paklausti kaip python kalboje nurodyti skaiciaus moduli? na tarkim turim -56, reik kad kintamojo reiksme butu be zenklo arba su + t.y. tik 56.

C
  • 13 Kov '10

Na pačios duombazės rikiavimas nelabai turi prasmės, nes tam ir yra tie select'ai sugalvoti, kad kai gauni rezultatus, gautum tokius kokių nori. O kas ten duombazėj darosi iš principo neturėtų būti įdomu.

Dėl modulio pythone, tai yra abs(number), pvz:

a = -1
print abs(a)
1
S
  • 15 Kov '10

nekuriant atskiros temos prie to pacio paklausiu apie error apdorojima pythone. esme tokia, kad pasirasiau tokias eilutes:

try:
    lightblue.obex.sendfile(device.getAddr(), c[1],"advertisement.jpg")
except lightblue._obexcommon.OBEXError, error:
    if error.args[0] == 111:
        print "Connection refused!"
    elif error.args[0] == 11:
        print "Resource temporarily unavailable!"
    else:
        raise error

na viskas turetu vykt taip: jei nevykdo try, patenka i except ir ten ziuri eroro numeri, jei jis 111 daro vienoki print, jei jis 11 daro kita print, jei netenkina salygu ismeta pati erora. sitoj vietoj nesuprantu to, kodel netenkina man niekad if salygu, o visad patenka i raise error kur isveda:

(111, 'Connection Refused')

pagal viska turetu error.args[0] pasiimti eroro numeri 111 ir tenkinti pirma if salyga. taciau tai neveikia. jei bandau error.errno tai grazina None. jei bandau error.args[1] tuomet raso tuple index out of range. Neveikia net jei tikrinu visa israiska (111, 'Connection Refused'), visuomet patenka i else ir ivykdo raise error.

S
  • 1 Geg '10

Norejau pasiklaust vieno dalyko apie mysql. tarkim turiu duomenu bazej stulpeli kuriame saugomi vardai. sakykim tokie jonas, pertras, jonas, jonas, juozas.

Man reikia isrinkti is duombazes unikalius vardus ir suskaiciuoti kiek kiekvieno vardo yra irasu duombazej. isrinkimui naudoju distinct kuris isrenka nepasikartojancius vardus. kai juos turiu man reik suskaiciuoti kiek kiekvieno vardo yra duombazej kad rezultatas butu tarkim jonas 3, petras 1, juozas 1.

Skaiciavimui naudoju select count(*) from lenteles_vardas where vardas = vardas[i]

kur vardas[i] tai unikaliu vardu listo elementai. tarkim vardas[1] yra jonas, vardas[2] petras ir pan. taciau sios funkcijos rezultatas yra visiem po 1, nors vardu jonas yra 3. Kame gali buti klaidos?