MYSQL LOAD DATA INFILE 语句适用于工作台,但不适用于 python

标签 mysql python-3.x mysql-workbench

我正在使用 Fannie Mae 抵押贷款数据试验 MySQL 和数据分析。为此,我创建了两个表(“perf”和“acq”)和几个 python 函数。我首先删除集合和表(如果存在),然后创建集合 (mortgage_analysis) 和两个表。然后我构建了一个文件列表,这些文件对应于我要执行的分析年数。所有这些都很好。

然后我使用以下函数从 Fannie Mae 的 perf 和 acq 文本文件中加载数据表。相同的函数用于加载两个表。它每次都与“perf”表一起工作,从不与“acq”表一起工作。如果我获取 SQL 语句并在 mySQL 工作台中执行它们,这些语句每次都有效。我很困惑,需要一些帮助。

在工作台中有效但在 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 总是空的)。

创建这两个表的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,它们确保日期格式正确,因此您可以进行比较、排序、日期算术等。

如果您有错误建议您应该放宽 sql_mode 并允许无效查询或无效数据,我建议您改为修复数据。即使您加载了数据,如果您允许非严格的 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 block 中。

加载数据成功。请注意,我必须对您的输入数据做出假设,因为您没有共享样本。我不知道您的文件是否真的格式正确,具有正确的字段分隔符和行分隔符。但我假设它是,因为你说它在 MySQL Workbench 中工作。

关于MYSQL LOAD DATA INFILE 语句适用于工作台,但不适用于 python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72003281/

相关文章:

mysql - 显示列名 MySQL

python - 将加密 key 存储为环境变量是个好主意吗?

c# - 出现sql语法错误?

php - 从数据库中仅选择 8 行

具有连接数和案例数的 Mysql 查询 - 添加更多连接和子查询

python-3.x - 当我尝试重新创建来自 Hands On Machine Learning with Sci-Kit Learn & Tensorflow 的住房数据集时,该数据集不显示

python - 无法在 Python 3 的列表理解中使用 locals() 吗?

mysql - 如何在mysql上处理大数据查询并具有更好的性能

mysql - 使用 mySQL 从其他行中选择具有多个值的行

php - 生成 CSV 时更改值