mysql - 确定两个 MySQL 数据库模式之间的差异

标签 mysql sql

我想获取数据库 AA 中数据库 BB 中缺失的任何表或字段。我正在使用 INFORMATION_SCHEMA.columns 来获取信息。所以,我写了一个“丢失的记录”查询来找到它们。在测试中,我使用了 2 个数据库,其中我知道 BB 有 1 个缺失表和另一个表中有 1 个缺失字段。
这是我的第一次尝试:

SELECT AA.table_name,
       AA.column_name,
       BB.table_name,
       BB.column_name
FROM   information_schema.columns AS AA
       LEFT JOIN information_schema.columns AS BB
              ON ( AA.table_name = bb.table_name )
                 AND ( AA.column_name = BB.column_name )
WHERE  AA.table_schema = 'wireless-2015-05'
   AND BB.table_schema = 'wireless-2015-04'
   AND BB.column_name IS NULL

这返回了 0 条记录。所以,然后我尝试了:

SELECT AA.table_name,
       AA.column_name
FROM   information_schema.columns AS AA
WHERE  AA.table_schema = 'wireless-2015-04'
   AND NOT EXISTS(SELECT BB.table_name,
                         BB.column_name
                  FROM   information_schema.columns AS BB
                  WHERE  BB.table_schema = 'wireless-2015-05')

我又得到了 0 条记录。最后我试了这个:

SELECT table_name,
       column_name
FROM   (SELECT DISTINCT table_name,
                        column_name
        FROM   information_schema.columns
        WHERE  table_schema = 'wireless-2015-04'
        UNION ALL
        SELECT DISTINCT table_name,
                        column_name
        FROM   information_schema.columns
        WHERE  table_schema = 'wireless-2015-05') AS tbl
GROUP  BY table_name,
          column_name
HAVING Count(*) = 1 

这产生了预期的结果。

虽然我不介意使用第三个查询,但我不明白为什么前两个查询不起作用。我想知道以供将来引用。谁能发现问题?


更新:
对于那些感兴趣的人,这里有 4 个有效的查询,以及运行每个查询所花费的时间。以最快的顺序列出,时间列在查询下方。

SELECT AA.table_name,
       AA.column_name
FROM   information_schema.columns AS AA
       LEFT JOIN (SELECT table_name,
                         column_name
                  FROM   information_schema.columns
                  WHERE  table_schema = 'wireless-2015-04') BB
              ON AA.table_name = BB.table_name
                 AND AA.column_name = BB.column_name
WHERE  AA.table_schema = 'wireless-2015-05'
       AND BB.table_name IS NULL; 

.047秒

SELECT table_name,
       column_name
FROM   (SELECT DISTINCT table_name,
                        column_name
        FROM   information_schema.columns
        WHERE  table_schema = 'wireless-2015-04'
        UNION ALL
        SELECT DISTINCT table_name,
                        column_name
        FROM   information_schema.columns
        WHERE  table_schema = 'wireless-2015-05') AS tbl
GROUP  BY table_name,
          column_name
HAVING Count(*) = 1; 

.078秒

SELECT DISTINCT table_name,
                column_name,
                Concat(table_name, '--', column_name) AS tc
FROM   information_schema.columns
WHERE  table_schema = 'wireless-2015-05'
HAVING tc NOT IN(SELECT DISTINCT Concat(table_name, '--', column_name)
                 FROM   information_schema.columns
                 WHERE  table_schema = 'wireless-2015-04'); 

.125秒(今天早上想到的新方案)

SELECT aa.table_name,
       aa.column_name
FROM   information_schema.columns aa
WHERE  table_schema = 'wireless-2015-05'
       AND NOT EXISTS (SELECT 1
                       FROM   information_schema.columns
                       WHERE  table_schema = 'wireless-2015-04'
                              AND table_name = aa.table_name
                              AND column_name = aa.column_name); 

44.382 秒。显然这不是一个很好的现实世界解决方案。

最佳答案

假设记录看起来像这样:

   schema              table    column
   ----------------    -----    ------
1. wireless-2015-05    T1       F1
2. wireless-2015-05    T1       F2
3. wireless-2015-05    T2       F1
4. wireless-2015-04    T1       F1

请注意,wireless-2015-04 缺少表 T2 和列 T1.F2。我们将在描述和 SQL Fiddle 示例中使用此示例。您在前两次尝试中非常接近。只需一点点修改(包括在下面)就可以解决问题。

查询 1

让我们分解第一个查询。我们将离开 where子句,因为上面的例子只有 where 中提到的那两个模式条款。

SELECT ...
FROM information_schema.columns AS AA
LEFT JOIN information_schema.columns AS BB 
    on aa.table_name = bb.table_name
    and aa.column_name = bb.column_name

wireless-2015-05 + T1 + F1的第一条记录与同一表中的所有记录匹配(基于表名和列名)。所以,

  • AA 的记录 #1 将匹配 BB 的记录 #1 和 #4
  • AA 的第 2 条记录将与 BB 的第 2 条记录相匹配
  • AA 的第 3 条记录将与 BB 的第 3 条记录相匹配
  • AA 的记录 #4 将匹配 BB 的记录 #1 和 #4

示例:http://sqlfiddle.com/#!9/6b704/4

NULL 不会有记录BB.column_name。所以没有记录被提取。但是,这不是您要找的。

查询 1 改进

您可以重写查询 1 以使用如下方式为您提供正确的结果:

SELECT AA.table_name,
       AA.column_name
FROM information_schema.columns AS AA
LEFT JOIN 
( 
  select table_name, column_name from
  information_schema.columns
  where table_schema = 'wireless-2015-04'
) BB
  on AA.table_name = BB.table_name
  and AA.column_name = BB.column_name
WHERE 
  AA.table_schema = 'wireless-2015-05'
  and BB.table_name is null

示例:http://sqlfiddle.com/#!9/6b704/10

查询 2

基本上,查询 2 的 NOT EXISTS子查询缺少匹配 AA 列的子句。所以那不会给你带来结果

查询 2 改进

可以通过执行以下操作正确改进该查询:

select aa.table_name, aa.column_name
from information_schema.columns aa
where table_schema = 'wireless-2015-05'
and not exists (
  select 1
  from information_schema.columns
  where table_schema = 'wireless-2015-04'
  and table_name = aa.table_name
  and column_name = aa.column_name
);

示例:http://sqlfiddle.com/#!9/6b704/9

希望这对您有所帮助。

关于mysql - 确定两个 MySQL 数据库模式之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31216365/

相关文章:

mysql - 为什么编译器找不到 mysql 包含?

php - 使用 PHP 附加 html 表格

Mysql,选择最大值和匹配值

mysql - MySQL 性能的表主键

mysql - 在 MySQL 中使用 WHERE 和 AS

php - 查询未使用 PHP 添加到 SQL 数据库

mysql合并两个表的数据

SQL Server 多个替换

sql - 使用多对多关系显示表 1 中的所有记录 - postgresql

SQL 计数列和列表值计数