3

只有当三列(名称、价格和新价格)与相同的数据匹配时,我才想删除重复的数据。但是在另一个python脚本中。

因此数据可以插入到数据库中,但是使用其他 python 脚本,我想通过 cron 作业删除这些重复数据。

所以在这种情况下:

cur.execute("INSERT INTO cars VALUES(8,'Hummer',41400, 49747)")

cur.execute("INSERT INTO cars VALUES(9,'Volkswagen',21600, 36456)")

是重复的。插入数据的示例脚本:

import psycopg2
import sys

con = None

try:
    con = psycopg2.connect(database='testdb', user='janbodnar')    
    cur = con.cursor()

    cur.execute("CREATE TABLE cars(id INT PRIMARY KEY, name VARCHAR(20), price INT, new price INT)")
    cur.execute("INSERT INTO cars VALUES(1,'Audi',52642, 98484)")
    cur.execute("INSERT INTO cars VALUES(2,'Mercedes',57127, 874897)")
    cur.execute("INSERT INTO cars VALUES(3,'Skoda',9000, 439788)")
    cur.execute("INSERT INTO cars VALUES(4,'Volvo',29000, 743878)")
    cur.execute("INSERT INTO cars VALUES(5,'Bentley',350000, 434684)")
    cur.execute("INSERT INTO cars VALUES(6,'Citroen',21000, 43874)")
    cur.execute("INSERT INTO cars VALUES(7,'Hummer',41400, 49747)")
    cur.execute("INSERT INTO cars VALUES(8,'Hummer',41400, 49747)")
    cur.execute("INSERT INTO cars VALUES(9,'Volkswagen',21600, 36456)")
    cur.execute("INSERT INTO cars VALUES(10,'Volkswagen',21600, 36456)")

    con.commit()

except psycopg2.DatabaseError, e:
    if con:
        con.rollback()

    print 'Error %s' % e    
    sys.exit(1

finally:    
    if con:
        con.close()
4

2 回答 2

3

您可以在一个语句中执行此操作,而无需额外往返服务器。

DELETE FROM cars
USING (
    SELECT id, row_number() OVER (PARTITION BY name, price, new_price
                                  ORDER BY id) AS rn
    FROM   cars
    ) x
WHERE cars.id = x.id
AND   x.rn > 1;

窗口函数row_number()需要 PostgreSQL 8.4 或更高版本。
在一组骗子中,最小的 id 幸存下来。
请注意,我更改"new price"new_price.

或者使用EXISTS半连接,@wildplasser 作为评论发布了同样的效果。


或者,根据 CTE 奉献者 @wildplasser 的特殊要求,使用 CTE 而不是子查询 ... :)

WITH x AS (
    SELECT id, row_number() OVER (PARTITION BY name, price, new_price
                                  ORDER BY id) AS rn
    FROM   cars
    )
DELETE FROM cars
USING  x
WHERE  cars.id = x.id
AND    x.rn > 1;

数据修改 CTE需要 Postgres 9.1 或更高版本。
这种形式的执行与带有子查询的形式大致相同。

于 2012-09-02T14:26:02.677 回答
2

使用GROUP BYSQL 语句以及初始主键来识别行:

duplicate_query = '''\
SELECT MIN(id), "name", price, "new price"
FROM cars
GROUP BY "name", price, "new price"
HAVING COUNT(ID) > 1
'''

id上面的查询为有多个主键的每组 (name, price, "new price") 行选择最低的主键id。对于您的示例数据,这将返回:

7, 'Hummer', 41400, 49747
9, 'Volkswagen', 21600, 36456

然后,您可以使用返回的数据删除重复项:

delete_dupes = '''
DELETE
FROM cars
WHERE 
    "name"=%(name)s AND price=%(price)s AND "new price"=%(newprice)s AND
    id > %(id)s
'''

cur.execute(duplicate_query)
dupes = cur.fetchall()
cur.executemany(delete_dupes, [
    dict(name=r[1], price=r[2], newprice=r[3], id=r[0])
    for r in dupes])

请注意,我们删除了主键id大于id具有相同 3 列的第一行的任何行。对于第一个欺骗,只有id8 的行将匹配,对于第二个欺骗,具有id10 个匹配的行。

这确实对找到的每个欺骗进行了单独的删除。WHERE EXISTS您可以将其与子选择查询组合成一个语句:

delete_dupes = '''\
DELETE FROM cars cdel
WHERE EXISTS (
    SELECT *
    FROM cars cex
    WHERE 
        cex."name" = cdel."name" AND 
        cex.price = cdel.price AND
        cex."new price" = cdel."new price" AND
        cex.id > cdel.id
)
'''

cur.execute(delete_dupes)

这指示 PostgreSQL 删除任何具有相同名称、价格和新价格但主键高于当前行的其他行的行。

于 2012-09-02T14:09:21.683 回答