2016-03-14 41 views
7

Tôi có 6 bảng trong cơ sở dữ liệu SQLite của tôi, mỗi bảng có 6 cột (Date, user, NormalA, specialA, contact, remarks) và 1000 hàng trở lên.python sqlalchemy giá trị cột riêng biệt

Làm cách nào để sử dụng sqlalchemy để sắp xếp thông qua cột Ngày để tìm ngày trùng lặp và xóa hàng đó?

+2

Q1: bạn cũng có một cột khóa chính riêng biệt không? Q2: Tại sao bạn có ** 6 ** bảng quan trọng cho câu hỏi này? – van

Trả lời

1

Lấy cảm hứng từ Find duplicate values in SQL table này có thể giúp bạn chọn thời gian trùng lặp:

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

Nếu bạn chỉ muốn hiển thị ngày độc đáo; distinct on là những gì bạn có thể cần

+0

Không thể thực hiện 'func.count'. Có vẻ như không có sự lựa chọn đó –

+1

@jakewong Bạn đã nhập hàm: 'từ sqlalchemy import func'? – Parfait

1

Mặc dù tôi thích toàn bộ đối tượng được định hướng bằng SQLAlchemy, đôi khi tôi thấy dễ dàng hơn khi trực tiếp sử dụng một số SQL. Và vì các bản ghi không có khóa, chúng tôi cần số hàng (_ROWID_) để xóa các bản ghi được nhắm mục tiêu và tôi không nghĩ API cung cấp nó.

Vì vậy, đầu tiên chúng tôi kết nối với cơ sở dữ liệu:

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

Sau đó, để liệt kê tất cả các hồ sơ:

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

Và để hiển thị tất cả các hồ sơ trùng lặp nơi ngày là giống hệt nhau:

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 

Bây giờ chúng tôi đã xác định tất cả các bản sao, chúng có thể cần phải được sửa nếu người khác các lĩnh vực khác nhau:

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' ;"); 

Và finnally để giữ kỷ lục chèn đầu tiên và xóa các bản ghi trùng lặp gần đây nhất:

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

Hoặc để giữ kỷ lục chèn cuối cùng và xóa các hồ sơ nhân đôi khác:

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

Giả sử đây là mô hình của bạn:

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 

Sau đây là hai cách để xóa bạn dữ liệu:

  1. Tìm bản sao, đánh dấu chúng để xóa và cam kết giao dịch
  2. Tạo một truy vấn SQL duy nhất mà sẽ thực hiện xóa trên cơ sở dữ liệu trực tiếp.

Đối với cả hai trong số họ một helper phụ truy vấn sẽ được sử dụng:

# 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') 

Option-1: Tìm bản sao, đánh dấu chúng để xóa và cam kết giao dịch

# 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() 

Tùy chọn-2: Tạo một truy vấn SQL đơn lẻ sẽ thực hiện xóa trên cơ sở dữ liệu trực tiếp

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) 
Các vấn đề liên quan