basic sql:检索所有不包含指定值的数据

时间:2017-11-27 17:07:27

标签: sql oracle

BOOKID AUNAME
  1101 Dilbert
  1101 Emerson
  1101 Sartre
  1102 Axel
  1102 Sartre
  1103 Breese
  1103 Marquez
  1104 Groom
  1104 Young
  1105 Blake
  1105 Julian
  1105 Scott
  1105 Verde
  1105 Young
  1106 Black
  1106 Sartre

BOOKID TITLE
  1101 Java Earth
  1102 MySQL
  1103 Sql Song
  1104 For Sale
  1105 No Sharing
  1106 Pascal
  2007 Index Choice
  2008 Business

好的,上面列出的是我正在使用的两个表。我们需要进行查询以列出所有不包括作者Sartre(共3页)的书籍的所有bookid,title和作者姓名

以下是我尝试做的两种方法,两种方法都没有成功:(注意:查询不会返回我在上面列出的所有内容[即标题],因为我需要先使用此部分才能工作)

select LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
from LITWORK, LITWORK_AUTHOR
where not exists (select BOOKID       
from LITWORK_AUTHOR
where AUNAME = 'Sartre');

RESULT SQL>启动q13.sql

未选择任何行

不确定为什么会这样执行,但没有选择任何行混淆:(。

第二次尝试:

select LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
from LITWORK, LITWORK_AUTHOR
where LITWORK.BOOKID != (select BOOKID 
from LITWORK_AUTHOR
where AUNAME = 'Sartre');

结果 SQL>启动q13.sql 其中LITWORK.BOOKID!=(选择BOOKID                         * 第3行的错误: ORA-01427: 单行子查询返回多行

所以这一次,我相信它填充了一个临时表,其中Bookid的Sartre是其中的一部分,但返回的不止一个(因为他创作了三个)因此无法工作,因为我打算.....如何获取sql到阅读并排除萨特是一个一个的一部分......

如何正确查询/嵌套子查询以使表格填充bookid不包含作者Sartre的所有bookids,titles和author name?

这是针对 基本 SQL类,我正在尝试专业开发,并且感到愚蠢地陷入困境。

到目前为止,我们已经学习了SELECT,WHERE,NOT IN,IN,EXISTS,NOT EXISTS,JOIN,UNION,GROUP BY,ORDER BY ....几乎涵盖了我们迄今为止学到的东西....所以答案不应该在这些事情之外。

5 个答案:

答案 0 :(得分:2)

你走了:

select a.BOOKID, a.TITLE, b.AUNAME
from LITWORK a
inner join LITWORK_AUTHOR b
   ON A.BOOKID = B.BOOKID
where a.BookID not In 
(select c.BOOKID from LITWORK_AUTHOR c where c.AUNAME = 'Sartre')

答案 1 :(得分:1)

第一个查询由于误用“不存在”而没有返回值。我在第一个查询中推断的意图是生成书籍列表,其中书籍的ID不是由Satre撰写的书籍列表中:

select LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
from LITWORK, LITWORK_AUTHOR
where LITWORK.BOOKID in (select BOOKID       
from LITWORK_AUTHOR 
where AUNAME <> 'SARTRE');

第二种方法返回指示的错误,因为您的子查询返回bookid的列表,但比较只能一次针对一条记录而不是列表。单个记录中的单个值无法与 set 值进行比较。那是当你回到'in'操作符的操作时 - 询问问题'以下列表中的值是否为x?'

然而,实际上,更好和可能的预期方法是使用连接,其中我建议使用ANSI标准连接语法而不是逗号分隔语法(并添加适当的修改以消除xQBert指出的问题,这个解决方案现在可能确实有太多的连接,但是在DBA过度使用'in'和'not exists'(特别是)之后,我倾向于首先尝试连接,然后看看如果我可以从那里改进:) :))。

这里的插图是创建书籍列表,加入作者表,然后外部加入到我们可以称之为萨特创作者的“非法书籍清单” - 并且还消除了空作者价值的问题:

Select a.*
  from litwork a
  join litwork_author b
    on a.bookid=b.bookid
  left outer join (select bookid
                     from litwork_author
                    where auname='SARTRE') c
    on a.bookid=c.bookid
  where c.bookid is null

答案 2 :(得分:1)

虽然经常使用的NOT IN语法确实有效,但依赖于数据和RDBMS,它可能非常昂贵且速度很慢。 (特别是如果NOT IN内的列表变得很大。)

因此,您可能希望考虑具有不同性能特征的替代方案(通常更好,但并非总是如此,并且所有这些都取决于表中的数据)。 ..

SELECT
    *
FROM
    litwork
INNER JOIN
    litwork_author
        ON  litwork_author.BookID = litwork.BookID
