首页 > 数据库 >[SQLAlchemy] sqlAlchemy学习笔记(2): 在orm中使用select

[SQLAlchemy] sqlAlchemy学习笔记(2): 在orm中使用select

时间:2024-01-23 11:15:07浏览次数:26  
标签:account SQLAlchemy name sqlAlchemy user orm id select User

SELECT的作用

select在sql中的作用是选中特定列并以表的形式返回, 是必要的关键字; 在sqlalchemy中, select()方法会返回一个Select对象, 并根据这个对象引入其他方法, 如where(), join(), order_by()等等

from sqlalchemy import select
stmt = select(User).where(User.name == "spongebob")

SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
WHERE user_account.name = "spongebob";

注意select()里的参数是orm中映射数据表的类 -> i.e.User类对应user_account表

使用scalars()格式化返回结果

首先来看一看这条

result = session.execute(select(User).order_by(User.id))

如果我们执行上面的语句, execute方法实际上会返回一个含有Row对象的数组(Result对象), 每个Row对象里只有一个元素, 那就是一个User对象
result.all()
返回结果为

[(User(id=1, name='spongebob', fullname='Spongebob Squarepants'),),
(User(id=2, name='sandy', fullname='Sandy Cheeks'),),
(User(id=3, name='patrick', fullname='Patrick Star'),),
(User(id=4, name='squidward', fullname='Squidward Tentacles'),),
(User(id=5, name='ehkrabs', fullname='Eugene H. Krabs'),)]

这时候我们需要scalars方法去掉Row, 这有两种方式, 但她们都使用了同一种方法(名)

  • Session.scalars()
session.scalars(select(User).order_by(User.id)).all()
  • Result.scalars()
    记住Session.execute返回了一个Result对象, 而它的主体类里则定义了一个scalars方法
result = session.execute(select(User).order_by(User.id))
result.scalars().all()

选中复数orm对象

stmt = select(User, Address).join(User.addresses).order_by(User.id, Address.id)
for row in session.execute(stmt):
    print(f"{row.User.name} {row.Address.email_address}")

SELECT user_account.id, user_account.name, user_account.fullname, address.id AS id_1, address.user_id, address.email_address
FROM user_account
JOIN address ON user_account.id = address.user_id
ORDER BY user_account.id, address.id;

选中特定列

stmt = select(User.name, Address.email_address).join(User.addresses).order_by(User.id, Address.id)
for row in session.execute(stmt):
	print(f"{row.name}  {row.email_address}")

SELECT user_account.name, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
ORDER BY user_account.id, address.id;

使用Bundle进行分组

当我们试图选中列时, 需要使用类名来进行区分, 这是必须的->但是如果被选中的列很多, 像上一种写法必然是繁琐的, 我们可以使用Bundle类来区分它们, 注意使用Bundle类的结果和单纯使用select是一样的, 只是增加了代码的可读性

from sqlalchemy.orm import Bundle
# 使用Bundle将来自不同类的属性区分开
stmt = select(
    Bundle("user", User.name, User.fullname),
    Bundle("email", Address.email_address),
).join_from(User, Address)
# 注意这里引用的路径也不一样了
for row in session.execute(stmt):
    print(f"{row.user.name} {row.user.fullname} {row.email.email_address}")

使用自定义别名

在写sql语句的时候, 经常需要使用别名来简写表名或是区别相同表, 在sqlalchemy中也有同样的用法

from sqlalchemy.orm import aliased
u1 = aliased(User, name="u1")
stmt = select(u1).order_by(u1.id)
row = session.execute(stmt).first()
print(f"{row.u1.name}")

子查询

有时候sql语句可以很复杂, 经常在查询里加查询,在sqlalchemy中我们需要用到subquery方法

# 内查询语句
inner_stmt = select(User).where(User.id < 7).order_by(User.id)
# 拿subquery封装一下
subq = inner_stmt.subquery()
# 给结果加个别名, 绑定一下对应类(表)
aliased_user = aliased(User, subq)
# 外部的sql查询
stmt = select(aliased_user)
# 执行, 打印结果
for user_obj in session.execute(stmt).scalars():
    print(user_obj)

sql查询语句长这样

SELECT anon_1.id, anon_1.name, anon_1.fullname
FROM 
	(SELECT user_account.id AS id, 
		user_account.name AS name, 
		user_account.fullname AS fullname
	 FROM user_account
	 WHERE user_account.id < ? 
	 ORDER BY user_account.id) 
AS anon_1;

注意因为没有指定别名, 因此别名anon_1是系统自动给的

实现UNION

UNION也是sql中一个常见的关键字(虽然我不喜欢用)

from sqlalchemy import union_all
# sql查询命令的文本, 其实是一个内查询的语句 --> 集合两张结果表, 并将结果以id排序
u = union_all(
    select(User).where(User.id < 2), select(User).where(User.id == 3)
).order_by(User.id)
# 将sql文本(内查询语句)加进最终指令stmt中
stmt = select(User).from_statement(u)
# 执行并打印
for user_obj in session.execute(stmt).scalars():
    print(user_obj)

注意这个方法没有用到任何子查询⬇️直来直去的

SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
WHERE user_account.id < ? 
UNION ALL 
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
WHERE user_account.id = ? 
ORDER BY id;

