Pandas: to_sql()을 μ‚¬μš©ν•  λ•Œ 쀑볡 κΈ°λ³Έ ν‚€κ°€ κ°μ§€λ˜λ©΄ κ³„μ†ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?

에 λ§Œλ“  2017λ…„ 04μ›” 13일  Β·  19μ½”λ©˜νŠΈ  Β·  좜처: pandas-dev/pandas

μ½”λ“œ μƒ˜ν”Œ, κ°€λŠ₯ν•œ 경우 볡사-λΆ™μ—¬λ„£κΈ° κ°€λŠ₯ν•œ 예

df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)

문제 μ„€λͺ…

SQL ν…Œμ΄λΈ”μ— 큰 DataFrame을 μΆ”κ°€ν•˜λ €κ³  ν•©λ‹ˆλ‹€. DataFrame의 일뢀 행은 SQL ν…Œμ΄λΈ”μ˜ ν–‰κ³Ό μ€‘λ³΅λ˜κ³  μΌλΆ€λŠ” 그렇지 μ•ŠμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ to_sql() λŠ” 쀑볡이 ν•˜λ‚˜λΌλ„ κ°μ§€λ˜λ©΄ 싀행을 μ™„μ „νžˆ μ€‘μ§€ν•©λ‹ˆλ‹€.

to_sql(if_exists='append') κ°€ μ‚¬μš©μžμ—κ²Œ 쀑볡 ν‚€κ°€ μžˆλŠ” 행을 κ²½κ³ ν•˜κ³  싀행을 μ™„μ „νžˆ μ€‘μ§€ν•˜μ§€ μ•Šκ³  κ³„μ†ν•΄μ„œ μƒˆ 행을 μΆ”κ°€ν•˜λŠ” 것이 ν•©λ¦¬μ μž…λ‹ˆλ‹€. 큰 데이터 μ„ΈνŠΈμ˜ 경우 쀑볡이 μžˆμ„ 수 μžˆμ§€λ§Œ λ¬΄μ‹œν•˜κ³  싢을 κ²ƒμž…λ‹ˆλ‹€.

쀑볡을 λ¬΄μ‹œν•˜κ³  계속 μ‹€ν–‰ν•˜λŠ” 인수λ₯Ό μΆ”κ°€ν•  수 μžˆμŠ΅λ‹ˆκΉŒ? 'append_skipdupes' 와 같은 μΆ”κ°€ if_exists μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆκΉŒ?

pd.show_versions() 의 좜λ ₯

μ„€μΉ˜λœ 버전

컀밋: μ—†μŒ
파이썬: 3.6.0.final.0
파이썬 λΉ„νŠΈ: 64
운영 체제: μœˆλ„μš°
OS 릴리슀: 10
기계: AMD64
ν”„λ‘œμ„Έμ„œ: Intel64 μ œν’ˆκ΅° 6 λͺ¨λΈ 60 μŠ€ν…Œν•‘ 3, μ •ν’ˆ 인텔
λ°”μ΄νŠΈ μ˜€λ”: 쑰금
LC_ALL: μ—†μŒ
λž‘: μ—†μŒ
LOCALE: English_United States.1252

νŒ¬λ”: 0.19.2
μ½”: μ—†μŒ
핍: 9.0.1
μ„€μ • 도ꡬ: 28.8.0
사이썬: μ—†μŒ
숫자: 1.12.0
scipy: μ—†μŒ
톡계 λͺ¨λΈ: μ—†μŒ
xarray: μ—†μŒ
μ•„μ΄νŒŒμ΄μ¬: 5.3.0
μŠ€ν•‘ν¬μŠ€: μ—†μŒ
νŒ¨ν‹°: μ—†μŒ
λ‚ μ§œ μœ ν‹Έλ¦¬ν‹°: 2.6.0
ν”ΌμΈ : 2016.10
블둝: μ—†μŒ
병λͺ© ν˜„μƒ: μ—†μŒ
ν…Œμ΄λΈ”: μ—†μŒ
numexpr: μ—†μŒ
matplotlib: μ—†μŒ
openpyxl: μ—†μŒ
xlrd: μ—†μŒ
xlwt: μ—†μŒ
xlsxwriter: μ—†μŒ
lxml: μ—†μŒ
bs4: μ—†μŒ
html5lib: 0.999999999
httplib2: μ—†μŒ
API ν΄λΌμ΄μ–ΈνŠΈ: μ—†μŒ
sqlalchemy: 1.1.9
pymysql: μ—†μŒ
psycopg2: μ—†μŒ
μ§„μž2: 2.9.5
보토: μ—†μŒ
pandas_datareader: μ—†μŒ

Enhancement IO SQL

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

이것은 λ˜ν•œ "쀑볡 μ—…λ°μ΄νŠΈ" λͺ¨λ“œλ„ 지원해야 ν•©λ‹ˆλ‹€.

λͺ¨λ“  19 λŒ“κΈ€

이것은 λ˜ν•œ "쀑볡 μ—…λ°μ΄νŠΈ" λͺ¨λ“œλ„ 지원해야 ν•©λ‹ˆλ‹€.

@rosstripi 이 μ•„μ΄λ””μ–΄λŠ” ν™•μ‹€νžˆ λ°›μ•„λ“€μ—¬μ§ˆ 것이라고 μƒκ°ν•˜μ§€λ§Œ AFAIK의 μ£Όμš” 병λͺ© ν˜„μƒμ€ sql/sqlalchemyλ₯Ό 풍미에 ꡬ애받지 μ•ŠλŠ” λ°©μ‹μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 이 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλŠ” 방법에 λŒ€ν•œ 일뢀 탐색은 ν™•μ‹€νžˆ ν™˜μ˜ν•©λ‹ˆλ‹€!

μ•ˆλ…•ν•˜μ„Έμš” 이에 λŒ€ν•œ ν•΄κ²° 방법을 μ•Œμ•„λƒˆμŠ΅λ‹ˆκΉŒ? μ•Œλ €μ£Όμ„Έμš”

이 κ΅¬ν˜„μ— λŒ€ν•œ μ—…λ°μ΄νŠΈκ°€ μžˆμŠ΅λ‹ˆκΉŒ?

μ €λŠ” 이제 PostgreSQL 및 SQLAlchemyμ—μ„œ 이 λ¬Έμ œμ— 직면해 있으며 "쀑볡 μ—…λ°μ΄νŠΈ μ‹œ"λ₯Ό μ›ν•©λ‹ˆλ‹€.

μž‘μ—…μ— κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€

ν•΄κ²° 방법은 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ 고유 인덱슀λ₯Ό μ œκ±°ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

sqlquery="ALTER 'TABLE DATABASE'.'TABLE' DROP INDEX 'idx_name'"
λ‚˜μ€‘μ—
df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)
μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

MySQL μ„œλ²„κ°€ 인덱슀λ₯Ό λ‹€μ‹œ μΆ”κ°€ν•˜κ³  쀑볡을 μ‚­μ œν•˜λ„λ‘ ν•˜μ‹­μ‹œμ˜€.
sqlquery="ALTER IGNORE TABLE 'DATABASE'.'TABLE' ADD UNIQUE INDEX 'idx_name' ('column_name1' ASC, 'column_name2' ASC, 'column_name3' '[ASC | DESC]')"

νŠΉμ • μ‘μš© ν”„λ‘œκ·Έλž¨μ— 따라 도움이 될 수 μžˆμŠ΅λ‹ˆλ‹€.
μ–΄μ¨Œλ“  $# append_skipdupes if_exists μ˜΅μ…˜μ΄ 훨씬 더 μ’‹μŠ΅λ‹ˆλ‹€.

append_skipdupes λŠ” 이것을 μ²˜λ¦¬ν•˜λŠ” μ™„λ²½ν•œ λ°©λ²•μž…λ‹ˆλ‹€.

예, append_skipdupes +1

df.to_sql() 의 μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ 이 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€λŠ” 데 λ™μ˜ν–ˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ sqliteμ—μ„œ μ‚¬μš©ν•˜λŠ” ν•΄κ²° λ°©λ²•μž…λ‹ˆλ‹€.

CREATE TABLE IF NOT EXISTS my_table_name (
    some_kind_of_id INT PRIMARY KEY ON CONFLICT IGNORE,
    ...

그런 λ‹€μŒ 쀑볡 ν•­λͺ©μ„ μ‚½μž…ν•˜λ©΄ μžλ™μœΌλ‘œ λ¬΄μ‹œλ˜κ³  μ€‘λ³΅λ˜μ§€ μ•Šμ€ ν•­λͺ©μ΄ μ˜¬λ°”λ₯΄κ²Œ μ²˜λ¦¬λ©λ‹ˆλ‹€. 제 κ²½μš°μ—λŠ” 데이터가 정적 이어야 ν•˜λ―€λ‘œ μ—…λ°μ΄νŠΈν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. 데이터 ν”Όλ“œμ˜ ν˜•μ‹μ΄ λ¬΄μ‹œν•  수 μ—†λŠ” 쀑볡을 얻을 수 μžˆλ‹€λŠ” κ²ƒλΏμž…λ‹ˆλ‹€.

MariaDb 및 MySql의 λ‹€λ₯Έ ν•΄κ²° 방법:
df.to_csv("test.csv")
λ‹€μŒμ„ μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.
LOAD DATA INFILE 'test.csv' IGNORE INTO TABLE mytable λ˜λŠ”
LOAD DATA INFILE 'test.csv' REPLACE INTO TABLE mytable .

LOAD DATAλŠ” INSERT보닀 맀우 λΉ λ¦…λ‹ˆλ‹€.

μ™„μ „ν•œ μ½”λ“œ:

csv_path = str(Path(application_path) / "tmp" / "tmp.csv").replace("\\", "\\\\")
df.to_csv(csv_path, index=False, sep='\t', quotechar="'", na_rep=r'\N')
rq = """LOAD DATA LOCAL INFILE '{file_path}' REPLACE INTO TABLE {db}.{db_table}
        LINES TERMINATED BY '\\r\\n'
        IGNORE 1 LINES
         ({col});
        """.format(db=db,
                   file_path=csv_path,
                   db_table=table_name,
                   col=",".join(df.columns.tolist()))

λ‚˜λŠ” 이것이 #14553을 μ£Όμ†Œλ‘œ ν•˜λŠ” upsert_ignore 인수둜 #29636μ—μ„œ ν•΄κ²°λ˜κ³  μžˆλ‹€κ³  λ―ΏμŠ΅λ‹ˆλ‹€.

append_skipdupes +1

append_skipdupes의 경우 +1

'append_skipdupes'λ₯Ό μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

예, λΆ€νƒν•©λ‹ˆλ‹€. κΈ°λ³Έ ν‚€ μ—΄λΏλ§Œ μ•„λ‹ˆλΌ 'append_skipdupes'λ₯Ό μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€. λ‹€λ₯Έ 고유 μ—΄ 간에 쀑볡이 μžˆλŠ” 경우 μƒˆ 쀑볡 ν–‰ μΆ”κ°€λ₯Ό κ±΄λ„ˆλ›°μ–΄μ•Ό ν•©λ‹ˆλ‹€.

append_skipdupes의 경우 +1

append_skipdupes +1

append_skipdupes +1

append_skipdupes의 경우 +1

κ·Έλ™μ•ˆ https://pypi.org/project/pangres/ λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