我正在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)
答案 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
和实际运行时的结果