MYSQL LOAD DATA INFILE 语句适用于 workbench,但不适用于 python
MYSQL LOAD DATA INFILE statement works in workbench, but not python
我正在试验 MySQL 并使用 Fannie Mae 抵押数据进行数据分析。为此,我创建了两个 table(“perf”和“acq”)和几个 python 函数。我首先删除集合和 tables(如果它们存在),然后创建集合 (mortgage_analysis) 和两个 tables。然后我构建了一个文件列表,这些文件对应于我要执行的分析年数。所有这些都很好。
然后我使用以下函数将 Fannie Mae 的 perf 和 acq 文本文件中的数据加载到 tables。相同的函数用于加载两个 tables。它每次都与“perf”table 一起工作,永远不会与“acq”table 一起工作。如果我采用 SQL 语句并在 mySQL workbench 中执行它们,这些语句每次都有效。我很困惑,需要一些帮助。
在 workbench 中有效但在 Python 中无效的 SQL 语句是:
LOAD DATA INFILE '/Users/<my user name>/github/mortgage-analysis-example/data/text/acq/Acquisition_2000Q1.txt'
INTO TABLE acq
FIELDS TERMINATED BY '|'
LINES TERMINATED BY '\n'
(loan_id, orig_channel, seller_name, orig_interest_rate, orig_upb, orig_loan_term,
orig_date, first_pay_date, orig_ltv, orig_cltv, num_borrowers, dti,
borrower_credit_score, first_home_buyer, loan_purpose, property_type, num_units,
occupancy_status, property_state, zip, mortgage_insurance_percent, product_type,
coborrow_credit_score, mortgage_insurance_type, relocation_mortgage_ind);
加载这个的python函数是:
def loadTable(env_in, template, file_list):
# env_in: (i know, uck global variable, holds info for this notebook common to all functions
# template: SQL template file
# file_list: python list element with fully qualified file names to use with SQL statement
env = env_in # environment info
from mysql.connector import Error
_file = open(env["base_path"]+env["path_separator"]+template, "r")
_template = _file.readlines()
try:
conn = mysql.connector.connect(host=env["mySQL"]["host"],user=env["mySQL"]["user"], passwd=env['pw'])
if conn.is_connected():
print('Connected to MySQL database')
except Error as e:
print(e)
cursor = conn.cursor()
cursor.execute("USE mortgage_analysis;")
cursor.execute("SET SESSION sql_mode = '';")
print("starting table load")
t0 = time.time()
res = []
for _file in file_list:
_sql = _template[0].format(_file)
print(f"\n{_sql}\n")
try:
res = cursor.execute(_sql)
warn = cursor.fetchwarnings()
#print(f"warn: {warn}")
except Error as e:
print(f"{_sql} \n{e}")
t1 = time.time()
print(f"Years: {env['years']} Table load time: {t1-t0}")
conn.close
return env
没有发现错误(尝试总是有效)并且没有生成警告(fetchwarnings 总是空的)。
用于创建两个 table 的 SQL 语句是:
DROP TABLE IF EXISTS acq;
CREATE TABLE acq (id DOUBLE AUTO_INCREMENT, loan_id DOUBLE, orig_channel VARCHAR(255), seller_name VARCHAR(255), orig_interest_rate DOUBLE, orig_upb DOUBLE, orig_loan_term DOUBLE, orig_date VARCHAR(255), first_pay_date VARCHAR(255), orig_ltv DOUBLE, orig_cltv DOUBLE, num_borrowers DOUBLE, dti DOUBLE, borrower_credit_score DOUBLE, first_home_buyer VARCHAR(255), loan_purpose VARCHAR(255), property_type VARCHAR(255), num_units DOUBLE, occupancy_status VARCHAR(255), property_state VARCHAR(255), zip DOUBLE, mortgage_insurance_percent DOUBLE, product_type VARCHAR(255), coborrow_credit_score DOUBLE, mortgage_insurance_type DOUBLE, relocation_mortgage_ind VARCHAR(255), PRIMARY KEY (id));
DROP TABLE IF EXISTS perf;
CREATE TABLE perf (id DOUBLE AUTO_INCREMENT, loan_id DOUBLE, monthly_reporting_period VARCHAR(255), servicer VARCHAR(255), interest_rate DECIMAL(6,3), current_actual_upb DECIMAL(12,2), loan_age DOUBLE, remaining_months_to_legal_maturity DOUBLE, adj_remaining_months_to_maturity DOUBLE, maturity_date VARCHAR(255), msa DOUBLE, current_loan_delinquency_status DOUBLE, mod_flag VARCHAR(255), zero_balance_code VARCHAR(255), zero_balance_effective_date VARCHAR(255), last_paid_installment_date VARCHAR(255), foreclosed_after VARCHAR(255), disposition_date VARCHAR(255), foreclosure_costs DOUBLE, prop_preservation_and_reair_costs DOUBLE, asset_recovery_costs DOUBLE, misc_holding_expenses DOUBLE, holding_taxes DOUBLE, net_sale_proceeds DOUBLE, credit_enhancement_proceeds DOUBLE, repurchase_make_whole_proceeds DOUBLE, other_foreclosure_proceeds DOUBLE, non_interest_bearing_upb DOUBLE, principal_forgiveness_upb VARCHAR(255), repurchase_make_whole_proceeds_flag VARCHAR(255), foreclosure_principal_write_off_amount VARCHAR(255), servicing_activity_indicator VARCHAR(255), PRIMARY KEY (id));
我测试了代码,我必须做一些更改才能让它工作。
不要更改 sql_mode
。我没有收到任何错误,我能够在不影响 sql_mode.
的情况下加载数据
我使用的测试数据:
1|2|name1|3|4|4|date|date|5|6|7|8|9|buyer|purpose|type|10|status|state|11|12|type|13|14|ind
1|2|name2|3|4|4|date|date|5|6|7|8|9|buyer|purpose|type|10|status|state|11|12|type|13|14|ind
我劝你选择更合适的数据类型。您应该几乎从不在 MySQL 中使用 FLOAT 或 DOUBLE,除非您要存储科学测量值或其他内容。绝对不是货币单位或整数。
我不会使用 VARCHAR 来存储日期。 MySQL 具有 DATE 和 DATETIME,这些确保日期是 well-formed,因此您可以进行比较、排序、日期算术等
如果您有错误建议您放宽 sql_mode 并允许无效查询或无效数据,我建议您改为修复数据。即使你加载了数据,如果你允许 non-strict SQL 模式,它也有变成垃圾的风险。
代码更改:
我没有使用 format()
来尝试将文件名插入查询模板,而是使用了一个查询参数。删除带有 _template[0].format(_file)
的行,改为使用:
res = cursor.execute(_template, [_file])
但模板必须将占位符放在不带引号的位置:
正确:
LOAD DATA INFILE %s INTO TABLE...
不正确:
LOAD DATA INFILE '%s' INTO TABLE...
最后,Python中的数据更改默认不提交。也就是说,您可以插入数据,然后当您使用 conn.close
时,未提交的更改将被丢弃。所以我加了一行:
conn.commit()
我在执行 SQL.
后将它放在 try/catch
块中
加载数据成功。请注意,我必须对您的输入数据做出假设,因为您没有共享样本。我不知道您的文件是否真的 well-formed 具有正确的字段分隔符和行分隔符。但我假设它是,因为你说它在 MySQL Workbench.
中有效
我正在试验 MySQL 并使用 Fannie Mae 抵押数据进行数据分析。为此,我创建了两个 table(“perf”和“acq”)和几个 python 函数。我首先删除集合和 tables(如果它们存在),然后创建集合 (mortgage_analysis) 和两个 tables。然后我构建了一个文件列表,这些文件对应于我要执行的分析年数。所有这些都很好。
然后我使用以下函数将 Fannie Mae 的 perf 和 acq 文本文件中的数据加载到 tables。相同的函数用于加载两个 tables。它每次都与“perf”table 一起工作,永远不会与“acq”table 一起工作。如果我采用 SQL 语句并在 mySQL workbench 中执行它们,这些语句每次都有效。我很困惑,需要一些帮助。
在 workbench 中有效但在 Python 中无效的 SQL 语句是:
LOAD DATA INFILE '/Users/<my user name>/github/mortgage-analysis-example/data/text/acq/Acquisition_2000Q1.txt'
INTO TABLE acq
FIELDS TERMINATED BY '|'
LINES TERMINATED BY '\n'
(loan_id, orig_channel, seller_name, orig_interest_rate, orig_upb, orig_loan_term,
orig_date, first_pay_date, orig_ltv, orig_cltv, num_borrowers, dti,
borrower_credit_score, first_home_buyer, loan_purpose, property_type, num_units,
occupancy_status, property_state, zip, mortgage_insurance_percent, product_type,
coborrow_credit_score, mortgage_insurance_type, relocation_mortgage_ind);
加载这个的python函数是:
def loadTable(env_in, template, file_list):
# env_in: (i know, uck global variable, holds info for this notebook common to all functions
# template: SQL template file
# file_list: python list element with fully qualified file names to use with SQL statement
env = env_in # environment info
from mysql.connector import Error
_file = open(env["base_path"]+env["path_separator"]+template, "r")
_template = _file.readlines()
try:
conn = mysql.connector.connect(host=env["mySQL"]["host"],user=env["mySQL"]["user"], passwd=env['pw'])
if conn.is_connected():
print('Connected to MySQL database')
except Error as e:
print(e)
cursor = conn.cursor()
cursor.execute("USE mortgage_analysis;")
cursor.execute("SET SESSION sql_mode = '';")
print("starting table load")
t0 = time.time()
res = []
for _file in file_list:
_sql = _template[0].format(_file)
print(f"\n{_sql}\n")
try:
res = cursor.execute(_sql)
warn = cursor.fetchwarnings()
#print(f"warn: {warn}")
except Error as e:
print(f"{_sql} \n{e}")
t1 = time.time()
print(f"Years: {env['years']} Table load time: {t1-t0}")
conn.close
return env
没有发现错误(尝试总是有效)并且没有生成警告(fetchwarnings 总是空的)。
用于创建两个 table 的 SQL 语句是:
DROP TABLE IF EXISTS acq;
CREATE TABLE acq (id DOUBLE AUTO_INCREMENT, loan_id DOUBLE, orig_channel VARCHAR(255), seller_name VARCHAR(255), orig_interest_rate DOUBLE, orig_upb DOUBLE, orig_loan_term DOUBLE, orig_date VARCHAR(255), first_pay_date VARCHAR(255), orig_ltv DOUBLE, orig_cltv DOUBLE, num_borrowers DOUBLE, dti DOUBLE, borrower_credit_score DOUBLE, first_home_buyer VARCHAR(255), loan_purpose VARCHAR(255), property_type VARCHAR(255), num_units DOUBLE, occupancy_status VARCHAR(255), property_state VARCHAR(255), zip DOUBLE, mortgage_insurance_percent DOUBLE, product_type VARCHAR(255), coborrow_credit_score DOUBLE, mortgage_insurance_type DOUBLE, relocation_mortgage_ind VARCHAR(255), PRIMARY KEY (id));
DROP TABLE IF EXISTS perf;
CREATE TABLE perf (id DOUBLE AUTO_INCREMENT, loan_id DOUBLE, monthly_reporting_period VARCHAR(255), servicer VARCHAR(255), interest_rate DECIMAL(6,3), current_actual_upb DECIMAL(12,2), loan_age DOUBLE, remaining_months_to_legal_maturity DOUBLE, adj_remaining_months_to_maturity DOUBLE, maturity_date VARCHAR(255), msa DOUBLE, current_loan_delinquency_status DOUBLE, mod_flag VARCHAR(255), zero_balance_code VARCHAR(255), zero_balance_effective_date VARCHAR(255), last_paid_installment_date VARCHAR(255), foreclosed_after VARCHAR(255), disposition_date VARCHAR(255), foreclosure_costs DOUBLE, prop_preservation_and_reair_costs DOUBLE, asset_recovery_costs DOUBLE, misc_holding_expenses DOUBLE, holding_taxes DOUBLE, net_sale_proceeds DOUBLE, credit_enhancement_proceeds DOUBLE, repurchase_make_whole_proceeds DOUBLE, other_foreclosure_proceeds DOUBLE, non_interest_bearing_upb DOUBLE, principal_forgiveness_upb VARCHAR(255), repurchase_make_whole_proceeds_flag VARCHAR(255), foreclosure_principal_write_off_amount VARCHAR(255), servicing_activity_indicator VARCHAR(255), PRIMARY KEY (id));
我测试了代码,我必须做一些更改才能让它工作。
不要更改 sql_mode
。我没有收到任何错误,我能够在不影响 sql_mode.
我使用的测试数据:
1|2|name1|3|4|4|date|date|5|6|7|8|9|buyer|purpose|type|10|status|state|11|12|type|13|14|ind
1|2|name2|3|4|4|date|date|5|6|7|8|9|buyer|purpose|type|10|status|state|11|12|type|13|14|ind
我劝你选择更合适的数据类型。您应该几乎从不在 MySQL 中使用 FLOAT 或 DOUBLE,除非您要存储科学测量值或其他内容。绝对不是货币单位或整数。
我不会使用 VARCHAR 来存储日期。 MySQL 具有 DATE 和 DATETIME,这些确保日期是 well-formed,因此您可以进行比较、排序、日期算术等
如果您有错误建议您放宽 sql_mode 并允许无效查询或无效数据,我建议您改为修复数据。即使你加载了数据,如果你允许 non-strict SQL 模式,它也有变成垃圾的风险。
代码更改:
我没有使用 format()
来尝试将文件名插入查询模板,而是使用了一个查询参数。删除带有 _template[0].format(_file)
的行,改为使用:
res = cursor.execute(_template, [_file])
但模板必须将占位符放在不带引号的位置:
正确:
LOAD DATA INFILE %s INTO TABLE...
不正确:
LOAD DATA INFILE '%s' INTO TABLE...
最后,Python中的数据更改默认不提交。也就是说,您可以插入数据,然后当您使用 conn.close
时,未提交的更改将被丢弃。所以我加了一行:
conn.commit()
我在执行 SQL.
后将它放在try/catch
块中
加载数据成功。请注意,我必须对您的输入数据做出假设,因为您没有共享样本。我不知道您的文件是否真的 well-formed 具有正确的字段分隔符和行分隔符。但我假设它是,因为你说它在 MySQL Workbench.
中有效