返回

Django 如何使用 Exists

发布时间:2023-01-01 11:42:32 241
# python# django# 数据库# sql# 数据

Django ORM 模型

class Base(models.Model):
    set_null = {
        'null': True,
        'blank': True
    }

    set_fk = {
        'db_constraint': False,
        'on_delete': models.SET_NULL
    }
    set_mtm = {
        'db_constraint': False,
    }

    class Meta:
        abstract = True


class Student(Base):
    name = models.CharField(max_length=10, **Base.set_null)
    age = models.IntegerField(**Base.set_null)
    classes = models.ManyToManyField('Class', related_name='student_class', **Base.set_mtm)

    class Meta:
        db_name = 'student'


class Class(Base):
    name = models.CharField(max_length=10, **Base.set_null)

    class Meta:
        db_name = 'classes'
        
 class Middle(Base):
    category = models.CharField(max_length=10, **Base.set_null)
    name = models.CharField(max_length=10, **Base.set_null)
    value = models.CharField(max_length=10, **Base.set_null)

    class Meta:
        db_table = 'tb_middle'


class A(Base):
    model = models.ForeignKey(
        'Middle', related_name='a_model', **Base.set_fk, **Base.set_null
    )

    class Meta:
        db_table = 'tb_a'


sql 中 where 使用

SELECT name FROM student WHERE age > 18;

在执行这条 SQL 语句的时候,DBMS 会扫描 student 表中的每一条记录,然后把符合 age 大于 18 这个条件的所有记录筛选出来,并放到结果集里面去。也就是说 WHERE 关键字的作用就是判断后面的逻辑表达式的值是否为 True。如果为 True,则将当前这条记录(经过 SELECT 关键字处理后)放到结果集里面去,如果逻辑表达式的值为 False 则不放。

sql 中的 exists

有个哥们讲的很适合初学者

概念:EXISTS 运算符用于判断查询子句是否有记录,如果有一条或多条记录存在返回 True,否则返回 False。

执行流程:先执行子查询,得到一个集合(或值),然后将这个集合(或值)作为一个常量带入到父查询的 WHERE 子句中去。

案例

查询选择课程是语文课程的所有学生名称

SELECT
	"app1_student"."name" 
FROM
	"app1_student" 
WHERE
	EXISTS (
	SELECT
		U0."id",
		U0."name" 
	FROM
		"app1_class" U0
		INNER JOIN "app1_student_classes" U1 ON ( U0."id" = U1."class_id" ) 
	WHERE
	( U0."name" = 语文 AND U1."student_id" = "app1_student"."id" ) 
	)

django 中 exists

官方文档

官方描述:Exists 是一个 Subquery 子类,它使用 SQL EXISTS 语句。在许多情况下,它的性能比子查询更好,因为当找到第一条匹配的记录时,数据库能够停止对子查询的执行。

案例一

上面的案例 Django 中可以这样写

# 方法一 原生sql 见上
queryset = Student.objects.filter(Exists(Class.objects.filter(student_class=OuterRef('pk'), name='语文'))).values('name')
# 方法二
queryset = Student.objects.filter(classes__name='语文').values('name')

方法二 sql

SELECT
	"app1_student"."name" 
FROM
	"app1_student"
	INNER JOIN "app1_student_classes" ON ( "app1_student"."id" = "app1_student_classes"."student_id" )
	INNER JOIN "app1_class" ON ( "app1_student_classes"."class_id" = "app1_class"."id" ) 
WHERE
	"app1_class"."name" = 语文

根据真实情况选择不同查询方式。遵循尽可能使用一次数据库交互数据数据。

案例二

获取 tb_middle 中 category 为 a_model 且排除已经和tb_a 表存在关联的表 tb_middle 字段 name value的数据

思路

  • 查询表 tb_middle 已经被使用的数据
  • filter中过滤掉被使用的数据

达到了效果,却需要查询两次数据库。而且,在书写python比较繁琐

Middle.objects.filter(category=category).filter(
                ~Exists(A.objects.filter(model=OuterRef('pk')))
            )
# Exists 存在 | ~Exists 不存在

下次更新 annotate subquery 使用方法...

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线