2016-03-14 39 views
7

Ho 6 tabelle nel mio database SQLite, ciascuna tabella con 6 colonne (Date, user, NormalA, specialA, contact, remarks) e 1000+ righe.python sqlalchemy valori distinti colonna

Come posso utilizzare sqlalchemy per ordinare la colonna Data per cercare date duplicate ed eliminare quella riga?

+2

Q1: hai anche una colonna chiave primaria separata? Q2: Perché il fatto di avere ** 6 ** tabelle è importante per questa domanda? – van

risposta

1

Ispirato dal Find duplicate values in SQL table questo potrebbe aiutare a selezionare le date duplicati:

query = session.query(
    MyTable 
).\ 
    having(func.count(MyTable.date) > 1).\ 
    group_by(MyTable.date).all() 

Se solo si desidera mostrare date uniche; distinct on è quello che potrebbe essere necessario

+0

Impossibile eseguire 'func.count'. Non sembra esserci quella scelta –

+1

@jakewong Hai importato la funzione: 'da sqlalchemy import func'? – Parfait

1

Mentre mi piace l'intero approccio orientato agli oggetti con SQLAlchemy, a volte trovo più facile utilizzare direttamente alcuni SQL. E poiché i record non hanno una chiave, abbiamo bisogno del numero di riga (_ROWID_) per cancellare i record presi come bersaglio e non penso che l'API lo fornisca.

Quindi, prima abbiamo la connessione al database:

from sqlalchemy import create_engine 
db = create_engine(r'sqlite:///C:\temp\example.db') 
eng = db.engine 

Poi per elencare tutti i record:

for row in eng.execute("SELECT * FROM TableA;") : 
    print row 

e di visualizzare tutti i record duplicati in cui sono identiche le date:

for row in eng.execute(""" 
    SELECT * FROM {table} 
    WHERE {field} IN (SELECT {field} FROM {table} GROUP BY {field} HAVING COUNT(*) > 1) 
    ORDER BY {field}; 
    """.format(table="TableA", field="Date")) : 
    print row 

Ora che abbiamo identificato tutti i duplicati, probabilmente devono essere corretti se l'altro campi sono diversi:

eng.execute("UPDATE TableA SET NormalA=18, specialA=20 WHERE Date = '2016-18-12' ;"); 
eng.execute("UPDATE TableA SET NormalA=4, specialA=8 WHERE Date = '2015-18-12' ;"); 

E finnally per mantenere il primo record inserito ed eliminare i più recenti record duplicati:

print eng.execute(""" 
    DELETE FROM {table} 
    WHERE _ROWID_ NOT IN (SELECT MIN(_ROWID_) FROM {table} GROUP BY {field}); 
    """.format(table="TableA", field="Date")).rowcount 

o per mantenere l'ultimo record inserito ed eliminare gli altri record duplicati:

print eng.execute(""" 
    DELETE FROM {table} 
    WHERE _ROWID_ NOT IN (SELECT MAX(_ROWID_) FROM {table} GROUP BY {field}); 
    """.format(table="TableA", field="Date")).rowcount 
2

Supponendo che questo è il tuo modello:

class MyTable(Base): 
    __tablename__ = 'my_table' 
    id = Column(Integer, primary_key=True) 
    date = Column(DateTime) 
    user = Column(String) 
    # do not really care of columns other than `id` and `date` 
    # important here is the fact that `id` is a PK 

seguito sono due modi per eliminare i tuoi dati:

  1. trovare i duplicati, contrassegnarle per l'eliminazione e il commit della transazione
  2. Creare una singola query SQL che eseguirà l'eliminazione sul database direttamente.

Per entrambi una sotto-query helper verranno utilizzati:

# helper subquery: find first row (by primary key) for each unique date 
subq = (
    session.query(MyTable.date, func.min(MyTable.id).label("min_id")) 
    .group_by(MyTable.date) 
) .subquery('date_min_id') 

Opzione 1: Trova duplicati, contrassegnarle per l'eliminazione e il commit della transazione

# query to find all duplicates 
q_duplicates = (
    session 
    .query(MyTable) 
    .join(subq, and_(
     MyTable.date == subq.c.date, 
     MyTable.id != subq.c.min_id) 
    ) 
) 

for x in q_duplicates: 
    print("Will delete %s" % x) 
    session.delete(x) 
session.commit() 

Opzione-2: crea una singola query SQL che eseguirà la cancellazione direttamente nel database

sq = (
    session 
    .query(MyTable.id) 
    .join(subq, and_(
     MyTable.date == subq.c.date, 
     MyTable.id != subq.c.min_id) 
    ) 
).subquery("subq") 

dq = (
    session 
    .query(MyTable) 
    .filter(MyTable.id.in_(sq)) 
).delete(synchronize_session=False)