【问题标题】:Comparing CSV entries against entries in postgresql table using Python使用 Python 将 CSV 条目与 postgresql 表中的条目进行比较
【发布时间】:2018-05-06 21:58:08
【问题描述】:

我正在使用 Postgresql 10,我需要在 CSV 文件中进行查找,并将 CSV 文件中的条目与我的 postgres 表中的条目进行比较。数据库看起来像这样,我必须在域表中插入域名并在排名表中排名:

CREATE TABLE lists (list_id integer PRIMARY KEY,
                    list_name text);

CREATE TABLE domains (domain_id BIGSERIAL PRIMARY KEY,
                      domain_name text UNIQUE);

CREATE TABLE ranks (list_id integer REFERENCES lists,
                    domain_id integer REFERENCES domains,
                    rank integer,
                    date date,
                    PRIMARY KEY (list_id, rank, date));

csv 包含两个条目,一个排名和一个域名,如下所示:“1, google.com”

目前我将域名插入到域表中,其中域 id 会自动递增并用作主键。然后我想将排名插入排名表中。但是我正在努力将 domain_id 从域表中获取到等级表中,因为 domain_id 充当等级表中的外键。因此,我想检查 CSV 中的域名,对照域表进行检查,并在插入排名时取出每个域的 domain_id。所以每个域名可以有几个等级,这是由日期来区分的。

我现在使用的当前脚本如下所示:

    import tkinter as tk
    from tkinter import filedialog
    import csv
    import psycopg2
    import shutil as sh

    root = tk.Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename()
    new_path = 'C:/Users/%user%/Desktop/alexa-top1m_16042018.csv'

    conn = psycopg2.connect("host=localhost dbname=test user=postgres   password=test")
    cur = conn.cursor()

    sh.copy2(file_path, new_path)
    with open(new_path, 'r') as original: data = original.read()
    with open(new_path, 'w') as modified: modified.write("rank,domain_name\n" + data)

    with open(new_path, 'r') as f:
        reader = csv.DictReader(f)


    for row in reader:
        cur.execute(
           """INSERT INTO ranks (list_id, rank, date) VALUES (%s, %s, %s);""", ( 1, row['rank'], '2018-04-16',)
        )

   conn.commit()

我正在使用 psycopg2 连接到数据库并进行查询。

有谁知道如何做到这一点,或者对如何实现这一点有任何其他建议?

【问题讨论】:

    标签: python postgresql csv


    【解决方案1】:

    您可以创建一个临时表来保存 CSV 数据并使用 SQL 查询将数据插入到 domainsranks 表中。

    临时表的代码如下:

    CREATE TABLE temporary_table (
      rank INTEGER,
      domain TEXT
    );
    

    用 CSV 数据填充此表。

    现在,插入存在于 CSV 文件中但不存在于 domains 表中的域。

    INSERT INTO domains (domain_name)
      (SELECT DISTINCT domain as domain_name FROM temporary_table
        EXCEPT
      SELECT domain_name FROM domains);
    

    现在,当您在 domains 表中拥有所有现有域时,我们可以在 ranks 表中插入行。

    INSERT INTO ranks (list_id, domain_id, rank, date)
        SELECT 1 as list_id, d.domain_id, rank, now()::DATE 
        FROM temporary_table tt JOIN domains d ON tt.domain = d.domain_name;
    

    为了获得我们要插入的排名的域 ID,我们通过域名在 temporary_tabledomains 表之间进行连接。这样,我们可以找到每个排名的 domain_id。

    请注意,我在排名插入中添加了 1 作为list_idnow()::date,因为您没有提供应该从中提取数据的列。

    另外,请注意组合主键 PRIMARY KEY (list_id, rank, date)。 如果要在同一日期为多个域插入排名,并且某些域具有相同的 rank 和 list_id 值,则会出现重复键值错误,并且不会插入数据。 为了解决这个问题,您也可以在组合主键中添加 domain_id。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 2021-08-14
      • 2019-08-26
      • 2015-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多