一.自关联基础
使用表别名的主要原因之一是能在单条SELECT语句中不止一次引用相同的表。下面举一个例子。
假如你发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。
下面是解决此问题的一种方法:
这是第一种解决方案,它使用了子查询。内部的SELECT语句做了一个简单的检索,返回生产ID为DTNTR的物品供应商的vend_id。该ID用于外部查询的WHERE子句中,以便检索出这个供应商生产的所有物品
现在来看使用联结的相同查询:
此查询中需要的两个表实际上是相同的表,因此products表在FROM子句中出现了两次。虽然这是完全合法的,但对products的引用具有二义性,因为MySQL不知道你引用的是products表中的哪个
为解决此问题,使用了表别名。products的第一次出现为别名p1,第二次出现为别名p2。现在可以将这些别名用作表名。例如,SELECT语句使用p1前缀明确地给出所需列的全名。如果不这样,MySQL将返回错误,因为分别存在两个名为prod_id、prod_name的列。MySQL不知道想要的是哪一个列(即使它们事实上是同一个列)。WHERE(通过匹配p1中的vend_id和p2中的vend_id)首先联结两个表,然后按第二个表中的prod_id过滤数据,返回所需的数据。
最终两个查找结果相同,如下
二、省市区数据库创建
from django.db import models
class Area(models.Model):
name=models.CharField(max_length=20,verbose_name=‘名称’)
parent=models.ForeignKey(‘self’,on_delete=models.SET_NULL,related_name=‘subs’,null=True,blank=True,verbose_name=‘上级行政区’)
class Meta:
db_table = ‘tb_areas’
verbose_name=‘省市区’
verbose_name_plural=‘省市区’
迁移后结果如下
分析
问题 1:ForeignKey
的作用,为什么 parent
变成了 parent_id
?
1. ForeignKey
的作用
在 Django 中,ForeignKey
是用来创建 表与表之间的关系 的。在 自关联 的情况下,它让表 关联自己,用于表示 层级关系(比如 省 → 市 → 区)。
示例:
class Area(models.Model):
name = models.CharField(max_length=20, verbose_name="名称")
parent = models.ForeignKey( # 外键指向自己,实现自关联
'self',
...
)
2. 为什么 parent
变成了 parent_id
?
👉 原因:Django 规定,外键字段在数据库里会存储 “关联对象的主键值”,所以 Django 默认给外键字段加上 _id
后缀。
🔹 你写的是:
parent = models.ForeignKey('self', ...)
🔹 Django 在数据库里创建的实际字段是:
parent_id INT # 代表 parent 这个字段存储的是 id
示例数据:
id | name | parent_id |
---|---|---|
130000 | 河北省 | NULL |
130100 | 石家庄 | 130000 |
130200 | 唐山市 | 130000 |
这里的 parent_id=130000
就是因为 parent
存储的是上级地区的 id
。
3.谁是主键
id
是 主键(Primary Key, PK),它是表的唯一标识,每条记录都有一个唯一的 id
。
parent_id
是 外键(Foreign Key, FK),它存储的是 这个记录的上级 id
,但 parent_id
本身不是主键。
问题 2:怎么通过省查询它的管辖市?
如何查询某个省的所有市?
SELECT * FROM areas WHERE parent_id = 130000;
如果 parent_id=130000
,说明 这些都是河北省的下级城市。
在 Django 里,你可以直接这样查:
hebei = Area.objects.get(id=130000) # 找到河北省
cities = hebei.subs.all() # 通过 related_name 查询下属城市
for city in cities:
print(city.name)
问题三:
什么是反向查询和正向查询
正向查询**:通过 主键(自身的) 查询 外键指向的值(上级)。
反向查询**:通过 外键(在别人表中的) 查询 所有关联的主键(下级)。
1. 正向查询(从 “子” 查 “父”)
通过主键查外键的值(从市找到省)
shijiazhuang = Area.objects.get(id=130100) # 获取石家庄市
province = shijiazhuang.parent # 查询它的上级省份
print(province.name) # 输出:河北省
2. 反向查询(从 “父” 查 “子”)
通过外键查主键的值(从省找到所有市)
hebei = Area.objects.get(id=130000) # 获取河北省
cities = hebei.subs.all() # 通过 related_name 查询下属所有城市
for city in cities:
print(city.name)
sql和django分别查询省市区结果
MySQL 查询省、市、区层级关系
1. 查询所有省份(没有上级的地区)
SELECT * FROM areas WHERE parent_id IS NULL;
2. 查询某个省的所有市(假设河北省 id=130000
)
SELECT * FROM areas WHERE parent_id = 130000;
3. 查询某个市的所有区(假设石家庄市 id=130100
)
SELECT * FROM areas WHERE parent_id = 130100;
**Django ORM 查询省、市、区
发挥作用的是subs
related_name='subs'
的作用
- 默认情况下,Django 反向查询的名字是
模型名小写 + _set
即area_set,但related_name
让你用subs
代替这个难记的默认名,可以自定义名字。 - 方便查询:可以从 “上级” 查询所有 “下级”,比如 省找市、市找区。
from myapp.models import Areas # 导入模型
1. 查询所有省份
provinces = Area.objects.filter(parent__isnull=True)
2. 查询某个省的所有市(假设河北省 id=130000
)
hebei = Area.objects.get(id=130000) # 获取河北省对象
cities = hebei.subs.all() # 通过 related_name 查询下属城市
3. 查询某个市的所有区(假设石家庄市 id=130100
)
shijiazhuang = Area.objects.get(id=130100) # 获取石家庄市对象
districts = shijiazhuang.subs.all() # 查询该市下属区县
hebei.subs.all() # 通过 related_name 查询下属城市
------
#### **3. 查询某个市的所有区(假设石家庄市 `id=130100`)**
```python
shijiazhuang = Area.objects.get(id=130100) # 获取石家庄市对象
districts = shijiazhuang.subs.all() # 查询该市下属区县