INNER JOIN
(
    SELECT
        BookID
    FROM
        litwork_author
    GROUP BY
        BookID
    HAVING
        SUM(CASE WHEN AuName = 'Sartre' THEN 1 ELSE 0 END) = 0  -- Return 1 row per book, where the total number of authors called 'Sartre' is 0
)
    validLitWork
        ON  validLitWork.BookID = litwork.BookID

在涉及'Sartre'的图书数量相对较高的情况下,可能表现良好。

相反,涉及'Sartre'的书籍数量相对较少,我倾向于采取相反的方式......

SELECT
    *
FROM
    litwork
INNER JOIN
    litwork_author
        ON  litwork_author.BookID   = litwork.BookID
LEFT JOIN
    litwork_author   excluded_litwork
        ON  excluded_litwork.BookID = litwork.BookID
        AND excluded_litwork.AuName = 'Sartre'
WHERE
    excluded_litwork.AuName IS NULL

答案 3 :(得分:0)

我不是,加入的忠实粉丝。这是旧的ansi 87标准...是1987年。我们现在30年后的情况?是的IT年代,来自现在应该已经死了;但遗憾的是它们仍然存在。

真正缺少的是exists和from子句之间的关联。

SELECT LW.BOOKID, LWA.AUNAME
FROM LITWORK LW
INNER JOIN LITWORK_AUTHOR LWA
 on LW.BookID = LWA.BookID
WHERE not exists (SELECT *       
                  FROM  LITWORK_AUTHOR LWA2
                  WHERE AUNAME = 'Sartre'
                    and LWA.BookID = LWA2.BookID);  <-- Your query is just missing this line

或将其更改为not In而不是存在。

select LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
from LITWORK, LITWORK_AUTHOR
where LitWork.BookID not In (select BOOKID          <--or change this to a not in instead of exists and add bookID.
                             from LITWORK_AUTHOR
                             where AUNAME = 'Sartre');

我通常会尝试使用not exists而不是not in,因为处理空值不会导致问题;一般来说,我看到不存在表现得更快(虽然情况并非总是如此)

我对表格的一般经验法则是,如果您在select中需要来自表格的值,则只有联接表格。如果不这样做,它们应该在where子句中作为所需数据的限制。

虽然我不推荐它作为派生表的开销,并且额外的连接可能会变得昂贵而不存在,而不是。

SELECT LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
FROM LITWORK LW
INNER JOIN LITWORK_AUTHOR LWA
 on LW.BookID = LWA.BookID
LEFT JOIN (select BookID from LITWORK_AUTHOR LWA2 where AUNAME = 'Sartre') BooksToExclude
 on booksToExclude.BookID = LWA.BookID
WHERE BooksToExclude.BookID is null 

最后一个说加入书籍和作者。然后包括所有结果,只包括BoooksToExclude以Satre作为作者的结果。

然后外部where子句表示如果Satre作为BooksToExclude派生表中的作者存在,则排除这些书。

你的第二个查询不起作用的原因是因为你的where子句将标量结果与非标量结果进行比较,而这些结果根本不起作用。

使用=!=操作数无法将1个值与多个值进行比较。

where LITWORK.BOOKID != (select BOOKID 
from LITWORK_AUTHOR
where AUNAME = 'Sartre');

!=将1值与1值进行比较,与=相同。如果您需要将1个值与多个值进行比较,则需要使用{Not} IN

您的第一个查询不起作用的原因仅仅是因为它们没有相关性且您有交叉连接。 ,表示LitWORK中的所有记录都与LitWork_Author的所有记录相关联。但你需要将这两者绑在Book_ID上。这是使用JOIN语法的一个原因,因为它避免了where子句被省略时的意外交叉连接。

但是如果你必须遵守ANSI 87标准......

select LITWORK.BOOKID, LITWORK_AUTHOR.AUNAME
from LITWORK, LITWORK_AUTHOR
where not exists (select A.BOOKID       
from LITWORK_AUTHOR A
where A.AUNAME = 'Sartre'
  and A.BookID = LitWork_Author.Book_ID)
 and LitWork.BookID = LitWork_Author.BookID

答案 4 :(得分:0)

首先要考虑结果应该是什么样子。一本书有一个标题,可能还有多个作者。你现在可以一次又一次地重复同一本书,每行有一位作者,或者为每本书显示一行,作者列表为逗号分隔字符串。

后一种方法是聚合;您汇总数据,例如每个结果行获得一本书。 “per”在SQL中转换为<section> <div class="labels"> Label 1<br> Label 2<br> Label 3<br> Label 4<br> Label 5<br> Label 6<br> Label 7<br> </div><div class="scrollable"> Line 1<br> Line 2<br> Line 3<br> Line 4<br> Line 5<br> Line 6<br> Line 7<br> </div> </section>。使用GROUP BY检查图书是否符合您的条件。

HAVING