mysql - 转换一个有效的 SQL NOT IN

标签 mysql sql

我有一些 SQL 可以告诉我从未使用过剑的 super 英雄。

创建表

首先,这是用于创建和填充表的 (MySQL) 脚本。

CREATE TABLE IF NOT EXISTS `mydb`.`weaponry` (
  `hero` VARCHAR(20) NULL,
  `weapon` VARCHAR(20) NULL)
ENGINE = InnoDB

insert into weaponry (hero, weapon) values ('Wonder Woman', 'Lasso of truth');
insert into weaponry (hero, weapon) values ('Wonder Woman', 'Sword');
insert into weaponry (hero, weapon) values ('Wonder Woman', 'Shield');
insert into weaponry (hero, weapon) values ('Spider Man', 'Web');
insert into weaponry (hero, weapon) values ('Gamora', 'Sword');
insert into weaponry (hero, weapon) values ('Gamora', 'Daggar');
insert into weaponry (hero, weapon) values ('Batman', 'Batarang');
insert into weaponry (hero, weapon) values ('Batman', 'Batgrapple');
insert into weaponry (hero, weapon) values ('Batman', 'Tranquilizer gun');

使用 NOT IN 的工作代码和一个子选择

select distinct hero from weaponry
  where hero not in
  (select hero from weaponry where weapon = 'Sword')

这正确地返回了没有使用剑的蜘蛛侠和 bat 侠。

备选方案 1:使用 NOT EXISTS

我想使用 NOT EXISTS 实现相同的查询. 我看了https://stackoverflow.com/a/5231731/509840 . 我试过这个:

select distinct hero from weaponry
  where not exists
  (select * from weaponry where weapon = 'Sword')

不幸的是,这不会返回任何行。

备选方案 2:使用 LEFT JOIN

我也看了这个答案:https://stackoverflow.com/a/17413996/509840 . 我很想尝试更换 NOT INLEFT JOIN .

  select * from weaponry a
    left join weaponry b on a.hero=b.hero and a.weapon=b.weapon
    where a.weapon <> 'Sword'

但这只会返回所有非剑类英雄(包括神奇女侠和卡魔拉),因为所有英雄都使用剑以外的武器。

你能帮我用 NOT EXISTS 重写 NOT IN 查询吗?或 LEFT JOIN

编辑:Left Join 和相关子查询

@JeffUK 在他的评论中建议,通过删除 WHERE 可以更好地理解相关子查询。条款。这是对 select 的一个小修改。与 where已删除。

select distinct a.hero, weaponryInner.hero from weaponry a
    left join 
        (Select * from weaponry b where weapon = 'Sword') as weaponryInner
    on a.hero=weaponryInner.hero 

结果是两列英雄,其中一些是NULL .

-------------------------------
Hero          |  Hero
-------------------------------
Wonder Woman  |  Wonder Woman
Gamora        |  Gamora
Spider Man    |  <null> 
Batman        |  <null>
-------------------------------

所以添加最后的where weaponryInner.Weapon is null只会返回蜘蛛侠和 bat 侠。

最佳答案

第一个检查是否存在任何持剑英雄,您只需要检查“当前”持剑英雄。

select distinct hero from weaponry as a
  where not exists
  (select * from weaponry as b where b.weapon = 'Sword' and b.hero = a.hero )

第二个对您不起作用,联接独立地作用于每一行,因此将完全按照您所看到的进行。你可以做这样的事情,有点复杂但可以完成工作。

我们在子查询中只找到带剑的英雄,并将其加入所有英雄,在子查询中找不到任何带有“NULL”的英雄,因此永远不要挥舞剑。

select distinct a.hero from weaponry a
    left join 
        (Select * from weaponry b where weapon = 'Sword') as weaponryInner
    on a.hero=weaponryInner.hero 
where weaponryInner.Weapon is null

关于mysql - 转换一个有效的 SQL NOT IN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44443887/

相关文章:

mysql - 如何使用 SQL 查询从字母数字中获取数值并按数字排序

php - Laravel 5.5 - Eloquent - 从具有 "microseconds"字段的 MySQL 表中检索 "datetime(6)"

php - 根据id和timestamp从两个表中选择

MySQL:更新前触发不起作用

mysql - 需要一个 sql 查询来查找 'customer info' 表中所有带空格的 3 部分名称

php - 检查多列上的重复行

mysql - 如何编写 SQL 查询以找出 5 列中最高的 4 列的总和?

php - MySQL从两个表中使用JOIN选择随机行

php - 为什么 PHP 不写入 MySQL 服务器?

mysql - SQL在搜索不同列时忽略WHERE