2015-07-04 50 views
1

我想要获取数据库AA中数据库AA中缺失的任何表或字段。我正在使用INFORMATION_SCHEMA.columns获取信息。所以,我写了一个'缺失记录'查询来找到它们。在测试中,我使用了2个数据库,我知道BB在另一个表中有1个缺失的表和1个缺失的字段。
这是我第一次尝试:确定两个MySQL数据库模式之间的差异

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; 

0.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; 

0.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'); 

0.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秒。显然不是一个好的现实世界的解决方案。

+0

information_schema对于查询来说相对昂贵,因为这些表并不是真实的,并且查询经常检查比查询实际需要的更多的内部结构。这有助于解释为什么第一个查询更快 - “LEFT JOIN(SELECT ...)BB'实际上创建了一个临时表”BB“* first *,因此查询中第二个表格实际上是在外部查询运行之前完全填充,与最后显示的非常缓慢的变体形成对比,这可能会针对每列向i_s发出请求。 –

回答

1

假设记录看起来像这样:

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 

注意,无线-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

会有与没有记录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

希望这有助于。

+0

谢谢。如果你看看我的编辑,你会看到基准测试结果。你重写查询1给了最好的时间。 –

+0

非常好的作品,@TomCollins。感谢您分享基准测试结果。 – zedfoxus

0

你的第一个查询应该是这样的,

Select AA.* 
(
    SELECT table_name, 
      column_name 
    From information_schema.columns 
    Where table_schema = 'wireless-2015-05' 
) 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 BB.table_name is null or BB.column_name is null 

您的查询问题:

你放在哪里查询与错误条件

WHERE AA.table_schema = 'wireless-2015-05' 
    AND BB.table_schema = 'wireless-2015-04' 
    AND BB.column_name IS NULL 

当记录中不存在的BB然后BB.table_schema = 'wireless-2015-04'这种情况变得错误,因此整个结果将是错误的,所以你没有重新获得SULT。

而对于第二个查询,我认为@zedfoxus是正确的。

你也可以使用EXCEPT的概念,它给你的愿望结果。

以下查询从查询​​中返回EXCEPT运算符左边的所有不同值,这些值在正确的查询中也找不到。

SELECT DISTINCT table_name, 
       column_name 
FROM information_schema.columns 
WHERE table_schema = 'wireless-2015-05' 

EXCEPT 

SELECT DISTINCT table_name, 
       column_name 
FROM information_schema.columns 
WHERE table_schema = 'wireless-2015-04' 
+0

EXCEPT子句不起作用。谷歌搜索显示,该条款不适用于MySQL。 –