[英]How to import csv data with parent/child (category-subcategory) hierarchy to MySQL using Python
我正在使用Python的MySQLdb模块将包含父级/子级(类别-子类别)层次结构的csv文件导入MySQL。 这是一个示例csv文件:
vendor,category,subcategory,product_name,product_model,product_price
First vendor,category1,subcategory1,product1,model1,100
First vendor,category1,subcategory2,product2,model2,110
First vendor,category2,subcategory3,product3,model3,130
First vendor,category2,subcategory4,product5,model7,190
在MySQL中,我想使用具有层次结构的category
表,如下所示:
CREATE TABLE IF NOT EXISTS `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL DEFAULT '0',
`status` tinyint(1) NOT NULL,
PRIMARY KEY (`category_id`),
KEY `parent_id` (`parent_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
我的问题是:如何确定此表中的parent_id
?
这是我到目前为止拥有的Python脚本:
import MySQLdb
import csv
con = MySQLdb.connect('localhost', 'root', '', 'testdb', use_unicode=True, charset='utf8')
with con:
cur = con.cursor()
csv_data = csv.reader(file('test.csv'))
csv_data.next()
for row in csv_data:
cur.execute("SELECT manufacturer_id FROM manufacturer WHERE name=%s", [row[0]],)
res = cur.fetchall()
if res:
vendor_id = res[0][0]
else:
cur.execute("INSERT INTO manufacturer (name) VALUES (%s)", (row[0],))
vendor_id = cur.lastrowid
cur.execute("SELECT category_id FROM category_description WHERE name=%s", [row[2]])
res = cur.fetchall()
if res:
category_id = res[0][0]
else:
# What parent_id should be inserted here?
cur.execute("INSERT INTO category (`status`, `parent_id`) VALUES (%s,%s)", (1,))
category_id = cur.lastrowid
cur.execute("INSERT INTO category_description (category_id, name) VALUES (%s,%s)", (category_id,row[2],))
cur.execute("INSERT INTO product (model, manufacturer_id, price,) VALUES (%s, %s, %s)", (row[4], `vendor_id`, row[8],))
product_id = cur.lastrowid
cur.execute("INSERT INTO product_to_category (product_id, category_id) VALUES (%s, %s)", (product_id, category_id,))
cur.commit()
这是我的示例中使用的其他表的定义:
CREATE TABLE IF NOT EXISTS `manufacturer` (
`manufacturer_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`manufacturer_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `category_description` (
`category_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`category_id`,`language_id`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `product` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`model` varchar(64) NOT NULL,
`manufacturer_id` int(11) NOT NULL,
`price` decimal(15,4) NOT NULL DEFAULT '0.0000',
PRIMARY KEY (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
CREATE TABLE IF NOT EXISTS `product_to_category` (
`product_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
PRIMARY KEY (`product_id`,`category_id`),
KEY `category_id` (`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
在层次结构表结构中,层次结构顶部的任何成员都没有父级。 我可能会使用NULL
父ID来显示此信息,但是根据您定义category
表的方式,您似乎想通过给父ID赋值为0
来显示此信息。
由于您只有两个级别(类别和子类别)的固定深度层次结构,因此任务相对简单。 对于CSV数据的每一行,您需要:
row[1]
)是否在表中; 如果不是,请插入其父ID为0
。 category_id
。 row[2]
)是否在表中; 如果不是,请插入其父ID等于步骤2中的category_id
。 在示例代码中,您永远不会访问父级( row[1]
); 您需要将其插入表格中,以使其具有孩子可以引用的ID。 如果您已在此之前插入了父母,则可能仍应检查以确保其在其中。
您在这里还有其他问题:
category_description
表的PK是在您忘记在表中定义的列( language_id
)上定义的。 category_description
, product
和product_to_category
强制使用外键约束。 cur.commit()
将引发异常–这是MySQLdb中Connection
对象的一种方法。 当然,无论如何都没有为MyISAM表实现COMMIT
,因此您也可以通过完全删除该行来避免异常。 row[8]
也会引发异常。 (这是为什么您应该测试MCVE以确保其正常工作的一个很好的例子!) with con as cur:
在退出with
块时获取一个提交自己的游标。 这样可以节省几行代码,并且可以在不对连接对象进行微观管理的情况下管理事务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.