SQL:选择一个表中不存在的键

时间:2011-07-18 10:51:45

标签: mysql sql select

我得到了一张正常设置auto inc的表格。 IDS。某些行已被删除,因此ID列表可能如下所示:

  

(1,2,3,5,8,......)

然后,从另一个来源(编辑:另一个来源=不在数据库中)我有这个数组:

  

(1,3,4,5,7,8)

我正在寻找一个可以在数据库上使用的查询来获取ID的列表:不在我所拥有的数组的表中。这将是:

  

(4,7)

这样的存在吗?我现在的解决方案是要么创建一个临时表,所以命令“WHERE table.id IS NULL”工作,或者更糟糕的是,使用PHP函数array_diff查看从表中检索所有id后缺少的内容。

由于id列表正在接近数百万或行,我渴望找到最佳解决方案。

谢谢! /托马斯

编辑2:

我的主要应用程序是一个相当简单的表,其中包含很多行。这个应用程序是使用浏览器管理的,我使用PHP作为代码的解释器。

此表中的所有内容都将导出到另一个系统(第三方产品),除了手动使用该程序中的导入功能外,还无法执行此操作。也可以在另一个系统中插入新行,尽管商定的路由永远不会这样做。

问题是我的系统无法100%确定用户在按下“导出”键时所做的一切都是正确的。或者,在其他系统中没有创建任何行。

从另一个系统我可以得到一个CSV文件,其中包含系统所有的行。因此,通过比较CSV文件和我的表格,我可以看到: *应该导入的其他系统中缺少任何行 *如果有人在其他系统中创建了行

问题不是“解决它”。它正在制定最佳解决方案,因为行中有太多数据。

再次感谢!

/托马斯

6 个答案:

答案 0 :(得分:20)

我们可以选择使用MYSQL。

SELECT id
FROM table_one
WHERE id NOT IN ( SELECT id FROM table_two )

<强>被修改

如果您从 csv文件获取源代码,那么您只需将这些值直接放在:

我假设CSV类似于1,2,3,...,n

SELECT id
FROM table_one
WHERE id NOT IN ( 1,2,3,...,n );

编辑2

或者如果您想选择其他方法,则可以使用mysqlimport导入MySQL数据库中临时表中的数据并检索结果并删除表。

喜欢:

创建表格

CREATE TABLE my_temp_table(
   ids INT,
);

加载.csv文件

LOAD DATA LOCAL INFILE 'yourIDs.csv' INTO TABLE my_temp_table
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
(ids);

选择记录

SELECT ids FROM my_temp_table
WHERE ids NOT IN ( SELECT id FROM table_one )

删除表

DROP TABLE IF EXISTS my_temp_table

答案 1 :(得分:1)

使用left join怎么样;像这样的东西:

select second_table.id
from second_table
    left join first_table on first_table.id = second_table.id
where first_table.is is null


您也可以使用子查询;根据具体情况,它可能会或可能不会更快,但是:

select second_table.id
from second_table
where second_table.id not in (
    select first_table.id
    from first_table
)

或使用not exists

select second_table.id
from second_table
where not exists (
    select 1
    from first_table
    where first_table.id = second_table.id
)

答案 2 :(得分:0)

您正在寻找的功能不是(&lt;&gt; ALL的别名)

MYSQL文档:

http://dev.mysql.com/doc/refman/5.0/en/all-subqueries.html

使用示例:

http://www.roseindia.net/sql/mysql-example/not-in.shtml

享受!

答案 3 :(得分:0)

问题是T1可能有一百万行或一千万行,而且这个数字可能会改变,所以你不知道你的比较表T2有多少行,那个没有间隙的行应该有,执行WHERE NOT EXISTS或LEFT JOIN测试NULL。

但问题是,为什么你会关心是否存在缺失值?我提交,当应用程序正确构建时,自动增量键序列中是否存在间隙应该无关紧要。即使是差距很重要的应用程序,例如检查寄存器,也不应该使用自动增加主键作为支票号的同义词。

注意详细说明您的申请要求?

答案 4 :(得分:0)

好的,我已经阅读了你的编辑/阐述。同步两个数据库,其中第二个数据库不应插入任何新行,但可能会这样做,听起来像是一个等待发生的问题。

上面建议的方法(不存在或左边连接)都不是气密的,也不是保证两个系统之间逻辑完整性的方法。在两个表都包含具有相同ID的行的情况下,他们不会让您知道哪个系统创建了一行。你现在关注的是差距,但另一个问题是重复的ids。

例如,如果两个表都有一个id为13887的行,则不能假设database1创建了该行。它本可以插入到database2中,然后database1可以使用相同的id插入一个新行。您必须比较所有列值以确定行是否相同。

因此我建议你也要探索GUID作为自动增量整数的替代品。您无法阻止database2插入行,但至少使用GUID,您不会遇到第二个数据库插入行并为其分配第一个数据库可能也使用的主键值的问题,从而产生两个不同的行同样的身份。 CreationDateTime和LastUpdateDateTime列也很有用。

但是,正确的解决方案(如果可用)是仅维护一个数据库并允许用户远程访问它,例如,通过Web界面。这将消除复制/同步问题的混乱和复杂性。

如果远程访问Web界面不可行,也许您可​​以将其中一个数据库设为只读?或者database2是否必须对行进行更新?也许你可以拒绝插入权限?你使用什么数据库引擎?

答案 5 :(得分:0)

我遇到了同样的问题:我有一个来自用户的值列表,我想在anther表中找到 not 的子集。我在oracle中通过在select语句中构建一个伪表来实现它。这是在Oracle中实现它的一种方法。在没有“from dual”的情况下在MySQL中试用它:

-- find ids from user (1,2,3) that *don't* exist in my person table
-- build a pseudo table and join it with my person table
select pseudo.id from (
  select '1' as id from dual
  union select '2' as id from dual
  union select '3' as id from dual
) pseudo
left join person
  on person.person_id = pseudo.id
where person.person_id is null