【问题标题】:How would you compare two big ( cca 2 mil rows x 60 cols) dataframes / data tables?你会如何比较两个大(cca 2 mil rows x 60 cols)数据框/数据表?
【发布时间】:2020-01-29 15:20:58
【问题描述】:

我见过一些方法,我如何比较(compare_df、dplyr 等)并且它们足够有效。但是,当我想比较大或巨大的数据帧时,我会遇到内存耗尽错误,所以我想问一些方法我怎样才能做得更好。

我在 DB2 数据库/数据表中有数据,如果有的话,我也可以接受服务器端解决方案。 任务基本上是我应该找到两个数据表之间的所有差异。我可以使用主键作为连接。

我还教导说,如果我将行连接成一个字符串并在主键连接上进行比较(在这种情况下我只能有 2 列),这可能是一个解决方案,但我应该知道两者之间的区别在哪里这两行,所以这将是一个额外的步骤。

欢迎任何开箱即用的想法。

【问题讨论】:

  • 您希望如何准确地获得某行的差异?在结果集的 60 列中还是在一列中?其他的?
  • 我更愿意取回一个数据框,其中以某种方式标记了差异。但是也可以只使用索引(例如:如果它返回“id: 6253 at col 14”处的两个数据帧之间存在差异)

标签: r dataframe db2 compare


【解决方案1】:

您可以使用方便的DISTINCT predicate(从 Db2 11.1 开始)尝试以下原样。等价表达式可能用于早期版本,但它们会更长一些。

WITH 
  A (ID, C1, C2) AS 
(
VALUES
  (1, '=', '=')
, (2, '=', '=')
, (4, 'A', '=')
, (5, '=', NULL)
, (6, 'A', 'A')
)
, B (ID, C1, C2) AS 
(
VALUES
  (1, '=', '=')
, (3, '=', '=')
, (4, 'B', '=')
, (5, '=', NULL)
, (6, 'B', 'B')
)
SELECT 
  COALESCE(A.ID, B.ID) AS ID
,  CASE 
    WHEN A.ID IS NULL THEN '-A' 
    WHEN B.ID IS NULL THEN '-B'
    ELSE ''
   END
|| CASE WHEN A.ID = B.ID AND A.C1 IS DISTINCT FROM B.C1 THEN ', C1' ELSE '' END  
|| CASE WHEN A.ID = B.ID AND A.C2 IS DISTINCT FROM B.C2 THEN ', C2' ELSE '' END
--...
--|| CASE WHEN A.ID = B.ID AND A.C60 IS DISTINCT FROM B.C60 THEN ', C60' ELSE '' END
  AS FLAG
FROM A
FULL JOIN B ON B.ID = A.ID
WHERE 
   A.ID IS DISTINCT FROM A.ID
OR A.C1 IS DISTINCT FROM B.C1
OR A.C2 IS DISTINCT FROM B.C2
--...
--OR A.C60 IS DISTINCT FROM B.C60;

结果是:

|ID         |FLAG      |
|-----------|----------|
|4          |, C1      |
|6          |, C1, C2  |
|3          |-A        |
|2          |-B        |

我们在两个表之间使用FULL OUTER JOIN,具有以下 OR 条件:

  • KEY (ID) 仅对于这些表之一为 NULL(此 KEY 在对应表中不匹配)
  • 对应的列值之一存在差异

FLAG 列包含差异类型:

  • -TABNAME - 表中缺少 KEY TABNAME
  • , Cx - 在Cx 列中存在差异 - 对于每个这样的列

如果两个表中都有大量列,则可以使用多个 Db2 系统视图为此 SELECT 语句生成相应的表达式。
例如,如果我们要为SYSIBM.SYSTABLES 表生成这样的表达式, 使用其唯一索引之一(您必须选择这样的索引,最好是支持主键的索引),然后按原样运行以检查:

SELECT 
  '|| CASE WHEN ' || I.KEY_EXPR || ' AND A.' || C.COLNAME || ' IS DISTINCT FROM B.' || C.COLNAME || ' THEN '', ' || COLNAME || ''' ELSE '''' END' AS SELECT_LIST_EXPR
, 'OR A.' || C.COLNAME || ' IS DISTINCT FROM B.' || C.COLNAME AS WHERE_EXPR
FROM 
  SYSCAT.COLUMNS C
, TABLE 
(
SELECT LISTAGG('A.' || U.COLNAME || ' = B.' || U.COLNAME, ' AND ') AS KEY_EXPR 
FROM SYSCAT.INDEXES I
JOIN SYSCAT.INDEXCOLUSE U ON U.INDSCHEMA = I.INDSCHEMA AND U.INDNAME = I.INDNAME
WHERE 
    I.TABSCHEMA=C.TABSCHEMA AND I.TABNAME=C.TABNAME
AND I.INDSCHEMA='SYSIBM' AND I.INDNAME='INDTABLES01'
AND I.UNIQUERULE IN ('P', 'U')
) I 
WHERE C.TABSCHEMA='SYSIBM' AND C.TABNAME='SYSTABLES'
--FETCH FIRST 10 ROWS ONLY
;

【讨论】:

    【解决方案2】:

    一种方式(多种方式)是

    (SELECT 'A', * FROM A EXCEPT ALL SELECT 'A', * FROM B)
    UNION ALL
    (SELECT 'B', * FROM B EXCEPT ALL SELECT 'B', * FROM A)
    

    返回的第一列中包含“A”的行在 TABLEA 中,但不在 TABLEB 中。

    返回的第一列中包含“B”的行在 TABLEB 中,但不在 TABLEA 中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-30
      相关资源
      最近更新 更多