我正在寻找一种方法来根据另一个表的行中的某些值从一个表的SELECT中过滤掉行.
我正在尝试下面的示例结构.我有一个博客文章内容表(每篇博文一行),另一个关于帖子的元数据表(每个键值对一行;每行有一个列与博客文章关联;每行多行博客文章).我想只在元数据中没有行的情况下拉一行帖子,其中Metadata.pID = posts.pID AND Metadata.k =’optout’.也就是说,对于下面的示例结构,我只想回到posts.ID = 1行.
(根据我的尝试)JOIN最终不会删除有一些元数据的帖子,其中Metadata.k =’optout’,因为该pID的另一行元数据意味着它会进入结果.
MysqL> select * from posts;+-----+-------+--------------+| pID | Title | content |+-----+-------+--------------+| 1 | Foo | Some content || 2 | bar | More content || 3 | Baz | Something |+-----+-------+--------------+3 rows in set (0.00 sec)MysqL> select * from Metadata;+------+-----+--------+-----------+| mdID | pID | k | v |+------+-----+--------+-----------+| 1 | 1 | date | yesterday || 2 | 1 | thumb | img.jpg || 3 | 2 | date | today || 4 | 2 | optout | true || 5 | 3 | date | tomorrow || 6 | 3 | optout | true |+------+-----+--------+-----------+6 rows in set (0.00 sec)
子查询可以给我与我想要的相反:
MysqL> select posts.* from posts where pID = any (select pID from Metadata where k = 'optout');+-----+-------+--------------+| pID | Title | content |+-----+-------+--------------+| 2 | bar | More content || 3 | Baz | Something |+-----+-------+--------------+2 rows in set (0.00 sec)
…但是使用pID!= any(…)给了我帖子中的所有3行,因为每个pID都有一个元数据行,其中k!=’optout’.最佳答案听起来你想要做left JOIN,然后检查连接表的值为NulL的结果,表明没有这样的连接记录.
例如:
SELECT * FROM posts left JOIN Metadata ON (posts.pID = Metadata.pID AND Metadata.k = 'optout')WHERE Metadata.mdID IS NulL;
这将从表格帖子中选择任何没有相应元数据行且值为k =’optout’的行.
编辑:值得注意的是,这是左连接的关键属性,不适用于常规连接;即使连接表中不存在匹配值,左连接也将始终返回第一个表中的值,从而允许您根据缺少这些行执行选择.
编辑2:让我们澄清这里关于left JOIN和JOIN(为了清晰起见我称之为INNER JOIN但在MysqL中可互换)的情况.
假设您运行以下两个查询之一:
SELECT posts.*,Metadata.mdID,Metadata.k,Metadata.v FROM posts INNER JOIN Metadata ON posts.pID = Metadata.pID;
要么
SELECT posts.*,Metadata.v FROM posts left JOIN Metadata ON posts.pID = Metadata.pID;
两个查询都生成以下结果集:
+-----+-------+--------------+------+-------+-----------+| pID | Title | content | mdID | k | v |+-----+-------+--------------+------+-------+-----------+| 1 | Foo | Some content | 1 | date | yesterday || 1 | Foo | Some content | 2 | thumb | img.jpg |+-----+-------+--------------+------+-------+-----------+
现在,让我们假设我们修改查询以添加提到的“optout”的额外条件.首先,INNER JOIN:
SELECT posts.*,Metadata.v FROM posts INNER JOIN Metadata ON (posts.pID = Metadata.pID AND Metadata.k = "optout");
正如所料,这不会返回任何结果:
Empty set (0.00 sec)
现在,将其更改为left JOIN:
SELECT posts.*,Metadata.v FROM posts left JOIN Metadata ON (posts.pID = Metadata.pID AND Metadata.k = "optout");
这会产生一个结果集:
+-----+-------+--------------+------+------+------+| pID | Title | content | mdID | k | v |+-----+-------+--------------+------+------+------+| 1 | Foo | Some content | NulL | NulL | NulL |+-----+-------+--------------+------+------+------+
INNER JOIN和left JOIN之间的区别在于,如果来自BOTH联接表的行匹配,则INNER JOIN将仅返回结果.在left JOIN中,无论是否找到任何要加入的内容,都将始终返回第一个表中匹配的行.在很多情况下,使用哪一个并不重要,但选择正确的一个非常重要,这样才能获得意想不到的结果.
所以在这种情况下,建议查询:
SELECT posts.*,Metadata.v left JOIN Metadata ON (posts.pID = Metadata.pID AND Metadata.k = 'optout')WHERE Metadata.mdID IS NulL;
将返回与上面相同的结果集:
+-----+-------+--------------+------+------+------+| pID | Title | content | mdID | k | v |+-----+-------+--------------+------+------+------+| 1 | Foo | Some content | NulL | NulL | NulL |+-----+-------+--------------+------+------+------+
希望清除它!加入是一个很好的东西要学习,完全理解何时使用哪一个是一件非常好的事情. 总结
以上是内存溢出为你收集整理的sql – 根据不同表中的列从SELECT中删除行全部内容,希望文章能够帮你解决sql – 根据不同表中的列从SELECT中删除行所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)