Çıkarma işlemini döngüye nasıl alabiliriz

Merhabalar…
aşağıda resimdeki gibi bir sql tablom var. Ve her zaman yeni id ile satırlar eklenmektedir.

Son id nin iki sütunundaki başlangıç ve bitiş saat verilerini çekerek çıkarma işlemi yapıp, sonucunu alarak o id nin verisini güncelliyorum. Buraya kadar her şey tamam.

veritabani_cursor.execute("SELECT max(id) FROM temp_table")
listeStop = veritabani_cursor.fetchone()[0]
veritabani_cursor.execute("SELECT * FROM temp_table WHERE id = '" + str(listeStop) +"'")
liste = veritabani_cursor.fetchone()
islem = datetime.strptime(liste[4], '%H:%M:%S') - datetime.strptime(liste[2], '%H:%M:%S')
islem1 = islem.seconds
veritabani_cursor.execute("UPDATE temp_table SET time = '" + str(islem1) + "' WHERE id = '" + str(listeStop) + "'")
veritabani_baglanti.commit()

Fakat bunu son id ve öncesindeki 10 adet id yi çekerek, çıkarma işlemini sonucunda güncellmesini nasıl döngü içinde yapabilirim?

image

SELECT * FROM temp_table ORDER BY id DESC LIMIT 10?

Basit bir örnek üzerinden göstermeye çalışayım. Önce sütun isimleri id, x, y, z olan ve 100 adet satırı olan bir veritabanı oluşturuyorum.

import sqlite3

from datetime import datetime as dt, timedelta as td

dummy_data = [[i, dt.now(), dt.now() + td(hours=i), 0] for i in range(100)]

con = sqlite3.connect("test.db")
cur = con.cursor()

cur.execute("CREATE TABLE IF NOT EXISTS test (id, x, y, z)")
cur.executemany("INSERT INTO test (id, x, y, z) VALUES (?, ?, ?, ?)", dummy_data)
con.commit()

Şimdi, @aib’in paylaştığı ifadeyi kullanarak son 10 satırın z sütunundaki verileri şöyle değiştirebiliriz.

def str_to_dt(s: str) -> dt:
    return dt.strptime(s, "%Y-%m-%d %H:%M:%S.%f")


cur.executemany(
    "UPDATE test SET z = ? WHERE id = ?",
    [
        [(str_to_dt(i[1]) - str_to_dt(i[2])).total_seconds(), i[0]]
        for i in cur.execute("SELECT id, y, x FROM test ORDER BY id DESC LIMIT 10").fetchall()
    ]
)
con.commit()

UPDATE test SET z = x - y WHERE id IN (SELECT id FROM test ORDER BY id DESC LIMIT 10); ?

1 Beğeni

Destekleriniz için öncelikle teşekkür ederim. Benim için oldukça aydınlatıcı ve yol gösterici bir cevap oldu

Ben biraz kafayı yakarak şöyle bir yoldan ilerledim. Yazmış olduğum kodu paylaşıyorum. Doğruluk açısından yorumlarınız benim için oldukça önemlidir.

veritabani_cursor.execute("SELECT id, firstClock, lastClock FROM test ORDER BY id DESC LIMIT 10")
                deneme = veritabani_cursor.fetchall()
                for i in deneme:
                    mastar = datetime.strptime(i[2], '%H:%M:%S') - datetime.strptime(i[1], '%H:%M:%S')
                    mastar1 = mastar.seconds
                    print(mastar1)
                    veritabani_cursor.execute("UPDATE test SET time = '" + str(mastar1) + "' WHERE id = '" + str(i[0]) + "'")
veritabani_cursor.execute("UPDATE test SET time = '" + str(mastar1) + "' WHERE id = '" + str(i[0]) + "'")

Bu ifadede sql injection açığı var. str(mastar1) veya str(i[0]) ifadelerine sql sorguları yazılabilir.

Bu ifadeyi şöyle değiştirmenizi tavsiye ediyorum:

veritabani_cursor.execute("UPDATE test SET time = ? WHERE id = ?", (mastar1, i[0]))

Ayrıca @aib’in paylaştığı sql sorgusunu, daha önce paylaştığım sorguya tercih etmenizi tavsiye ederim. Çünkü benim paylaştığım örnekte, tarihler, veritabanına str tipinde veriler olarak ekleniyordu. Tarihleri str olarak veritabanına eklemek yerine float tipinde bir zaman damgası olarak eklemek, tarihler üzerinde işlem yapılmasını da kolaylaştırıyor.

sqlite3, DATEDIFF gibi bazı sql fonksiyonlarını içermiyor. Tarihleri timestamp olarak kaydedersek, aşağıdaki ifade ile tam da istediğinizi yapan bir sql sorgusu yazmış olursunuz:

cur.execute("UPDATE test SET z = y - x WHERE id IN (SELECT id FROM test ORDER BY id DESC LIMIT 10)")
1 Beğeni

Biraz baktim, yakin zamanda eklenen bir fonksiyonla to_timestamp(y) - to_timestamp(x) gibi bir ifade kullanmak mumkun. (unixepoch veya datetime(x, ‘unixepoch’) gibi bir sey idi.) Kolayimda olmayan bir versiyonda eklendigi icin ugrasmadim.

PostgreSQL’de duzgun tarih turleri var ve - operatoru interval donduruyor, tiplerle tasarlanan herhangi cagdas bir programlama dilindeki gibi.

2 Beğeni

Haklısın, fonksiyonun adı unixepoch.

cur.execute("UPDATE test SET z = unixepoch(y) - unixepoch(x) WHERE id IN (SELECT id FROM test ORDER BY id DESC LIMIT 10)")

https://www.sqlite.org/lang_datefunc.html

1 Beğeni

Çok teşekkürler.

Emeğinize sağlık.

Saygılarımla…