拥抱SQLAlchemy 之二 拉拉手,我请你去看电影~
所有按照我Pao妞的程序,上次是一见钟情,那么这次一定是要约她看电影的,坐在情侣包,你挨着我,我爱着你,可以好好的了解了解,拉近感情了,哈哈,这又让我想起了初恋,都说初恋无限美,正所谓“举头望明月,低头思故乡”,好诗呀~~
今天看的电影名字叫《SQL Expression Language》,绝对引进大片,首映哦~
这次,我主要是要了解一下SQLAlchemy构建SQL的一些细节,如果你没有看到我们一见钟情的那篇,那要继续下面的练习前一定要先确认你已经正确的安装了相关库,具体安装,还是去看第一篇吧~~ :P
检查一下你的版本,我的是SQLAlchemy 0.5.5的,用下面代码检查:
>>> import sqlalchemy
>>> sqlalchemy.__version__
0.5.0
所有的练习都是用内存SQLite数据库,建立一个连接先!
>>> from sqlalchemy import create_engine
>>> engine = create_engine(’sqlite:///:memory:’, echo=True)
构建练习需要用到的表模式,一定要建哦,否则无法继续练习~
>>> from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
>>> metadata = MetaData()
>>> users = Table(’users’, metadata,
... Column(’id’, Integer, primary_key=True),
... Column(’name’, String),
... Column(’fullname’, String),
... )
>>> addresses = Table(’addresses’, metadata,
... Column(’id’, Integer, primary_key=True),
... Column(’user_id’, None, ForeignKey(’users.id’)),
... Column(’email_address’, String, nullable=False)
... )
用create_all方法创建数据库中的真实表
>>> metadata.create_all(engine)
PRAGMA table_info("users")
{}
PRAGMA table_info("addresses")
{}
CREATE TABLE users (
id INTEGER NOT NULL,
name VARCHAR,
fullname VARCHAR,
PRIMARY KEY (id)
)
{}
COMMIT
CREATE TABLE addresses (
id INTEGER NOT NULL,
user_id INTEGER,
email_address VARCHAR NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(user_id) REFERENCES users (id)
)
{}
COMMIT
给users表中插入记录
>>> ins = users.insert()
让我们看看上面那句产生了什么样的SQL语句
>>> str(ins)
’INSERT INTO users (id, name, fullname) VALUES (:id, :name, :fullname)’
可以使用values来给插入的记录字段赋值
>>> ins = users.insert().values(name=’jack’, fullname=’Jack Jones’)
>>> str(ins)
’INSERT INTO users (name, fullname) VALUES (:name, :fullname)’
这样产生的SQL里并没有体现我们传递的字段值,字段到哪里了?原来字段值存储在了内建的结构中。
可以这样看刚才传入的字段值
>>> ins.compile().params
{’fullname’: ’Jack Jones’, ’name’: ’jack’}
下面看看如何执行语句,先获得一个数据库链接
>>> conn = engine.connect()
>>> conn
<sqlalchemy.engine.base.Connection object at 0x...>
然后通过连接执行刚才的查询语句,因为不是事务,执行完就提交了
>>> result = conn.execute(ins)
INSERT INTO users (name, fullname) VALUES (?, ?)
[’jack’, ’Jack Jones’]
COMMIT
也可以手动的绑定数据库链接,并查看绑定后生成的SQL语句有什么不同
>>> ins.bind = engine
>>> str(ins)
’INSERT INTO users (name, fullname) VALUES (?, ?)’
当调用了execute()后,就可以访问result变量了,执行结果就在这里面,聪明的SQLAlchemy有自己一套获得主键ID的办法,并且针对不同数据库。
>>> result.last_inserted_ids()
[1]
也可以这样执行插入语句
>>> ins = users.insert()
>>> conn.execute(ins, id=2, name=’wendy’, fullname=’Wendy Williams’)
INSERT INTO users (id, name, fullname) VALUES (?, ?, ?)
[2, ’wendy’, ’Wendy Williams’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
现在让我要一次添加多个EMAIL地址到addresses表,SQLite自动为新纪录产生了主键
>>> conn.execute(addresses.insert(), [
... {’user_id’: 1, ’email_address’ : ’jack@yahoo.com’},
... {’user_id’: 1, ’email_address’ : ’jack@msn.com’},
... {’user_id’: 2, ’email_address’ : ’www@www.org’},
... {’user_id’: 2, ’email_address’ : ’wendy@aol.com’},
... ])
INSERT INTO addresses (user_id, email_address) VALUES (?, ?)
[[1, ’jack@yahoo.com’], [1, ’jack@msn.com’], [2, ’www@www.org’], [2, ’wendy@aol.com’]]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
使用数据库链接直接执行插入,不用手动OPEN和CLOSE
>>> result = engine.execute(users.insert(), name=’fred’, fullname="Fred Flintstone")
INSERT INTO users (name, fullname) VALUES (?, ?)
[’fred’, ’Fred Flintstone’]
COMMIT
如果当前的metadata和engine还绑定的话(别忘记了,一开始我们就用create_all创建表格的时候做过绑定,别紧张,没绑定的话,现在绑定也来得及),就可以这样执行了,这种执行方式被称为含蓄的执行。
>>> metadata.bind = engine #绑定
>>> result = users.insert().execute(name="mary", fullname="Mary Contrary")
INSERT INTO users (name, fullname) VALUES (?, ?)
[’mary’, ’Mary Contrary’]
COMMIT
解除绑定可以这样做
>>> metadata.bind = None
用一个很简单的语句就可以选择users表中的所有纪录
>>> from sqlalchemy.sql import select
>>> s = select([users])
>>> result = conn.execute(s)
SELECT users.id, users.name, users.fullname
FROM users
[]
结果被返回到result变量中,可以这样读取结果
>>> from sqlalchemy.sql import select
>>> s = select([users])
>>> result = conn.execute(s)
SELECT users.id, users.name, users.fullname
FROM users
[]
我个人感觉这样访问结果集的每一行更舒服些^_^
>>> result = conn.execute(s)
SELECT users.id, users.name, users.fullname
FROM users
[]>>> row = result.fetchone()
>>> print "name:", row[’name’], "; fullname:", row[’fullname’]
name: jack ; fullname: Jack Jones
对于列来说,用整数索引来访问也是可以的
>>> row = result.fetchone()
>>> print "name:", row[1], "; fullname:", row[2]
name: wendy ; fullname: Wendy Williams
你要是很喜欢整合语句,也可以这样搞~
>>> for row in conn.execute(s):
... print "name:", row[users.c.name], "; fullname:", row[users.c.fullname]
SELECT users.id, users.name, users.fullname
FROM users
[]name: jack ; fullname: Jack Jones
name: wendy ; fullname: Wendy Williams
name: fred ; fullname: Fred Flintstone
name: mary ; fullname: Mary Contrary
用完了,别忘记关门哦~
>>> result.close()
如果在选择纪录的时候希望指定输出的列,可以使用表对象的c属性
>>> s = select([users.c.name, users.c.fullname])
>>> result = conn.execute(s)
SELECT users.name, users.fullname
FROM users
[]>>> for row in result:
... print row
(u’jack’, u’Jack Jones’)
(u’wendy’, u’Wendy Williams’)
(u’fred’, u’Fred Flintstone’)
(u’mary’, u’Mary Contrary’)
从多个表里选择纪录,可以这么写,因为没有WHERE,结果看上去很混乱,用户和邮件地址之间对应关系不正确
>>> for row in conn.execute(select([users, addresses])):
... print row
SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users, addresses
[](1, u’jack’, u’Jack Jones’, 1, 1, u’jack@yahoo.com’)
(1, u’jack’, u’Jack Jones’, 2, 1, u’jack@msn.com’)
(1, u’jack’, u’Jack Jones’, 3, 2, u’www@www.org’)
(1, u’jack’, u’Jack Jones’, 4, 2, u’wendy@aol.com’)
(2, u’wendy’, u’Wendy Williams’, 1, 1, u’jack@yahoo.com’)
(2, u’wendy’, u’Wendy Williams’, 2, 1, u’jack@msn.com’)
(2, u’wendy’, u’Wendy Williams’, 3, 2, u’www@www.org’)
(2, u’wendy’, u’Wendy Williams’, 4, 2, u’wendy@aol.com’)
(3, u’fred’, u’Fred Flintstone’, 1, 1, u’jack@yahoo.com’)
(3, u’fred’, u’Fred Flintstone’, 2, 1, u’jack@msn.com’)
(3, u’fred’, u’Fred Flintstone’, 3, 2, u’www@www.org’)
(3, u’fred’, u’Fred Flintstone’, 4, 2, u’wendy@aol.com’)
(4, u’mary’, u’Mary Contrary’, 1, 1, u’jack@yahoo.com’)
(4, u’mary’, u’Mary Contrary’, 2, 1, u’jack@msn.com’)
(4, u’mary’, u’Mary Contrary’, 3, 2, u’www@www.org’)
(4, u’mary’, u’Mary Contrary’, 4, 2, u’wendy@aol.com’)
为了使用户和自己的邮箱能对应起来,可以这么写
>>> s = select([users, addresses], users.c.id==addresses.c.user_id)
>>> for row in conn.execute(s):
... print row
SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users, addresses
WHERE users.id = addresses.user_id
[](1, u’jack’, u’Jack Jones’, 1, 1, u’jack@yahoo.com’)
(1, u’jack’, u’Jack Jones’, 2, 1, u’jack@msn.com’)
(2, u’wendy’, u’Wendy Williams’, 3, 2, u’www@www.org’)
(2, u’wendy’, u’Wendy Williams’, 4, 2, u’wendy@aol.com’)
上面的where表达式这样执行一下,会发现生成了一个表达式对象
>>> users.c.id==addresses.c.user_id
<sqlalchemy.sql.expression._BinaryExpression object at 0x...>
用str看一下这个表达式,惊奇的是,返回的不是TRUE或FALSE,而是一个字符串语句,想想也是能想通的,这个语句是给SQL的where使用的。
>>> str(users.c.id==addresses.c.user_id)
’users.id = addresses.user_id’
这样查看表达式也行
>>> print users.c.id==addresses.c.user_id
users.id = addresses.user_id
下面的表达式赋值了7,但生成的语句中却是被映射到了一个绑定参数中
>>> print users.c.id==7
users.id = :id_1
要查看绑定的参数,要这样做
>>> (users.c.id==7).compile().params
{u’id_1’: 7}
会了等于,当然也就明白了不等于
>>> print users.c.id != 7
users.id != :id_1
下面自动把None转换为NULL
>>> print users.c.name == None
users.name IS NULL
虽然你前后颠倒,但是SQLAlchemy可不会,顺序它帮你顺过来,是不是越来越觉得SQLAlchemy很贤惠了?偷着乐吧~
>>> print ’fred’ > users.c.name
users.name < :name_1
如果要联合两个字段是integer类型,如下
>>> print users.c.id + addresses.c.id
users.id + addresses.id
更有趣的是,如果两个列类型为String,用+就会产生这样的效果
>>> print users.c.name + users.c.fullname
users.name || users.fullname
上面的||是字符串连接符,但并不都是这么写,在MySQL里会有其他的写法,如下:
>>> print (users.c.name + users.c.fullname).compile(bind=create_engine(’mysql://’))
concat(users.name, users.fullname)
可爱的SQLAlchemy是很智慧的,可以根据不同的数据库特征来进行翻译
下面这句咱没弄明白,咱也不在这里胡说~~嘿嘿
>>> print users.c.name.op(’tiddlywinks’)(’foo’)
users.name tiddlywinks :name_1
要是用逻辑连接符,也是有办法滴
>>> from sqlalchemy.sql import and_, or_, not_
>>> print and_(users.c.name.like(’j%’), users.c.id==addresses.c.user_id,
... or_(addresses.c.email_address==’wendy@aol.com’, addresses.c.email_address==’jack@yahoo.com’),
... not_(users.c.id>5))
users.name LIKE :name_1 AND users.id = addresses.user_id AND
(addresses.email_address = :email_address_1 OR addresses.email_address = :email_address_2)
AND users.id <= :id_1
你要是喜欢这么写逻辑连接符,SALAlchemy也没有意见
>>> print users.c.name.like(’j%’) & (users.c.id==addresses.c.user_id) & \
... ((addresses.c.email_address==’wendy@aol.com’) | (addresses.c.email_address==’jack@yahoo.com’)) \
... & ~(users.c.id>5)
users.name LIKE :name_1 AND users.id = addresses.user_id AND
(addresses.email_address = :email_address_1 OR addresses.email_address = :email_address_2)
AND users.id <= :id_1
下面让我们生成BETWEEN和AS语句
>>> s = select([(users.c.fullname + ", " + addresses.c.email_address).label(’title’)],
... and_(
... users.c.id==addresses.c.user_id,
... users.c.name.between(’m’, ’z’),
... or_(
... addresses.c.email_address.like(’%@aol.com’),
... addresses.c.email_address.like(’%@msn.com’)
... )
... )
... )
>>> print conn.execute(s).fetchall()
SELECT users.fullname || ? || addresses.email_address AS title
FROM users, addresses
WHERE users.id = addresses.user_id AND users.name BETWEEN ? AND ? AND
(addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
[’, ’, ’m’, ’z’, ’%@aol.com’, ’%@msn.com’]
[(u’Wendy Williams, wendy@aol.com’,)]
写到这里原文说SQLAlchemy还可以支持ORDER BY,GROPY BY和HAVING,忧郁篇幅的原因,这里就不一一列举了,既然原文都不列举了,我也就不列举了,哈哈
通过text()来构建SQL语句,其中的变量必须是冒号加变量名,我想尽量不使用这种语法,我感觉写SQL实在是太痛苦了。
>>> from sqlalchemy.sql import text
>>> s = text("""SELECT users.fullname || ’, ’ || addresses.email_address AS title
... FROM users, addresses
... WHERE users.id = addresses.user_id AND users.name BETWEEN :x AND :y AND
... (addresses.email_address LIKE :e1 OR addresses.email_address LIKE :e2)
... """)
>>> print conn.execute(s, x=’m’, y=’z’, e1=’%@aol.com’, e2=’%@msn.com’).fetchall()
SELECT users.fullname || ’, ’ || addresses.email_address AS title
FROM users, addresses
WHERE users.id = addresses.user_id AND users.name BETWEEN ? AND ? AND
(addresses.email_address LIKE ? OR addresses.email_address LIKE ?)
[’m’, ’z’, ’%@aol.com’, ’%@msn.com’][(u’Wendy Williams, wendy@aol.com’,)]
使用text()却又想在select中单独列出from的表,可以使用from_obj参数来指定
>>> s = select([text("users.fullname || ’, ’ || addresses.email_address AS title")],
... and_(
... "users.id = addresses.user_id",
... "users.name BETWEEN ’m’ AND ’z’",
... "(addresses.email_address LIKE :x OR addresses.email_address LIKE :y)"
... ),
... from_obj=[’users’, ’addresses’]
... )
>>> print conn.execute(s, x=’%@aol.com’, y=’%@msn.com’).fetchall()
SELECT users.fullname || ’, ’ || addresses.email_address AS title
FROM users, addresses
WHERE users.id = addresses.user_id AND users.name BETWEEN ’m’ AND ’z’ AND (addresses.email_add
[’%@aol.com’, ’%@msn.com’][(u’Wendy Williams, wendy@aol.com’,)]
使用alias()来创建表的别名完成如下查询
>>> a1 = addresses.alias(’a1’)
>>> a2 = addresses.alias(’a2’)
>>> s = select([users], and_(
... users.c.id==a1.c.user_id,
... users.c.id==a2.c.user_id,
... a1.c.email_address==’jack@msn.com’,
... a2.c.email_address==’jack@yahoo.com’
... ))
>>> print conn.execute(s).fetchall()
SELECT users.id, users.name, users.fullname
FROM users, addresses AS a1, addresses AS a2
WHERE users.id = a1.user_id AND users.id = a2.user_id AND a1.email_address = ? AND a2.email_address = ?
[’jack@msn.com’, ’jack@yahoo.com’][(1, u’jack’, u’Jack Jones’)]
alias()也可以这样写,匿名别名,每次生成的别名都一样,这对于在oracle这种编译执行的数据库中,根据每次不同的SQL字符串编译的情况非常有用,编译次数少有利于性能提升吧~~~
>>> a1 = addresses.alias()
>>> a2 = addresses.alias()
>>> s = select([users], and_(
... users.c.id==a1.c.user_id,
... users.c.id==a2.c.user_id,
... a1.c.email_address==’jack@msn.com’,
... a2.c.email_address==’jack@yahoo.com’
... ))
>>> print conn.execute(s).fetchall()
SELECT users.id, users.name, users.fullname
FROM users, addresses AS addresses_1, addresses AS addresses_2
WHERE users.id = addresses_1.user_id AND users.id = addresses_2.user_id AND addresses_1.email_address = ? AND addresses_2.email_address = ?
[’jack@msn.com’, ’jack@yahoo.com’][(1, u’jack’, u’Jack Jones’)]
这句留着以后研究,暂时没看明白…
>>> a1 = s.correlate(None).alias()
>>> s = select([users.c.name], users.c.id==a1.c.id)
>>> print conn.execute(s).fetchall()
SELECT users.name
FROM users, (SELECT users.id AS id, users.name AS name, users.fullname AS fullname
FROM users, addresses AS addresses_1, addresses AS addresses_2
WHERE users.id = addresses_1.user_id AND users.id = addresses_2.user_id AND addresses_1.email_address = ? AND addresses
WHERE users.id = anon_1.id
[’jack@msn.com’, ’jack@yahoo.com’][(u’jack’,)]
下面看看join()如何工作的
>>> print users.join(addresses)
users JOIN addresses ON users.id = addresses.user_id
智能再次体现出来,根据外键ON字句自动被加上了
当然,你也可以自己决定ON后面的表达式
>>> print users.join(addresses, addresses.c.email_address.like(users.c.name + ’%’))
users JOIN addresses ON addresses.email_address LIKE users.name || :name_1
也可以使用select()的from_obj参数来指定from字句,并应用join()
>>> s = select([users.c.fullname], from_obj=[
... users.join(addresses, addresses.c.email_address.like(users.c.name + ’%’))
... ])
>>> print conn.execute(s).fetchall()
SELECT users.fullname
FROM users JOIN addresses ON addresses.email_address LIKE users.name || ?
[’%’][(u’Jack Jones’,), (u’Jack Jones’,), (u’Wendy Williams’,)]
outerjoin()的用法和join()雷同了
>>> s = select([users.c.fullname], from_obj=[users.outerjoin(addresses)])
>>> print s
SELECT users.fullname
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
对于oracle的SQL来说,有一些特别需要处理的地方,下面的语义需要查看ORACLE相关资料
>>> from sqlalchemy.databases.oracle import OracleDialect
>>> print s.compile(dialect=OracleDialect(use_ansi=False))
SELECT users.fullname
FROM users, addresses
WHERE users.id = addresses.user_id(+)
下面开始说说select(),用它可以组合语句片段,构建select语句
>>> query = users.select()
>>> print query
SELECT users.id, users.name, users.fullname
FROM users
给刚才的查询增加一个查询条件
>>> query = query.where(users.c.name==’jack’)
再让他根据fullname字段排序
>>> query = query.order_by(users.c.fullname.desc())
我们查看一下看看哪些用户有MSN邮箱地址
>>> from sqlalchemy.sql import exists
>>> query = query.where(
... exists([addresses.c.id],
... and_(addresses.c.user_id==users.c.id, addresses.c.email_address.like(’%@msn.com’))
... ).correlate(users))
一点一点的添加语句,到这里生成的SQL语句已经很复杂了,这个要手写,很辛苦哩~
>>> query = query.column(addresses).select_from(users.outerjoin(addresses)).apply_labels()
>>> conn.execute(query).fetchall()
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, addresses.id AS addresses_id, addresses.user_id AS address
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
WHERE users.name = ? AND (EXISTS (SELECT addresses.id
FROM addresses
WHERE addresses.user_id = users.id AND addresses.email_address LIKE ?)) ORDER BY users.fullname DESC
[’jack’, ’%@msn.com’][(1, u’jack’, u’Jack Jones’, 1, 1, u’jack@yahoo.com’), (1, u’jack’, u’Jack Jones’, 2, 1, u’jack@msn.com’)]
继续丰富SQL语句
>>> a1 = addresses.alias()
>>> query = query.replace_selectable(addresses, a1)
>>> print query
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, addresses_1.id
FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = :name_1 AND (EXISTS (SELECT addresses_1.id
FROM addresses AS addresses_1
WHERE addresses_1.user_id = users.id AND addresses_1.email_address LIKE :email_address_1)) ORDER BY use
写了这么老半天,执行以下吧,乖乖,看来用ORM写SQL,优势是大大的!!
>>> for row in conn.execute(query):
... print "Name:", row[users.c.name], "; Email Address", row[a1.c.email_address]
SELECT users.id AS users_id, users.name AS users_name, users.fullname AS users_fullname, addresses_1.id AS addresses_1_id,
FROM users LEFT OUTER JOIN addresses AS addresses_1 ON users.id = addresses_1.user_id
WHERE users.name = ? AND (EXISTS (SELECT addresses_1.id
FROM addresses AS addresses_1
WHERE addresses_1.user_id = users.id AND addresses_1.email_address LIKE ?)) ORDER BY users.fullname DESC
[’jack’, ’%@msn.com’]Name: jack ; Email Address jack@yahoo.com
Name: jack ; Email Address jack@msn.com
使用bindparam()来绑定一个参数
>>> from sqlalchemy.sql import bindparam
>>> s = users.select(users.c.name==bindparam(’username’))
>>> conn.execute(s, username=’wendy’).fetchall()
SELECT users.id, users.name, users.fullname
FROM users
WHERE users.name = ?
[’wendy’][(2, u’wendy’, u’Wendy Williams’)]
使用bindparam()还可以指定参数类型和表达式
>>> s = users.select(users.c.name.like(bindparam(’username’, type_=String) + text("’%’")))
>>> conn.execute(s, username=’wendy’).fetchall()
SELECT users.id, users.name, users.fullname
FROM users
WHERE users.name LIKE ? || ’%’
[’wendy’][(2, u’wendy’, u’Wendy Williams’)]
同名的绑定参数可以多次出现,这样参数再输入的时候也省事些
>>> s = select([users, addresses],
... users.c.name.like(bindparam(’name’, type_=String) + text("’%’")) |
... addresses.c.email_address.like(bindparam(’name’, type_=String) + text("’@%’")),
... from_obj=[users.outerjoin(addresses)])
>>> conn.execute(s, name=’jack’).fetchall()
SELECT users.id, users.name, users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users LEFT OUTER JOIN addresses ON users.id = addresses.user_id
WHERE users.name LIKE ? || ’%’ OR addresses.email_address LIKE ? || ’@%’
[’jack’, ’jack’][(1, u’jack’, u’Jack Jones’, 1, 1, u’jack@yahoo.com’), (1, u’jack’, u’Jack Jones’, 2, 1, u’jack@msn.com’)]
看看如何使用函数
>>> from sqlalchemy.sql import func
>>> print func.now()
now()
>>> print func.concat(’x’, ’y’)
concat(:param_1, :param_2)
当前的时间戳
>>> print func.current_timestamp()
CURRENT_TIMESTAMP
使用scalar()返回函数结果
>>> print conn.execute(
... select([func.max(addresses.c.email_address, type_=String).label(’maxemail’)])
... ).scalar()
SELECT max(addresses.email_address) AS maxemail
FROM addresses
[]www@www.org
Oracle中可以定义函数,下面看看如何运行一个名为calculate()的函数
>>> from sqlalchemy.sql import column
>>> calculate = select([column(’q’), column(’z’), column(’r’)],
... from_obj=[func.calculate(bindparam(’x’), bindparam(’y’))])
>>> print select([users], users.c.id > calculate.c.z)
SELECT users.id, users.name, users.fullname
FROM users, (SELECT q, z, r
FROM calculate(:x, :y))
WHERE users.id > z
想使用不同的绑定参数两次,可以使用unique_params()
>>> s = select([users], users.c.id.between(
... calculate.alias(’c1’).unique_params(x=17, y=45).c.z,
... calculate.alias(’c2’).unique_params(x=5, y=12).c.z))
>>> print s
SELECT users.id, users.name, users.fullname
FROM users, (SELECT q, z, r
FROM calculate(:x_1, :y_1)) AS c1, (SELECT q, z, r
FROM calculate(:x_2, :y_2)) AS c2
WHERE users.id BETWEEN c1.z AND c2.z
>>> s.compile().params
{u’x_2’: 5, u’y_2’: 12, u’y_1’: 45, u’x_1’: 17}
>>> s.compile().params
{u’x_2’: 5, u’y_2’: 12, u’y_1’: 45, u’x_1’: 17}
联合两个记录集UNION和UNION ALL
>>> from sqlalchemy.sql import union
>>> u = union(
... addresses.select(addresses.c.email_address==’foo@bar.com’),
... addresses.select(addresses.c.email_address.like(’%@yahoo.com’)),
... ).order_by(addresses.c.email_address)
>>> print conn.execute(u).fetchall()
SELECT addresses.id, addresses.user_id, addresses.email_address
FROM addresses
WHERE addresses.email_address = ? UNION SELECT addresses.id, addresses.user_id, addresses.email_address
FROM addresses
WHERE addresses.email_address LIKE ? ORDER BY addresses.email_address
[’foo@bar.com’, ’%@yahoo.com’][(1, 1, u’jack@yahoo.com’)]
注意,不是所有的数据库都支持intersect(), intersect_all(), except_()和except_all()的
>>> from sqlalchemy.sql import except_
>>> u = except_(
... addresses.select(addresses.c.email_address.like(’%@%.com’)),
... addresses.select(addresses.c.email_address.like(’%@msn.com’))
... )
>>> print conn.execute(u).fetchall()
SELECT addresses.id, addresses.user_id, addresses.email_address
FROM addresses
WHERE addresses.email_address LIKE ? EXCEPT SELECT addresses.id, addresses.user_id, addresses.e
FROM addresses
WHERE addresses.email_address LIKE ?
[’%@%.com’, ’%@msn.com’][(1, 1, u’jack@yahoo.com’), (4, 2, u’wendy@aol.com’)]
使用Scalar()
>>> print conn.execute(select([
... users.c.name,
... select([func.count(addresses.c.id)], users.c.id==addresses.c.user_id).as_scalar()
... ])).fetchall()
SELECT users.name, (SELECT count(addresses.id) AS count_1
FROM addresses
WHERE users.id = addresses.user_id) AS anon_1
FROM users
[][(u’jack’, 2), (u’wendy’, 2), (u’fred’, 0), (u’mary’, 0)]
给上面的语句应用label()
>>> print conn.execute(select([
... users.c.name,
... select([func.count(addresses.c.id)], users.c.id==addresses.c.user_id).label(’address_count’)
... ])).fetchall()
SELECT users.name, (SELECT count(addresses.id) AS count_1
FROM addresses
WHERE users.id = addresses.user_id) AS address_count
FROM users
[][(u’jack’, 2), (u’wendy’, 2), (u’fred’, 0), (u’mary’, 0)]
correlate()关联子查询
>>> s = select([users.c.name], users.c.id==select([users.c.id]).correlate(None))
>>> print s
SELECT users.name
FROM users
WHERE users.id = (SELECT users.id
FROM users)
>>> s = select([users.c.name, addresses.c.email_address], users.c.id==
... select([users.c.id], users.c.id==addresses.c.user_id).correlate(addresses)
... )
>>> print s
SELECT users.name, addresses.email_address
FROM users, addresses
WHERE users.id = (SELECT users.id
FROM users
WHERE users.id = addresses.user_id)
关于order_by(asc,desc),group_by(having),limit和offset,distinct=True的一些用法
>>> s = select([addresses.c.user_id, func.count(addresses.c.id)]).\
... group_by(addresses.c.user_id).having(func.count(addresses.c.id)>1)
>>> print conn.execute(s).fetchall()
SELECT addresses.user_id, count(addresses.id) AS count_1
FROM addresses GROUP BY addresses.user_id
HAVING count(addresses.id) > ?
[1][(1, 2), (2, 2)]
>>> s = select([addresses.c.email_address, addresses.c.id]).distinct().\
... order_by(addresses.c.email_address.desc(), addresses.c.id)
>>> conn.execute(s).fetchall()
SELECT DISTINCT addresses.email_address, addresses.id
FROM addresses ORDER BY addresses.email_address DESC, addresses.id
[][(u’www@www.org’, 3), (u’wendy@aol.com’, 4), (u’jack@yahoo.com’, 1), (u’jack@msn.com’, 2)]
>>> s = select([addresses]).offset(1).limit(1)
>>> print conn.execute(s).fetchall()
SELECT addresses.id, addresses.user_id, addresses.email_address
FROM addresses
LIMIT 1 OFFSET 1
[][(2, 1, u’jack@msn.com’)]
更新记录
>>> conn.execute(users.update().where(users.c.name==’jack’).values(name=’ed’))
UPDATE users SET name=? WHERE users.name = ?
[’ed’, ’jack’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
使用绑定参数的更新语句
>>> u = users.update().where(users.c.name==bindparam(’oldname’)).values(name=bindparam(’newname
>>> conn.execute(u, oldname=’jack’, newname=’ed’)
UPDATE users SET name=? WHERE users.name = ?
[’ed’, ’jack’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
使用表达式的更新语句
>>> conn.execute(users.update().values({users.c.fullname:"Fullname: " + users.c.name}))
UPDATE users SET fullname=(? || users.name)
[’Fullname: ’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
关联更新
>>> conn.execute(users.update().values({users.c.fullname:"Fullname: " + users.c.name}))
UPDATE users SET fullname=(? || users.name)
[’Fullname: ’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
删除表记录
>>> conn.execute(addresses.delete())
DELETE FROM addresses
[]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
根据条件删除表记录
>>> conn.execute(users.delete().where(users.c.name > ’m’))
DELETE FROM users WHERE users.name > ?
[’m’]
COMMIT<sqlalchemy.engine.base.ResultProxy object at 0x...>
电影完了,不亏是引进大片,太精彩了,不过也需要我花一段时间好好回味和消化一下,通过这次约会,我对SQLAlchemy有了进一步的了解,也更加喜欢了~~我要坚持和她拍拖下去,争取白头偕老~~坚持!!!!
这文章可能要暂停几天,我需要花些时间消化这两天学的知识,希望大家谅解~
转载请注明出处:http://booolee.cnblogs.com