SQL子查询和ORDER BY

时间:2016-10-18 17:17:12

标签: mysql sql

我正在PHPMyAdmin中学习SQL,想知道我的解决方案是否合适,或者我是否正在做一些不是最好的标准。谢谢。

  

作者(ID,FirstName,LastName,YearOfBirth,Gender,LivingCityID)

     

book(ID,Name,Type,YearPublished,PublisherID,SoldBookCount)

     

写(BookID,AuthorID)

     

城市(ID,城市名称,国家/地区)

     

publisher(ID,PublisherName,PublisherCityID)

查找未在作者居住城市发布的所有图书的ID。一本书可能有几位作者。

SELECT w.BookID
FROM author as a, book as b, writes as w, publisher as p
WHERE a.LivingCityID != p.PublisherCityId AND w.AuthorID = a.ID AND w.BookID = b.ID AND p.ID = b.PublisherID
ORDER BY w.BookID ASC

接下来的两个基本相同,但我认为我所写的是草率的。有什么更好的方法呢?

查找在1900年之后在1600年之前发布图书的出版商的ID ,但是在1600年到1900年之间没有出版任何图书。

SELECT DISTINCT PublisherID
FROM book
WHERE PublisherID NOT IN (SELECT PublisherID
 FROM book
 WHERE YearPublished >=1600 AND YearPublished <= 1900)

查找在1900年之后发布图书的出版商的ID AND ,但是在1600年到1900年之间没有出版任何图书。

SELECT DISTINCT PublisherID
FROM book
WHERE PublisherID NOT IN (SELECT PublisherID
 FROM book
 WHERE YearPublished >=1600 AND YearPublished <= 1900)
      AND PublisherID IN (SELECT PublisherID
FROM book
WHERE YearPublished < 1600)
      AND PublisherID IN (SELECT PublisherID
FROM book
WHERE YearPublished > 1900)

1 个答案:

答案 0 :(得分:3)

我觉得你做得很好。以下任何内容都与您所做的完全不同;以下信息只是增加了不同的观点。

<强>第一

第一个查询可以使用JOIN来编写,如下所示:

SELECT w.BookID
FROM book b
LEFT JOIN writes w on w.bookid = book.id
LEFT JOIN author a on a.id = w.authorid
LEFT JOIN publisher p on p.id = b.publisherid
WHERE NOT a.LivingCityID = p.PublisherCityId
ORDER BY w.BookID ASC

使用where子句过滤信息。使用join子句显示关系。如果你想要所有书籍,我会把它作为SQL中的第一个表格,以便于阅读(个人意见,并且在进行左连接时也很重要)。

<强>第二

第二个查询可以重写为

SELECT DISTINCT publisherid
FROM book b
INNER JOIN publisher p on p.id = b.publisherid
WHERE    NOT    b.yearpublished BETWEEN 1600 and 1900

在这种情况下,我们要求在1600年到1900年之间(包括1600年和1900年)出版的书not。我们还加入图书和出版商以获取发布商信息。

编写此查询的替代方法是:

SELECT DISTINCT publisherid
FROM publisher p
WHERE EXISTS (
    SELECT 1 
    FROM book 
    WHERE    NOT    yearpublished BETWEEN 1600 and 1900
        AND publisherid = p.id
)

我们要求发布商表格检查是否有符合我们特定需求的书籍记录。如果是的话,很棒...做一个选择。否则,继续下一条记录。

很好读:http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx。尽管博客是关于SQL Server的,但这种理念仍然适用。

<强>第三

您的查询显示正常。使用exists关键字添加以下示例。

SELECT DISTINCT publisherid
FROM publisher p
WHERE EXISTS (
    SELECT 1 
    FROM book 
    WHERE    NOT    yearpublished BETWEEN 1600 and 1900
        AND publisherid = p.id
) 
AND EXISTS (
    SELECT 1 
    FROM book 
    WHERE yearpublished < 1600
        AND publisherid = p.id
)
AND EXISTS (
    SELECT 1 
    FROM book 
    WHERE yearpublished > 1900
        AND publisherid = p.id
)

in子句的交易是,如果>1900有成千上万的publisherid会议标准,您的查询可能会变慢(取决于优化器)。 exists条款有助于克服in的一些限制。

另一种写作方式是:

SELECT publisherid
FROM 
(
    SELECT DISTINCT 
        CASE WHEN yearpublished < 1600 THEN 1600 ELSE 1900 END AS yr,
        publisherid
    FROM book b
    INNER JOIN publisher p on p.id = b.publisherid
    WHERE    NOT    b.yearpublished BETWEEN 1600 and 1900
) t
GROUP BY yr
HAVING COUNT(*) = 2

在这里,我们创建一个子查询,并为其指定别名t。此子查询结合了书籍和发布者,并忽略了年度发布不受欢迎的记录。选择是由publisherid完成的,case语句用作标记。年&lt; 1600标记为1600.年&gt; 1900标记为1900.这给我们的结果如下:

1600  publisherid#1
1600  publisherid#1
1900  publisherid#1
1600  publisherid#2
1600  publisherid#3
1900  publisherid#3
...

使用distinct,我们将结果缩短为:

1600  publisherid#1    |
1900  publisherid#1    | --> this and above record will become a group
1600  publisherid#2
1600  publisherid#3    |
1900  publisherid#3    | --> this and above record will become a group
...

现在我们按发布商ID进行分组,并仅询问那些数量为2的发布商ID。#1和#3将符合上述示例中的条件。

注意

未测试这些查询。他们只是展示了编写查询的不同方式并突出了某些差异。哪一个很快,哪一个很慢? - 这取决于您的数据,索引以及explain和运行时的结果。

我的一般模式

  • 使用joins而不是where来组合表格
  • 使用exists而不是in
  • 使用虚拟数据集检查explain和实际运行时的结果
  • 添加索引以涵盖分组,过滤和排序
  • 添加索引提示,以查看查询是否使用我们使用
  • 暗示的索引更快地执行