我在SQL表中提供了一些数据,需要根据某些规则进行转换。 但是,这种转换需要动态地寻址列名,即应该存储值的列的名称本身作为值存储在其他列中,等等。 另外,根据值是否存在于不同列的范围内,应该为一个输入行生成多个输出行,因此我猜这是一种转置。
让我用一个例子说明一下:
id | targetColumnName | col1 | col2 | col3 | col4
-----------------------------------------------------
1 foo 5
2 foo 7 42
3 bar 3 6
4 foo 5
5 bar
6 bar 2 12
这应该产生以下结果:
id | foo | bar
--------------
1 5
2 7
2 42
3 3
3 6
4 5
6 2
6 12
换句话说,对于任何colX列中的每个当前值,在targetColumnName列指定的列中生成一个具有该值的输出行。
这让我相信使用SQL根本不是一个好主意,至少不是通过创建一个简单的查询。它可能可以创建一个复合语句/存储过程,但对我来说似乎仍然是错误的工具。
我的数据也是csv格式,我觉得有一个强大的脚本语言和文本操作功能可以更好地适应这项工作,但我只是抓住了Python的表面,我不知道任何Perl,只有一点点awk等 我知道我可以用Java来解决这个问题,但我仍然觉得这可以通过Python中的一个神奇的单行程来完成。 :)
所以问题基本上是1)用SQL(ite)做这个是合理的,2)其他工具会更好吗?
答案 0 :(得分:1)
虽然不完全是单行,但在Python(*)中相对容易。标准库中的csv模块是您的朋友。
假设目标列名称未知且文件很大而无法读入内存,则必须读取CSV一次以获取所有可能的列名称,然后再次读取实际转换。
这是一些伪代码:
import csv
fieldnames = set('id')
with open('in.csv', 'rb') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
fieldname = row[1]
fieldnames.add(row[1])
fieldnames = sorted(fieldnames)
with open('in.csv', 'rb') as csvfile:
reader = csv.reader(csvfile)
with open('out.csv', 'w') as outfile:
writer = csv.DictWriter(outfile, fieldnames=fieldnames)
for row in reader:
id_ = row[0]
fieldname = row[1]
for field in row[2:]:
if field:
writer.writerow({'id': id_, fieldname: field})
您可能需要根据CSV的方言将某些参数调整为csv.reader
。
(*)17个非空行:)