将连接的两列结果折叠为一列

时间:2017-11-08 15:54:20

标签: python mysql pivot mariadb

我试图找出一种时间有效的方法来将我们通常连接在一起的两个表折叠到一个表中。这些表包含读数,其中表A是包含读数类型的表,表B包含表A的FK和实际读数值。这两个表在我们的生产服务器上都是一个gb。

这两个表的架构是以下

表A

id | fk_id | timestamp | type
 1 |   1   | 1510155021| type A
 2 |   1   | 1510155021| type B

表B

id | fk_to_a | value 
1  |   1     | 30.5
2  |   2     | 50.7

我们通常会执行类似

的联接
select * 
from a 
join b
on b.fk_to_a = a.id
order by a.time_stamp desc

这里的关键点是连接将给我们一堆行,其中每n行将有一个n + 1"伙伴"行。

连接的示例结果是

a.id | a.fk_id | a.timestamp | a.type | b.id | b.fk_to_a | b.reading
  1  |   1     |  1510155021 | type A |   1  |    1      | 30.5
  2  |   1     |  1510155021 | type B |   2  |    2      | 50.7

第一行是n,第二行是n + 1。 n和n + 1共同的唯一共同点是它们的时间戳,它总是相同的。

我们希望将这两行压缩成一行,就像

一样
c.id | c.fk_id | c.timestamp | c.a_reading | c.b_reading
 1   |    1    |  1510155021 |     30.5    |   50.7 

我目前有一个非常非常基本的迁移脚本,我使用python来获取查询并存储连接的结果,遍历此连接(这需要几个小时)来查找n和n + 1 in为了创建"对",然后通过INSERT语句将这些对输出到新表中。

这是我的for循环遍历连接,这是99%的时间执行此ETL作业的时间。

#above is the join, database initialization. I'm using pymysql 
combinedList = []
eventList = list(cursor.fetchall())
for idx, row in enumerate(eventList):
    if (idx + 1) < eventLength:
        if eventList[idx][2] == eventList[idx+1][2]:
            insertStatement = 'INSERT INTO c (fk_to_a, timestamp, a_reading, b_reading) VALUES('
            insertStatement += str(eventList[idx][1]) + ',' + str(eventList[idx][2]) + ',' + str(eventList[idx][6]) + ',' + str(eventList[idx+1][6]) + ');'
            combinedList.append(insertStatement)
            del eventList[idx+1]

    else:
       print 'end of the events'

我知道迁移策略还有改进的余地。有没有人有经验做我喜欢做的事情?

感谢您抽出时间阅读本文。

2 个答案:

答案 0 :(得分:2)

将两个单独的行(数据)合并为一个是JOIN的用途,这些行是来自不同的表还是来自同一个表。您可以编写一个相对简单的查询来生成所需的行,例如

select
  a1.id as id,
  a1.fk_id as fk_id,
  a1.timestamp as timestamp,
  b1.reading as a_reading,
  b2.reading as b_reading
from
  a as a1
  join a as a2 on a1.timestamp = a2.timestamp
  join b as b1 on b1.fk_to_a = a1.id
  join b as b2 on b2.fk_to_a = a2.id
where
  a1.type = 'type A' and a2.type = 'type B'

在MySQL中,您可以将此类查询与CREATE TABLE ... SELECT语句或INSERT INTO ... SELECT语句结合使用(取决于目标表是否已存在)来填充新表,并将所有内容保留在内数据库。将其保存在数据库中应该会有很大的改进。

原始表上的合适索引可能有助于查询性能。您可能会发现,只有在最初填充后才能在结果表上创建任何所需索引的效率更高。

答案 1 :(得分:1)

请提供一些示例代码。

我会尝试的是一个两步的数据库内解决方案。 CREATE一个临时表,INSERT只有你想要的最终密钥进入该表(保留其他字段为空),然后UPDATE该表包含一个或多个具有所需逻辑的查询。 (一个查询将填充id = n,下一个将仅在id = n + 1时填充不同的列。可以将两者合并。)

首先,我看看它有多快,接下来我会考虑并行创建多个临时表并将它们组合起来,可能使用存储过程和临时表。

在MySQL中,我将MYISAM存储引擎用于登台表,然后将它们组合到最终表中。