簡體   English   中英

使用Python將CSV條目與postgresql表中的條目進行比較

[英]Comparing CSV entries against entries in postgresql table using Python

我使用的是Postgresql 10,需要在CSV文件中進行查找,並將CSV文件中的條目與postgres表中的條目進行比較。 數據庫看起來像這樣,在這里我必須在domains表中插入域名,並在ranks表中進行排名:

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從domains表獲取到ranks表中,因為domain_id用作ranks表中的外鍵。 因此,我想檢查域名的CSV文件,並根據domains表進行檢查,並在插入排名時獲取每個域的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連接到數據庫並進行查詢。

有誰知道如何做到這一點,或者對實現這一目標有其他建議?

您可以創建一個臨時表來保存CSV數據,並使用SQL查詢將數據插入domainsranks表中。

這是臨時表的代碼:

CREATE TABLE temporary_table (
  rank INTEGER,
  domain TEXT
);

用CSV數據填充此表。

現在,插入CSV文件中存在但domains表中不存在的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_table表和domains表之間進行了連接。 這樣,我們可以找到每個等級的domain_id。

請注意,我在列插入中添加了1作為list_idnow()::date ,因為您沒有提供應該從中提取數據的列。

另外,請小心組合主鍵PRIMARY KEY (list_id, rank, date) 如果要在同一日期為多個域插入等級,並且某些域具有相同的rank和list_id值,則將得到重復的鍵值錯誤,並且不會插入數據。 為了解決此問題,您也可以在組合的主鍵中添加domain_id。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM