我们如何构建如此复杂的SQL语句?
[图书]isbn(主键),标题,类别id,子类别id,价格 [作者]isbn(FK)、作者id(PK)、姓名 [类别]类别id(主键),名称 [子类别]子类别id(PK)、类别id(FK)、名称 我有一个包含上述四个表的数据库(不是我设计的) 我想要一个具有以下格式的图书列表: isbn、标题、作者姓名、类别名称、子类别名称(可能没有)、价格 但也有一些复杂性,正如您所看到的,每本书可以有多个作者,作者姓名列应该有作者姓名,并用逗号分隔 对于更难的类别,有些类别没有子类别,因此有些图书记录的子类别id设置为0,因为其类别id指的是没有子类别的类别,在这种情况下,图书列表中的子类别名称列不需要显示任何内容 我真的不知道如何快速构建如此复杂的SQL语句来获取图书列表。有人能想出一个解决办法吗我们如何构建如此复杂的SQL语句?,sql,mysql,Sql,Mysql,[图书]isbn(主键),标题,类别id,子类别id,价格 [作者]isbn(FK)、作者id(PK)、姓名 [类别]类别id(主键),名称 [子类别]子类别id(PK)、类别id(FK)、名称 我有一个包含上述四个表的数据库(不是我设计的) 我想要一个具有以下格式的图书列表: isbn、标题、作者姓名、类别名称、子类别名称(可能没有)、价格 但也有一些复杂性,正如您所看到的,每本书可以有多个作者,作者姓名列应该有作者姓名,并用逗号分隔 对于更难的类别,有些类别没有子类别,因此有些图书记录的子类
非常感谢大家。像这样的事情应该很接近了
select
Book.ISBN,
Book.Title,
Author.Name,
Category.Name as Category_Name,
SubCategory.Name as SubCategory_Name,
Book.Price
from
Book join Author
on Book.ISBN = Author.ISBN
join Category
on Book.Category_ID = Category.Category_ID
join SubCategory
on Book.Category_ID = SubCategory.Category_ID
and Book.SubCategory_ID = SubCategory.Sub_Category_ID
像这样的事情应该很接近
select
Book.ISBN,
Book.Title,
Author.Name,
Category.Name as Category_Name,
SubCategory.Name as SubCategory_Name,
Book.Price
from
Book join Author
on Book.ISBN = Author.ISBN
join Category
on Book.Category_ID = Category.Category_ID
join SubCategory
on Book.Category_ID = SubCategory.Category_ID
and Book.SubCategory_ID = SubCategory.Sub_Category_ID
当您发现自己正在构建一个“极其复杂的SQL语句”时,通常最好退一步重新思考 记住这一点——对数据库表执行的绝大多数操作都是选择,而不是插入或更新(当然,每个规则都有例外) “花费”CPU周期计算诸如作者列表之类的内容的正确时间是在列表更改时,而不是在您只想提取信息时
将另一列添加到图书表中,称为author_list,然后在authors上创建一个insert/update触发器,以便在为特定ISBN更改作者时重新生成此列 这将使成本达到应有的水平,并使您的查询更加简单。触发器确保数据保持一致,如果您知道自己在做什么,可以中断3NF 至于子类别,
case
语句可以是您的朋友,但select上的每行函数永远无法很好地伸缩
我只需要在子类别中创建一组id为0的行(每个类别一行),并将其名称设置为空。然后可以通过一个简单的连接来完成,而不必担心性能。这也可以在类别上使用触发器,因此每个类别的子类别始终为0
通过这两项更改,查询变得简单得多,大致如下:
select b.isbn, b.title, b.author_list, c.name, sc.name, b.price
from Book b, Category c, SubCategory sc
where b.category_id = c.category_id
and b.category_id = sc.category_id
and b.subcategory_id = sc.subcategory_id
order by ...
这个查询应该很快就会出现,因为它只使用关系代数的基本级别(即,没有每行函数(包括case语句),没有子查询)。这是一个“老派”的查询,通过使用显式连接而不是隐式连接,您可能会获得更高的性能
最后一点:一个正确的3NF模式不会在authors表中包含ISBN——更好的选择是使用一个单独的BookAuthor表来保存ISBN和author_id,从而正确地建模多对多关系。但是为了性能,您可能已经改变了这一点(我不知道)。当您发现自己正在构建一个“极其复杂的SQL语句”时,通常最好是退一步重新思考 记住这一点——对数据库表执行的绝大多数操作都是选择,而不是插入或更新(当然,每个规则都有例外) “花费”CPU周期计算诸如作者列表之类的内容的正确时间是在列表更改时,而不是在您只想提取信息时
将另一列添加到图书表中,称为author_list,然后在authors上创建一个insert/update触发器,以便在为特定ISBN更改作者时重新生成此列 这将使成本达到应有的水平,并使您的查询更加简单。触发器确保数据保持一致,如果您知道自己在做什么,可以中断3NF 至于子类别,
case
语句可以是您的朋友,但select上的每行函数永远无法很好地伸缩
我只需要在子类别中创建一组id为0的行(每个类别一行),并将其名称设置为空。然后可以通过一个简单的连接来完成,而不必担心性能。这也可以在类别上使用触发器,因此每个类别的子类别始终为0
通过这两项更改,查询变得简单得多,大致如下:
select b.isbn, b.title, b.author_list, c.name, sc.name, b.price
from Book b, Category c, SubCategory sc
where b.category_id = c.category_id
and b.category_id = sc.category_id
and b.subcategory_id = sc.subcategory_id
order by ...
这个查询应该很快就会出现,因为它只使用关系代数的基本级别(即,没有每行函数(包括case语句),没有子查询)。这是一个“老派”的查询,通过使用显式连接而不是隐式连接,您可能会获得更高的性能
最后一点:一个正确的3NF模式不会在authors表中包含ISBN——更好的选择是使用一个单独的BookAuthor表来保存ISBN和author_id,从而正确地建模多对多关系。但是为了性能,您可能已经修改了aleready(我不知道)。请参阅@Pax的答案,了解处理sub_category_id的空/零值的更好方法
select isbn, a.name as author_name, c.name as category_name, sc.name as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id != 0
union
select isbn, a.name as author_name, c.name as category_name, '' as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id = 0
请参阅@Pax的答案,了解处理sub_category_id的空/零值的更好方法
select isbn, a.name as author_name, c.name as category_name, sc.name as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id != 0
union
select isbn, a.name as author_name, c.name as category_name, '' as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id = 0
嗯,子类别业务是糟糕的数据库设计。即使您假设一本书只能属于一个类别,这也是一个糟糕的设计,因为(在这种情况下),一个类别总是可以派生自子类别,因此您通过让书同时具有这两个类别的属性引入了冗余 对于所需的查询,这只是执行联接和投影select语句的问题。如果您不知道足够的SQL来实现这一点,您可能不应该尝试编写