另一种方法, 使用subquery

subq = union_all(
    select(User).where(User.id < 2), select(User).where(User.id == 3)
).subquery()
user_alias = aliased(User, subq)
stmt = select(user_alias).order_by(user_alias.id)
for user_obj in session.execute(stmt).scalars():
    print(user_obj)

对应的sql是这样⬇️很难懂但很有观赏性

SELECT anon_1.id, anon_1.name, anon_1.fullname FROM 
	(SELECT 
		user_account.id AS id,
		user_account.name AS name,
		user_account.fullname AS fullname
	 FROM user_account
	 WHERE user_account.id < ? 
	 UNION ALL 
	 SELECT 
	 	user_account.id AS id, 
		user_account.name AS name, 
		user_account.fullname AS fullname
	 FROM user_account
	 WHERE user_account.id = ?) AS anon_1 
ORDER BY anon_1.id;

标签:account,SQLAlchemy,name,sqlAlchemy,user,orm,id,select,User
From: https://www.cnblogs.com/Akira300000/p/17980587

相关文章

  • Winform中设置程序开机自启动(修改注册表和配置自启动快捷方式)
    场景winform程序需要在启动时自启动,可通过将exe快捷方式添加到自启动目录下,或者通过修改注册表添加启动项的方式。注:博客:https://blog.csdn.net/badao_liumang_qizhi实现使用添加快捷方式到启动目录的方式Windows下怎样使用bat设置Redis和Nginx开机自启动:https://blog.csd......
  • DevExpress WinForms导航控件 - 交付更时尚、体验更好的业务应用(二)
    DevExpressWinForms的SideNavigation(侧边导航)和NavPanel(导航面板)可以帮助客户交付完全可模仿UI体验的业务解决方案,这些体验在当今流行的应用程序中都可找到。在上文中(点击这里回顾>>),我们为大家介绍了DevExpressWinForms导航控件中的折叠组件、导航栏组件等。接下来我们将继续......
  • http的form表单格式请求
    Content-Type:application/x-www-form-urlencoded是一个HTTP头部中使用的媒体类型(MIMEtype),它告诉服务器消息体的格式以键值对形式进行编码,并且键值对之间用&分隔,每个键和值都用=连接。这是表单数据被编码成一个查询字符串的方式,通常用于提交HTML表单数据。当你提交一个简......
  • 用BEVformer来卷自动驾驶-2
    回顾上一期:用BEVformer来卷自动驾驶-1(qq.com)       上一期我们讲到了从3D到4D(加了时间概念)以后使得BEV能变得更厉害,具体这种厉害其实是可以解决纯视觉解决方案里面最难解决的问题,就是基于恶劣天气,或者拍的不清楚的时候,或者突然有遮挡的时候,融入时间的概念,可以很大一......
  • Transformer的应用
    Transformer写在前面本学期学习了NLP的课程,本小菜鸡结合做的课设(基于Transformer的英文文档摘要系统的设计与实现),来写一下有关于Transformer的相关内容吧,有问题之处还请各位大佬批评指正系统的背景抽象文本摘要是自然语言处理中最具挑战性的任务之一,涉及理解长段落、信息压缩......
  • [SQLAlchemy] SQLAlchemy学习笔记: 基础使用
    InstallationpipinstallSQLAlchemymakesurethatissql-alchemy2创建引擎数据库url格式一般为dialect+driver://username:password@host:port/database#PyMySQL-python里的数据库驱动engine=create_engine("mysql+pymysql://scott:tiger@localhost/foo?charset=utf......
  • 数据前置参数类型转换@InitBinder、Formatter<?>、Converter<?>的使用
    前言:在很多时候我们在进行调用接口的时候,传入的参数类型不是指定的特别明确(或者是不能进行自动类型转换),会导致调用接口失败的情况出现,如果我们在调用接口之前进行数据格式化,手动进行数据类型转换,那么就不会出现调用接口失败的情况出现了。这些注解无非也就是做这些工作的。下面列举......
  • 无涯教程-MATLAB - 变换(Transforms)
    MATLAB提供了用于处理变换的命令,例如Laplace和Fourier变换,转换在科学和工程中用作简化分析并从另一个角度查看数据的工具。例如,傅立叶变换允许我们将表示为时间函数的信号转换为频率函数,拉普拉斯变换使我们能够将微分方程转换为代数方程。MATLAB提供了laplace,傅立叶和fft命......
  • CF1679E Typical Party in Dorm
    TypicalPartyinDormLuoguCF1679E题面描述给定一个长度为\(n(n\le1000)\),仅由前\(17\)个英文小写字母和问号组成的字符串\(s\)。多次询问,每次给出一个由前\(17\)个英文小写字母组成的字符集\(A\),你可以将\(s\)中的问号任意替换成\(A\)中的字母,求你能得到多少......
  • 题解 [ABC242D] ABC Transform
    【洛谷博客】很巧妙的一道题。题意给定一个字符串\(S\),只包含字符A,B,C。每过一个时刻,字符会发生变化:A\(\to\)BC,B\(\to\)CA,C\(\to\)AB。设\(0\)时刻为\(S_0=S\)。进行\(Q\)次询问,每次询问时刻\(t\)时,字符串\(S_t\)中第\(k\)个字符。分析为了方便处理,我这里将所......