增加数据:
# 单行数据(from sqlalchemy import ...)
conn = engine.connect() # 方式一: 调用表对象的insert ins = cookies.insert().values( cookie_name='chocolate chip', cookie_recipe_url='http://some.aweso.me/cookie/recipe.html', cookie_sku='CC01', quantity='12', unit_cost='0.50' ) print 'values: => {0}'.format(ins.compile().params) result = conn.execute(ins) print 'instid: => {0}'.format(result.inserted_primary_key) # 方式二: 调用全局对象insert ins = insert(cookies).values( cookie_name='chocolate chip', cookie_recipe_url='http://some.aweso.me/cookie/recipe.html', cookie_sku='CC01', quantity='12', unit_cost='0.50' ) print 'values: => {0}'.format(ins.compile().params) result = conn.execute(ins) print 'instid: => {0}'.format(result.inserted_primary_key) # 方式三: 调用execute中执行 ins = cookies.insert() result = conn.execute( ins, cookie_name='chocolate chip', cookie_recipe_url='http://some.aweso.me/cookie/recipe.html', cookie_sku='CC01', quantity='12', unit_cost='0.50' ) print 'values: => {0}'.format(ins.compile().params) result = conn.execute(ins) print 'instid: => {0}'.format(result.inserted_primary_key)
说明: 如上演示了三种添加数据的方式,如第一种调用,指定表的inset()初始化一个insert实例,然后调用其values方法来填充默认insert语句的中的列对应的值,最终返回一个insert对象,通过ins.compile().params可通过字典的形式返回插入的键值对,最终调用conn连接对象的execute执行这个ins对象compile翻译后的SQL语句,返回执行结果对象,还可以通过结果对象result.inserted_primary_key返回插入记录的ID列表
# 多行数据(from sqlalchemy import ...)
conn = engine.connect() inventory_list = [ { 'cookie_name': 'peanut butter', 'cookie_recipe_url': 'http://some.aweso.me/cookie/peanut.html', 'cookie_sku': 'PB01', 'quantity': '24', 'unit_cost': '0.25' }, { 'cookie_name': 'oatmeal raisin', 'cookie_recipe_url': 'http://some.okay.me/cookie/raisin.html', 'cookie_sku': 'EWW01', 'quantity': '100', 'unit_cost': '1.00' } ] ins = insert(cookies) result = conn.execute(ins, inventory_list) print 'instid: {0}'.format(result.lastrowid)
说明: 如上演示了最常用的多行插入数据的方式,conn.execute返回的ResultProxy对象在多行插入时可以通过result.lastrowid来获取插入最后一行的id值
查询数据:
# 所有字段(from sqlalchemy import ...)
conn = engine.connect() # 方式一: 调用全局对象select s = select([ cookies.c.id, cookies.c.cookie_name, cookies.c.cookie_recipe_url, cookies.c.cookie_sku, cookies.c.quantity, cookies.c.unit_cost ]) r = conn.execute(s) k = r.keys() result = [dict(zip(k, v)) for v in r.fetchall()] print 'values: {0}'.format(result) # 方式二: 调用表级对象select s = cookies.select() r = conn.execute(s) k = r.keys() result = [dict(zip(k, v)) for v in r.fetchall()] print 'values: {0}'.format(result)
说明: 如上演示了两种查询数据的方式,首先实例化,如第一种调用,一个select实例,实例参数必须是一个列表,如果列表中为表名则表示查询所有列,否则查询指定列,cookies.c.id其实就是column(id)对象,然后调用conn.execute执行这个select对象compile翻译后的SQL语句,然后返回ResultProxy对象,然后调用ResultProxy对象的fetchall来获取所有行,ResultProxy对象有一个特殊的方法keys()可获取所有的列名,有时模版渲染时字典形式比较方便.
# 结果对象(from sqlalchemy import ...)
conn = engine.connect() s = select([ cookies.c.id, cookies.c.cookie_name, cookies.c.cookie_recipe_url, cookies.c.cookie_sku, cookies.c.quantity, cookies.c.unit_cost ]) # 说明: r为ResultProxy是cursor代理,而cursor是支持迭代的,更加推荐迭代获取结果集 r = conn.execute(s) for record in r: print 'type => {} values => {}'.format(type(record), record) # 说明: r.fetchall()返回是列表,但列表中的每个元素通过分片后会自动转换为RowProxy对象 r = conn.execute(s) # Get a wrapper of cursor, ResultProxy print 'type => {}'.format(type(r)) # Get all row of the ResultProxy, list allrows = r.fetchall() print 'type => {} values => {}'.format(type(allrows), allrows) # Get one row of the list, RowProxy onerow = allrows[0] print 'type => {} values => {}'.format(type(onerow), onerow) # 说明: cookies.c为cookies中虽有的列对象集合,可通过遍历通过.或[]来获取对应列的值 # Get all col of the row, value for key in cookies.c: oneval = getattr(onerow, key.name) print 'type => {} values => {}'.format(type(oneval), oneval) # 说明: r.fetchone每次获取的是从上一次fetch的位置算起的第一个,且返回的也是RowProxy对象 r = conn.execute(s) onerow = r.fetchone() print 'type => {} values => {}'.format(type(onerow), onerow) # 说明: r.first()永远返回结果集中的第一条记录,且返回的是RowProxy对象 r = conn.execute(s) firstrow = r.first() print 'type => {} values => {}'.format(type(firstrow), firstrow) # 说明: r.scalar()永远返回结果集中的第一条记录的第一列的值,返回一行时才有意义 r = conn.execute(s) ids = r.scalar() print 'type => {} values => {}'.format(type(ids), ids)
说明: 如上演示了多种代理结果集的操作方法,比较有意思的是ResultProxy对象fetchall返回的是元组列表而分片后的元素自动转换为RowProxy对象,还可以通过fetchone/first/scalar等获取,获取到的RowProxy对象可通过.或[表实例.c.列名]的方式获取对应列的值
# 排序相关(from sqlalchemy import ...)
conn = engine.connect() s = select([cookies.c.quantity, cookies.c.cookie_name]).order_by(desc(cookies.c.quantity)) r = conn.execute(s) for record in r: print '{0} - {1}'.format(record.quantity, record.cookie_name)
说明: 如上演示了常规按照指定列排序操作方法,通过对ResultProxy调用order_by排序,参数为指定列对象,默认正向排序,可通过desc(cookies.c.quantity)或cookies.c.quantity.desc()来逆向排序,但是更推荐使用desc(cookies.c.quantity)这种方式.
# 限制行数(from sqlalchemy import ...)
conn = engine.connect() s = select([cookies.c.quantity, cookies.c.cookie_name]).order_by(cookies.c.quantity).limit(2) r = conn.execute(s) for record in r: print '{0} - {1}'.format(record.quantity, record.cookie_name)
说明: 如上演示了按照指定列排序限制行数,通过对ResultProxy调用limit限制行数,参数为限制输出指定行
# 聚合函数(from sqlalchemy.sql import functions)
conn = engine.connect() # 说明: 总和 s = select([functions.sum(cookies.c.quantity)]) r = conn.execute(s) print 'values: {0}'.format(r.scalar()) # 说明: 计数 s = select([functions.count(cookies.c.id).label('inventory_count')]) r = conn.execute(s) result = r.first() print 'values: {0}'.format(result.inventory_count)
说明: 如上演示了常用聚合函数sum和count,sum,默认不使用label定义一个列别名默认用sum_1/count_1...sum_n/count_n作为RowProxy的属性,否则可直接调用result.label_name获取新增列值,当然了比较简单粗暴的方式还是调用scalar,因为它始终会输出最左边列的值
# 各种运算(from sqlalchemy import ...)
conn = engine.connect() # 说明: 支持几乎PY中所有运算符 s = select([cookies.c.id, ('xmdevops-' + cookies.c.cookie_sku).label('cookie_sku_alias')]) r = conn.execute(s) for record in r: print type(record), record.items() # 说明: 支持运算参数灵活的转换 s = select([cookies.c.id, cookies.c.unit_cost.cast(Numeric(12, 2))]) r = conn.execute(s) for record in r: print type(record), record.items()
说明: 如上演示了常用的运算符和一个特殊的转换类型的cast,可以作为column对象的属性调用,也可以直接调用cast,它的最后参数可以是SQLAlchemy支持的任意数据类型
# 过滤数据(from sqlalchemy import ...)
conn = engine.connect() # expression s = select([cookies]).where( cookies.c.quantity == 12 ).where( cookies.c.cookie_name == u'chocolate chip' ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # like / notlike s = select([cookies]).where( cookies.c.cookie_name.like('%chocolate%') ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # between s = select([cookies]).where( cookies.c.id.between(16, 32) ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # concat s = select([cookies]).where( cookies.c.id.concat(cookies.c.quantity) == '2424' ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # distinct s = select([cookies.c.cookie_name.distinct()]) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # in_ / notin_ s = select([cookies]).where( cookies.c.cookie_name.in_([u'chocolate chip', u'oatmeal raisin']) ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # is_ / isnot s = select([cookies]).where( cookies.c.cookie_name.is_(None) ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # contains s = select([cookies]).where( cookies.c.cookie_name.contains('raisin') ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # endswith s = select([cookies]).where( cookies.c.cookie_name.endswith('raisin') ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # startswith s = select([cookies]).where( cookies.c.cookie_name.startswith('chocolate') ) r = conn.execute(s) for record in r: print type(record), dict(record.items()) # and_ / or_ / not_ s = select([cookies]).where( and_(cookies.c.quantity > 23, cookies.c.unit_cost < 0.40) ) r = conn.execute(s) for record in r: print type(record), dict(record.items())
说明: 如上演示了常用的内置函数like/notlike/between/concat/distinct/in_/notin_/is_/isnot/contains/startswith/endswith/and_/or_/not_的操作方法,熟悉MySQL的应该对这些都不陌生吧~这里就不一一讲解了~
更新数据:
conn = engine.connect() u = update(cookies).where(cookies.c.cookie_name == 'peanut butter').values( quantity=cookies.c.quantity * 2 ) r = conn.execute(u) print 'values: {0}'.format(r.rowcount) s = select([cookies.c.cookie_name, cookies.c.quantity]).where( cookies.c.cookie_name == 'peanut butter' ) r = conn.execute(s) for record in r: print type(record), record
说明: 如上演示了常用的更新数据方式,update和insert用法类似,但支持where条件,来限制更新指定列,不然将会更新所有列.
删除数据:
conn = engine.connect() d = delete(cookies).where(cookies.c.cookie_name == 'peanut butter') r = conn.execute(d) print 'values: {0}'.format(r.rowcount)
说明: 如上演示了常用的删除数据方式,delete和update/insert的区别在于不需要values,但支持where,来限制删除指定列,不然会删除所有列.
多表连接:
conn = engine.connect() # 内连接: join,只有两个表相匹配的行才能在结果集中出现 s = select([orders.c.id, users.c.username, line_items.c.quantity, cookies.c.cookie_name]).select_from( orders.join(users).join(line_items).join(cookies) ).where(users.c.username == 'cookiemon') r = conn.execute(s) for record in r: print type(record), dict(record.items()) # 左连接: outerjoin,左边的表不加限制 s = select([line_items.c.id, line_items.c.quantity, cookies.c.cookie_name]).select_from( line_items.outerjoin(cookies, line_items.c.cookie_id == cookies.c.id) ) r = conn.execute(s) for record in r: print type(record), dict(record.items())
说明: 如上演示了常用的自连接join和左连接outerjoin的用法,新版不支持右连接,全连接,但是基本上使用自连接和左连接已经几乎可以满足我们的所有需求了.
表级别名:
conn = engine.connect() c = cookies.alias() s = select([c.c.id, cookies.c.cookie_name]).where( c.c.id == cookies.c.id ) r = conn.execute(s) for record in r: print type(record), record
说明: 如上演示了常用的表别名用法,特别是在多表关联时,多处会用到不同的表名,有的表名可能臭长臭长的,不太好记忆,可通过先定义一个别名再操作对应的表~
分组查询:
conn = engine.connect() s = select([users.c.username, functions.sum(orders.c.id)]).select_from( users.join(orders, users.c.id == orders.c.user_id) ).group_by(users.c.username) r = conn.execute(s) for record in r: print type(record), record
说明: 如上演示了常用的分组查询用法,查询每个用户的订单量,先通过内连接join关联多表查询,然后通过group_by按照用户名来分组,思路和SQL非常类似~
RAWSQL:
conn = engine.connect() # 全raw sql s = 'select * from users' r = conn.execute(s) for record in r: print type(record), record # 半raw sql s = select([users]).where(text("username='limanman'")) r = conn.execute(s) for record in r: print type(record), record
说明: 如上演示了常用的裸SQL的用法,其实工作中不太常用,但是有时候SQLALchemy没有实现对应接口时裸SQL也是一种解决方案,如果要半裸状态则需要用text来解析一下先.