MySQL-关系数据库和标记

MySQL-关系数据库和标记,mysql,sql,Mysql,Sql,我对这一点摸不着头脑已经有一段时间了,所以我想我应该问一下堆栈溢出注意:我是一个试图学习更多SQL的SQL新手,所以请尊重和解释: 我有一个sql表,看起来像是posts: id | user -------------------------------- 0 | tim 1 | tim 2 | bob 另一种称为标记,它以文本形式存储posts表中POST上的标记: id | postID | tag -------------------------------- 0 | 0

我对这一点摸不着头脑已经有一段时间了,所以我想我应该问一下堆栈溢出注意:我是一个试图学习更多SQL的SQL新手,所以请尊重和解释:

我有一个sql表,看起来像是posts:

id | user
--------------------------------
0  | tim
1  | tim
2  | bob
另一种称为标记,它以文本形式存储posts表中POST上的标记:

id | postID | tag
--------------------------------
0  | 0      | php
1  | 2      | php
2  | 0      | mysql
3  | 1      | mysql
4  | 1      | sql
5  | 3      | perl
为了澄清,其中的概念:id=0被标记为php、mysql;id=1标记为sql、mysql;id=2被标记为php;id=3被标记为perl

如何编写WHERE语句来获取标记为x的帖子,而不是由php定义的YX和y

例如,我如何才能将所有贴子标记为mysql而不是php

编辑 您还可以解释一下如何添加多个标记来搜索例如get all tagged mysql和recursion而不是php吗

select *
from
    (select distinct postID
    from tags
    where tag = "mysql") as t1
left join
    (select distinct postID
     from tags
     where tag = "php") as t2
using (postID)
where t2.postID is NULL
示例2:获取所有标记的mysql和递归,但不获取php:

select *
from
    ((select distinct postID
    from tags
    where tag = "mysql") as t1
join
    (select distinct postID
    from tags
    where tag = "recursion") as t3
using (postID))
left join
    (select distinct postID
     from tags
     where tag = "php") as t2
using (postID)
where t2.postID is NULL

我的建议是:

SELECT DISTINCT postID
FROM tags t1
WHERE EXISTS(SELECT NULL
             FROM tag t2
             WHERE t2.id = t1.id
               AND t2.tag = 'x')
  AND NOT EXISTS(SELECT NULL
                   FROM tag t2
                  WHERE t2.id = t1.id
                    AND t2.tag = 'y')

天真、简单且便于携带:

SELECT *
FROM posts
WHERE EXISTS (SELECT * FROM tags WHERE tags.postid = posts.id AND tags.tag = 'x')
AND NOT EXISTS (SELECT * FROM tags WHERE tags.postid = posts.id AND tags.tag = 'y')


现在,根据执行计划,您可以做其他事情来优化它。

+1对于真正好的任务,在sql中不容易完成。我更喜欢使用左连接,而不是exist谓词。看看我的答案……递归在SQL中是不容易做到的。如果你看你自己的答案,这基本上是一个带pk为空谓词的左连接。@todda,是的,我知道,我写的:。。。你想说什么?你说在SQL中不容易做到这一点的评论是错误的。谢谢,你能解释一下如何添加多个标记来搜索例如get all tagged mysql和recursion,但不是php@Tomas,好的,请参阅更新后的帖子。您只需向联接中添加另一个子查询。@Tomas Telensky:如果您想检查3个标记,该怎么办?4.5.我们的问题不是进化的,它们并不能真正回答问题。@Vincent你是在告诉我,我所问的基本上是不可能的,还是有一种方法不是过于复杂/刻薄,只是采取了不同的方法?如果只是添加子查询的问题,那么在执行查询之前,我能否在php中编写一个循环来向查询添加连接?还是我遗漏了什么?@Tomas:我知道如何使用PostgreSQL来实现这一点,但是MySQL不支持数组或递归查询来简化查询。如果不进行大量的连接或子查询,我看不出如何做到这一点。当然,你可以用PHP构造这个查询,但我怀疑它是否非常有效。昨天你没有回答我的一个问题吗!您还可以解释如何添加多个标记来搜索,例如get all tagged mysql和recursion,但不是phpMySQL不知道递归,所以据我所知,您必须对要查看的每个标记执行一个联接/子查询。你也许可以围绕GROUP_CONCAT制定一个解决方案,但这确实让人觉得有点黑客味。我会在我的答案中写下这个问题。谢谢你,这个练习的目的是让我学习并掌握如何构建标记系统:D,+1你确实帮了我很多。@Tomas:我收回我说的话,事实上,如果你想选择,例如,文章完全包含php和mysql标记,不包含它们。我不知道如何使用MySQL实现您所期望的功能。您是什么意思?这对只有这两个标签的帖子有效吗?或者别的什么?我可能在这里完全偏离了方向,但我不能这样做:从存在的帖子中选择*,从tags.postid=posts.id和tags.tag='x'和存在的标签中选择*,从tags.postid=posts.id和tags.tag='x2'和NOT EXISTS的标签中选择*,从tags.postid=posts.id和tags.tag='y'的标签中选择多个标签?我是否遗漏了什么…@Tomas-是的,但是您必须以某种动态方式添加and和NOT-要么在客户端代码中,要么在SQL中使用字符串,然后是MySQL的PREPARE特性。或者,您可以使用固定但大量的参数设置它们,并将null作为noop处理。ANSI SQL中通常没有可移植的数组处理功能。那当然很好。每种方言都有其特点或惯用的变通方法。