mysql - SQL 子查询和 ORDER BY

标签 mysql sql

我正在 PHPMyAdmin 中学习 SQL,想弄清楚我的解决方案是否合适,或者我正在做的事情是否不是最佳标准。谢谢。

author (ID, FirstName, LastName, YearOfBirth, Gender, LivingCityID)

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

writes (BookID, AuthorID)

city (ID, CityName, Country)

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

后面两个基本一样但是我觉得我写的比较草率。执行此操作的更好方法是什么?

查找在 1600 年之前在 1900 年之后出版书籍但在 1600 年和 1900 年之间没有出版任何书籍的出版商的 ID。

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

查找在 1600 年之前在 1900 年之后出版书籍但在 1600 年和 1900 年之间没有出版任何书籍的出版商的 ID。

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)

最佳答案

我觉得你做得很好。以下内容与您所做的没有太大不同;下面的信息只是增加了一个不同的视角。

首先

第一个查询可以使用 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 年)出版的书籍。我们还加入了书籍和出版商以获取出版商信息。

编写此查询的另一种方法是:

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

这里我们要求 publisher 表检查图书中是否有符合我们特定需要的记录。如果是,那就太好了……做一个选择。否则,继续下一条记录。

不错的阅读: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 子句的处理是,如果有数千个 publisherid 满足 >1900 的条件,您的查询可能会变慢(也取决于优化器)。 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。此子查询结合了书籍和出版商,并忽略了不需要 yearpublished 的记录。选择 publisherid 并使用 case 语句作为标记。 <1600 年用 1600 标记。>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 和运行时的结果。

我的一般模式

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

关于mysql - SQL 子查询和 ORDER BY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40114328/

相关文章:

asp.net - 在Linq中使用JOIN进行SQL ExecuteQuery问题

sql - SQL 查询使用 TOP 1 + ORDER BY 或 max/min + GROUP BY?

python - Django中用于投票应用程序的数据库结构

Mysql:使用 INSERT SELECT 中的自动递增 ID 进行后续 INSERT

sql - mysql比较枚举

mysql - 将 CSV 导出到 MySQL

mysql - 授予所有特权的逆

java - Hibernate 在字符串数组中搜索

sql - 当 select 语句没有返回记录时,函数中的变量会得到什么?

mysql - 根据 PostgreSQL 中的列值指定的间隔