一、GROUP BY基本语法格式:html
GROUP BY关键字能够将查询结果按照某个字段或多个字段进行分组。字段中值相等的为一组。基本的语法格式以下:python
GROUP BY 属性名 [HAVING 条件表达式] [WITH ROLLUP]mysql
二、GROUP BY联合函数使用:sql
1)GROUP BY关键字能够和GROUP_CONCAT()函数一块儿使用。数据库
2)GROUP_CONCAT()函数会把每一个分组中指定的字段值都显示出来。django
3)同时,GROUP BY关键字一般与集合函数一块儿使用。集合函数包括COUNT()函数、SUM()函数、AVG()函数、MAX()函数和MIN()函数等。编程
4)注意:若是GROUP BY不与上述函数一块儿使用,那么查询结果就是字段取值的分组状况。字段中取值相同的记录为一组,可是只显示该组的第一条记录。windows
1. 首先执行不带GROUP BY关键字的SELECT语句。以下图所示:数组
select * from employee;服务器
2. 执行带有GROUP BY关键字的SELECT语句。代码以下:
SELECT * FROM employee GROUP BY sex;
+----+------+--------+-----+-----+-------------+
| id | num | name | sex | age | homeaddress |
+----+------+--------+-----+-----+-------------+
| 2 | 1001 | 马莉莉 | 女 | 24 | 河南开封 |
| 1 | 1001 | 王冬军 | 男 | 26 | 河南郑州 |
+----+------+--------+-----+-----+-------------+
2 rows in set (0.00 sec)
上图中代码执行的结果只显示了两条记录。这两条记录的sex字段的值分别为“女”和“男”。
查询结果进行比较,GROUP BY关键字只显示每一个分组的一条记录。这说明,GROUP BY关键字单独使用时,只能查询出每一个分组的一条记录,这样作的意义不大。
所以,通常在使用集合函数时才使用GROUP BY关键字。
GROUP BY关键字与GROUP_CONCAT()函数一块儿使用时,每一个分组中指定的字段值会所有显示出来。
实例:将employee表按照sex字段进行分组查询。使用GROUP_CONCAT()函数将每一个分组的name字段的值显示出来。
SELECT sex,GROUP_CONCAT(name) FROM employee GROUP BY sex;
+-----+--------------------+
| sex | GROUP_CONCAT(name) |
+-----+--------------------+
| 女 | 马莉莉,张雪梅 |
| 男 | 王冬军,刘兵,Tom |
+-----+--------------------+
2 rows in set (0.00 sec)
上图中代码执行的结果显示,查询结果分为两组。sex字段取值为“女”的记录是一组,取值为“男”的记录是一组。
每一组中全部人的名字都被查询出来了。
该实例说明,使用GROUP_CONCAT()函数能够很好的把分组状况表示出来。
mysql> SELECT sex,GROUP_CONCAT(name) FROM employee GROUP BY sex WITH ROLLUP;
+-----+-------------------------------+
| sex | GROUP_CONCAT(name) |
+-----+-------------------------------+
| 女 | 马莉莉,张雪梅 |
| 男 | 王冬军,刘兵,Tom |
| NULL | 马莉莉,张雪梅,王冬军,刘兵,Tom |
+-----+-------------------------------+
3 rows in set (0.00 sec)
GROUP BY关键字与集合函数一块儿使用时,能够经过集合函数计算分组中的总记录、最大值、最小值等。
实例:将employee表的sex字段进行分组查询。sex字段取值相同的为一组。而后对每一组使用集合函数COUNT()函数进行计算,求出每一组的记录数。
mysql> SELECT sex,COUNT(sex) FROM employee GROUP BY sex;
+-----+------------+
| sex | COUNT(sex) |
+-----+------------+
| 女 | 2 |
| 男 | 3 |
+-----+------------+
2 rows in set (0.00 sec)
上图中代码执行的结果显示,查询结果按sex字段的取值进行分组。取值为“女”的记录为一组,取值为“男”的记录为一组。
COUNT(sex)计算出了sex字段不一样分组的记录数。第一组共有2条记录,第二组共有3条记录。
WITH ROLLUP:将会在全部记录的最后加上一条记录。加上的这一条记录是上面全部记录的总和。
mysql> SELECT sex,COUNT(sex) FROM employee GROUP BY sex WITH ROLLUP;
+-----+------------+
| sex | COUNT(sex) |
+-----+------------+
| 女 | 2 |
| 男 | 3 |
| NULL | 5 |
+-----+------------+
3 rows in set (0.00 sec)
使用GROUP BY关键字时,若是加上“HAVING 条件表达式”,则能够限制输出的结果。只有符合条件表达式的结果才会显示。
实例:将employee表的sex字段进行分组查询。而后显示记录数大于等于3的分组。
SELECT语句的代码以下:
mysql> SELECT sex,COUNT(sex) FROM employee GROUP BY sex HAVING COUNT(sex)>=3;
+-----+------------+
| sex | COUNT(sex) |
+-----+------------+
| 男 | 3 |
+-----+------------+
1 row in set (0.00 sec)
在MySQL中,还能够按照多个字段进行分组。例如,employee表按照num字段和sex字段进行分组。分组过程当中,
先按照num字段进行分组,遇到num字段的值相等的状况时,再把num值相等的记录按照sex字段进行分组。
实例:将employee表按照num字段和sex字段进行分组。
SELECT语句的代码以下:
mysql> SELECT * FROM employee GROUP BY num,sex;
+----+------+--------+-----+-----+-------------+
| id | num | name | sex | age | homeaddress |
+----+------+--------+-----+-----+-------------+
| 2 | 1001 | 马莉莉 | 女 | 24 | 河南开封 |
| 1 | 1001 | 王冬军 | 男 | 26 | 河南郑州 |
| 3 | 1002 | 刘兵 | 男 | 25 | 广东省广州 |
| 5 | 1004 | 张雪梅 | 女 | 20 | 福建厦门 |
| 4 | 1004 | Tom | 男 | 18 | America |
+----+------+--------+-----+-----+-------------+
5 rows in set (0.00 sec)
1.内联结:将两个表中存在联结关系的字段符合联结关系的那些记录造成记录集的联结。
2.外联结:分为外左联结和外右联结。
右联结A、B表的结果和左联结B、A的结果是同样的,也就是说:
Select A.name B.name From A Left Join B On A.id=B.id
Select A.name B.name From B Right Join A on B.id=A.id
执行后的结果是同样的。
说明:
1)内外联结的区别是内联结将去除全部不符合条件的记录,而外联结则保留其中部分。
2) 外左联结与外右联结的区别在于若是用A左联 结B则A中全部记录都会保留在结果中,此时B中只有符合联结条件的记录,而右联结相反。
假设有以下两张表:
表A |
|
ID |
Name |
1 |
Tiim |
2 |
Jimmy |
3 |
John |
4 |
Tom |
表B |
|
ID |
Hobby |
1 |
Football |
2 |
Basketball |
2 |
Tennis |
4 |
Soccer |
1)内联结:
Select A.Name B.Hobby from A, B where A.id = B.id
这是隐式的内联结,查询的结果是:
Name |
Hobby |
Tim |
Football |
Jimmy |
Basketball |
Jimmy |
Tennis |
Tom |
Soccer |
它的做用和:
Select A.Name from A INNER JOIN B ON A.id = B.id
是同样的。
2)外左联结
Select A.Name from A Left JOIN B ON A.id = B.id
这样查询获得的结果将会是保留全部A表中联结字段的记录,若无与其相对应的B表中的字段记录则留空,结果以下:
Name |
Hobby |
Tim |
Football |
Jimmy |
Basketball,Tennis |
John |
|
Tom |
Soccer |
因此从上面结果看出,由于A表中的John记录的ID没有在B表中有对应ID,所以为空,但Name栏仍有John记录。
2)外右联结
Select A.Name from A Right JOIN B ON A.id = B.id
结果将会是:
Name |
Hobby |
Tim |
Football |
Jimmy |
Basketball |
Jimmy |
Tennis |
Tom |
Soccer |
此时B表中的所有记录都打印了,可是A表没有显示完整记录,只是显示了跟B表相关联的记录。
1.USING (column_list):
其做用是为了方便书写联结的多对应关系,大部分状况下USING语句能够用ON语句来代替,以下面例子:
a LEFT JOIN b USING (c1,c2,c3),其做用至关于
a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
2.STRAIGHT_JOIN:
因为默认状况下MySQL在进行表的联结的时候会先读入左表,当使用了这个参数后MySQL将会先读入右表,这是个MySQL的内置优化参数,
你们应该在特定状况下使用,譬如已经确认右表中的记录数量少,在筛选后能大大提升查询速度。
下载
http://dev.mysql.com/downloads/mysql/
安装
windows:
点点点
Linux:
yum -y install mysql mysql-server mysql-devel
SHOW DATABASES; SHOW TABLES;
默认数据库:
mysql - 用户权限相关数据
test - 用于用户测试数据
information_schema - MySQL自己架构相关数据
1)用户管理:
建立用户 create user '用户名'@'IP地址' identified by '密码'; 删除用户 drop user '用户名'@'IP地址'; 修改用户 rename user '用户名'@'IP地址'; to '新用户名'@'IP地址';; 修改密码 set password for '用户名'@'IP地址' = Password('新密码') PS:用户权限相关数据保存在mysql数据库的user表中,因此也能够直接对其进行操做(不建议)
2)受权管理:
show grants for '用户'@'IP地址' -- 查看权限 grant 权限 on 数据库.表 to '用户'@'IP地址' -- 受权 revoke 权限 on 数据库.表 from '用户'@'IP地址' -- 取消权限
3)对于权限:
all privileges 除grant外的全部权限 select 仅查权限 select,insert 查和插入权限 ... usage 无访问权限 alter 使用alter table alter routine 使用alter procedure和drop procedure create 使用create table create routine 使用create procedure create temporary tables 使用create temporary tables create user 使用create user、drop user、rename user和revoke all privileges create view 使用create view delete 使用delete drop 使用drop table execute 使用call和存储过程 file 使用select into outfile 和 load data infile grant option 使用grant 和 revoke index 使用index insert 使用insert lock tables 使用lock table process 使用show full processlist select 使用select show databases 使用show databases show view 使用show view update 使用update reload 使用flush shutdown 使用mysqladmin shutdown(关闭MySQL) super 使用change master、kill、logs、purge、master和set global。还容许mysqladmin调试登录 replication client 服务器位置的访问 replication slave 由复制从属使用
4)对于数据库:
对于目标数据库以及内部其余: 数据库名.* 数据库中的全部 数据库名.表 指定数据库中的某张表 数据库名.存储过程 指定数据库中的存储过程 *.* 全部数据库
5)对于用户和IP:
用户名@IP地址 用户只能在改IP下才能访问 用户名@192.168.1.% 用户只能在改IP段下才能访问(通配符%表示任意) 用户名@% 用户能够再任意IP下访问(默认IP地址为%)
6)示例:
grant all privileges on db1.tb1 TO '用户名'@'IP' grant select on db1.* TO '用户名'@'IP' grant select,insert on *.* TO '用户名'@'IP' revoke select on db1.tb1 from '用户名'@'IP'
create table 表名( 列名 类型 是否能够为空, 列名 类型 是否能够为空 )
是否可空,null表示空,非字符串 not null - 不可空 null - 可空
默认值,建立列时能够指定默认值,当插入数据时若是未主动设置,则自动添加默认值 create table tb1( nid int not null defalut 2, num int not null )
自增,若是为某列设置自增列,插入数据时无需设置此列,默认将自增(表中只能有一个自增列) create table tb1( nid int not null auto_increment primary key, num int null ) 或 create table tb1( nid int not null auto_increment, num int null, index(nid) ) 注意:1、对于自增列,必须是索引(含主键)。 2、对于自增能够设置步长和起始值 show session variables like 'auto_inc%'; set session auto_increment_increment=2; set session auto_increment_offset=10; shwo global variables like 'auto_inc%'; set global auto_increment_increment=2; set global auto_increment_offset=10;
主键,一种特殊的惟一索引,不容许有空值,若是主键使用单个列,则它的值必须惟一,若是是多列,则其组合必须惟一。 create table tb1( nid int not null auto_increment primary key, num int null ) 或 create table tb1( nid int not null, num int not null, primary key(nid,num) )
外键,一个特殊的索引,只能是指定内容 creat table color( nid int not null primary key, name char(16) not null ) create table fruit( nid int not null primary key, smt char(32) null , color_id int not null, constraint fk_cc foreign key (color_id) references color(nid) )
drop table 表名
delete from 表名 truncate table 表名
添加列:alter table 表名 add 列名 类型 删除列:alter table 表名 drop column 列名 修改列: alter table 表名 modify column 列名 类型; -- 类型 alter table 表名 change 原列名 新列名 类型; -- 列名,类型 添加主键: alter table 表名 add primary key(列名); 删除主键: alter table 表名 drop primary key; alter table 表名 modify 列名 int, drop primary key; 添加外键:alter table 从表 add constraint 外键名称(形如:FK_从表_主表) foreign key 从表(外键字段) references 主表(主键字段); 删除外键:alter table 表名 drop foreign key 外键名称 修改默认值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000; 删除默认值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT;
MySQL的数据类型大体分为:数值、时间和字符串
http://www.runoob.com/mysql/mysql-data-types.html
insert into 表 (列名,列名...) values (值,值,值...) insert into 表 (列名,列名...) values (值,值,值...),(值,值,值...) insert into 表 (列名,列名...) select (列名,列名...) from 表
delete from 表 delete from 表 where id=1 and name='alex'
update 表 set name = 'alex' where id>1
select * from 表 select * from 表 where id > 1 select nid,name,gender as gg from 表 where id > 1
1、条件 select * from 表 where id > 1 and name != 'alex' and num = 12; select * from 表 where id between 5 and 16; select * from 表 where id in (11,22,33) select * from 表 where id not in (11,22,33) select * from 表 where id in (select nid from 表) 2、通配符 select * from 表 where name like 'ale%' - ale开头的全部(多个字符串) select * from 表 where name like 'ale_' - ale开头的全部(一个字符) 3、限制 select * from 表 limit 5; - 前5行 select * from 表 limit 4,5; - 从第4行开始的5行 select * from 表 limit 5 offset 4 - 从第4行开始的5行 4、排序 select * from 表 order by 列 asc - 根据 “列” 从小到大排列 select * from 表 order by 列 desc - 根据 “列” 从大到小排列 select * from 表 order by 列1 desc,列2 asc - 根据 “列1” 从大到小排列,若是相同则按列2从小到大排序 5、分组 select num from 表 group by num select num,nid from 表 group by num,nid select num,nid from 表 where nid > 10 group by num,nid order nid desc select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid select num from 表 group by num having max(id) > 10 特别的:group by 必须在where以后,order by以前 6、连表 无对应关系则不显示 select A.num, A.name, B.name from A,B Where A.nid = B.nid 无对应关系则不显示 select A.num, A.name, B.name from A inner join B on A.nid = B.nid A表全部显示,若是B中无对应关系,则值为null select A.num, A.name, B.name from A left join B on A.nid = B.nid B表全部显示,若是B中无对应关系,则值为null select A.num, A.name, B.name from A right join B on A.nid = B.nid 7、组合 组合,自动处理重合 select nickname from A union select name from B 组合,不处理重合 select nickname from A union all select name from B
pymsql是Python中操做MySQL的模块,其使用方法和MySQLdb几乎相同。
pip3 install pymysql
1、执行SQL
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql # 建立链接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 建立游标 cursor = conn.cursor() # 执行SQL,并返回收影响行数 effect_row = cursor.execute("update hosts set host = '1.1.1.2'") # 执行SQL,并返回受影响行数 #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,)) # 执行SQL,并返回受影响行数 #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) # 提交,否则没法保存新建或者修改的数据 conn.commit() # 关闭游标 cursor.close() # 关闭链接 conn.close()
2、获取新建立数据自增ID
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) conn.commit() cursor.close() conn.close() # 获取最新自增ID new_id = cursor.lastrowid
3、获取查询数据
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.execute("select * from hosts") # 获取第一行数据 row_1 = cursor.fetchone() # 获取前n行数据 # row_2 = cursor.fetchmany(3) # 获取全部数据 # row_3 = cursor.fetchall() conn.commit() cursor.close() conn.close()
注:在fetch数据时按照顺序进行,可使用cursor.scroll(num,mode)来移动游标位置,如:
4、fetch数据类型
关于默认获取的数据是元祖类型,若是想要或者字典类型的数据,即:
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) r = cursor.execute("call p1()") result = cursor.fetchone() conn.commit() cursor.close() conn.close()
SQLAlchemy是Python编程语言下的一款ORM框架,该框架创建在数据库API之上,使用关系对象映射进行数据库操做,简言之即是:将对象转换成SQL,而后使用数据API执行SQL并获取执行结果。
sqlalchemy默认不支持修改表结构,得下载第三方的工具,才能修改。
SQLAlchemy自己没法操做数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不一样调用不一样的数据库API,从而实现对数据库的操做,如:
MySQL-Python mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
使用 Engine/ConnectionPooling/Dialect 进行数据库操做,Engine使用ConnectionPooling链接数据库,而后再经过Dialect执行SQL语句。
#!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)" # ) # 新插入行自增ID # cur.lastrowid # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES(%s, %s)",[('1.1.1.22', 3),('1.1.1.221', 3),] # ) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)", # host='1.1.1.99', color_id=3 # ) # 执行SQL # cur = engine.execute('select * from hosts') # 获取第一行数据 # cur.fetchone() # 获取第n行数据 # cur.fetchmany(3) # 获取全部数据 # cur.fetchall()
使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 全部组件对数据进行操做。根据类建立对象,对象转换成SQL,执行SQL。
sqlalchemy不会帮你建立数据库,要本身建立数据库。
sqlalchemy要么建立表,要么删除表,默认不支持修改表结构,得下载sqlalchemy第三方的工具,才能修改。
在django的orm里能够修改表结构。
1、建立表
#!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) # 创建数据库链接 Base = declarative_base() # 建立base module # 建立单表 class Users(Base): # 建立类,要继承Base __tablename__ = 'users' # 定义的表名 id = Column(Integer, primary_key=True) # 下面是建立了三列数据 name = Column(String(32)) extra = Column(String(16)) __table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), # 加了联合索引,上面一行是惟一,下面一行是加索引。 Index('ix_id_name', 'name', 'extra'), ) # 一对多 class Favor(Base): __tablename__ = 'favor' nid = Column(Integer, primary_key=True) caption = Column(String(50), default='red', unique=True) class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 和favor表的id作了外键关联 # 多对多 class Group(Base): __tablename__ = 'group' id = Column(Integer, primary_key=True) name = Column(String(64), unique=True, nullable=False) class Server(Base): __tablename__ = 'server' id = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(64), unique=True, nullable=False) port = Column(Integer, default=22) class ServerToGroup(Base): # 建立多对多关系,得建立第三张表。 __tablename__ = 'servertogroup' nid = Column(Integer, primary_key=True, autoincrement=True) server_id = Column(Integer, ForeignKey('server.id')) # 外键到server表的id group_id = Column(Integer, ForeignKey('group.id')) # 外键到group表的id def init_db(): Base.metadata.create_all(engine) # 只要执行这一句,就会自动找base全部的子类,根据这些子类把表批量建立出来。 def drop_db(): Base.metadata.drop_all(engine) # 表示批量删除全部base的子类建立的表
ForeignKeyConstraint(['other_id'], ['othertable.other_id']),
二、操做表
建立session搞上会话。
经过session来操做数据库。
若是想往表里添加数据的话,用
session.add()
或者
session.addall()
就从某个表里加了数据
举例说明:
Session = sessionmaker(bind=engine) session = Session() obj = Users(name="qiaomei", extra='qm') #建立一个记录,就是建立一个对象 session.add(obj) #把对象加到session里 session.add_all([ Users(name="qiaomei1", extra='qm'), Users(name="qiaomei2", extra='qm'), ]) session.commit()
若是是多个条件,且的话,就在filter里加上逗号,添加多个条件。
session.query(Users).filter(Users.id > 2,Users.name='qiaomei').delete()
session.commit()
#!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) Base = declarative_base() # 建立单表 class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(32)) extra = Column(String(16)) __table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), Index('ix_id_name', 'name', 'extra'), ) def __repr__(self): return "%s-%s" %(self.id, self.name) # 一对多 class Favor(Base): __tablename__ = 'favor' nid = Column(Integer, primary_key=True) caption = Column(String(50), default='red', unique=True) def __repr__(self): return "%s-%s" %(self.nid, self.caption) class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers') # 多对多 class ServerToGroup(Base): __tablename__ = 'servertogroup' nid = Column(Integer, primary_key=True, autoincrement=True) server_id = Column(Integer, ForeignKey('server.id')) group_id = Column(Integer, ForeignKey('group.id')) group = relationship("Group", backref='s2g') server = relationship("Server", backref='s2g') class Group(Base): __tablename__ = 'group' id = Column(Integer, primary_key=True) name = Column(String(64), unique=True, nullable=False) port = Column(Integer, default=22) # group = relationship('Group',secondary=ServerToGroup,backref='host_list') class Server(Base): __tablename__ = 'server' id = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(64), unique=True, nullable=False) def init_db(): Base.metadata.create_all(engine) def drop_db(): Base.metadata.drop_all(engine) Session = sessionmaker(bind=engine) session = Session()
增
obj = Users(name="qiaomei0", extra='qm') session.add(obj) session.add_all([ Users(name="qiaomei1", extra='qm'), Users(name="qiaomei2", extra='qm'), ]) session.commit()
删
session.query(Users).filter(Users.id > 2,Users.name='qiaomei').delete() session.commit()
改
session.query(Users).filter(Users.id > 2).update({"name" : "099"}) session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False) session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate") session.commit()
查
ret = session.query(Users).all() print(type(ret[0])) # <class '__main__.Users'> ret = session.query(Users.name, Users.extra).all() ret = session.query(Users).filter_by(name='qiaomei').all() ret = session.query(Users).filter_by(name='qiaomei').first() ''' 打印结果: ret1: [1-qiaomei0, 2-qiaomei1, 3-qiaomei2] 注意:打印的是User类对象列表。(一条记录对应着一个User对象) ret2: [('qiaomei0', 'qm'), ('qiaomei1', 'qm'), ('qiaomei2', 'qm')] ret3: [] ret4: None '''
# 若是想查看生成的sql语句是什么,就不加all()
q = session.query(Users) print(q) # SELECT users.id AS users_id, users.name AS users_name, users.extra AS users_extra FROM users
其余
# 条件 ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all() # filtwr里有逗号,条件是而且的关系 ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.in_([1,3,4])).all() # id是1,3,4其中一个 ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all() # id不在,~是否的意思 ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all() # id在一个数组中,可是要先执行里面的sql from sqlalchemy import and_, or_ ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all() # and 表示都是而且关系 ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all() ret = session.query(Users).filter( # 内部是and链接,得出一个布尔值,而后外面再用or or_( Users.id < 2, and_(Users.name == 'eric', Users.id > 3), Users.extra != "" )).all() # 通配符 ret = session.query(Users).filter(Users.name.like('e%')).all() # %表示通配符 ret = session.query(Users).filter(~Users.name.like('e%')).all() # ~表示否 # 限制 ret = session.query(Users)[1:2] # 排序 ret = session.query(Users).order_by(Users.name.desc()).all() ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # 首先按照User表倒序排列,若是有相同,再排序 # 分组 from sqlalchemy.sql import func ret = session.query(Users).group_by(Users.extra).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).all() # 按照name分组,而且取其余列(id列)的最大,总数,最小值。 ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all() # having是group_by的条件过滤 # 连表 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all() # 直接让两个表进行链接 # 直接让两个表联合。这里join默认是innerjoin,这里没有写他们的对应关系,它们在内部本身找。 # 它是怎么找的呢,在建立表的时候,有类型是foreignkey,是根据它来找的。 ret = session.query(Person).join(Favor).all() ret = session.query(Person).join(Favor, isouter=True).all() # isouter=True表示leftjoin。没有rightjoin,若是想rightjoin,替换表写的位置。 # 组合 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union(q2).all() # 把q1.q2两个联合的所有取到,union会帮你去重 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union_all(q2).all() # union_all不会帮你去重
1)__repr__ 指定打印对象显示内容
def __repr__ 经过这样定义,print Users对象的时候,就打印出须要显示的内容。
若是是django,若是是python2.7,就是__unicode__方式,若是是python3,就是__str__方式。
ret = session.query(Users).filter_by(name='qiaomei').all()
print ret 这时候显示出的是__repr__打印的结果组成的数组。
__repr__对数据库查询,一点做用都没有,只是print对象有用。
2)获取属性
ret = session.query(Users).filter_by(name='qiaomei').all()
print ret[0].name就是获取名字。
这种方式是直接获取属性值
q1 = session.query(Users.name).filter(Users.id > 2)
print q1
打印:[('qiaomei1',),('qiaomei2',)]
2)创建外键关联
ForeignKey,就加上外键约束
avor_id = Column(Integer, ForeignKey("favor.nid"))
# 建立单表 class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(32)) extra = Column(String(16)) __table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), Index('ix_id_name', 'name', 'extra'), ) def __repr__(self): return "%s-%s" %(self.id, self.name)
4.1)默认是innerjoin。
# 直接让两个表联合。这里join默认是innerjoin,这里没有写他们的对应关系,它们在内部本身找。
# 它是怎么找的呢,在建立表的时候,有类型是foreignkey,是根据它来找的。
ret = session.query(Person).join(Favor).all()
至关于sql语句:
两个表经过on,来关联
sql = session.query(Person).join(Favor)
print(sql)
'''
inner join打印sql,只打印person表全部字段信息,不打印favor表
SELECT person.nid AS person_nid, person.name AS person_name, person.favor_id AS person_favor_id
FROM person JOIN favor ON favor.nid = person.favor_id
'''
4.2)isouter=True就是left join
ret1 = session.query(Person).join(Favor,isouter=True).all()
sql1 = session.query(Person).join(Favor,isouter=True)
print(sql1)
'''
打印sql,只打印person表全部字段的信息,可是没有打印favor表
SELECT person.nid AS person_nid, person.name AS person_name, person.favor_id AS person_favor_id
FROM person LEFT OUTER JOIN favor ON favor.nid = person.favor_id
'''
4.3)两张表的信息都打印出来
ret2 = session.query(Person,Favor).join(Favor,isouter=True).all() print(ret2) sql2 = session.query(Person,Favor).join(Favor,isouter=True) print(sql2) ''' left join,打印结果:打印person和favor两张表的全部字段。 [(<__main__.Person object at 0x0000000003B34FD0>, 1-white), (<__main__.Person object at 0x0000000003B69BE0>, 2-blue), (<__main__.Person object at 0x0000000003B69C50>, 2-blue)] left join,打印sql:打印person和favor两张表的全部字段。 SELECT person.nid AS person_nid, person.name AS person_name, person.favor_id AS person_favor_id, favor.nid AS favor_nid, favor.caption AS favor_caption FROM person LEFT OUTER JOIN favor ON favor.nid = person.favor_id '''
4.4)联表,只打印某些字段
联表,上面的都是打印对象,而如今咱们要获取指定字段的值。
ret3 = session.query(Person.name,Favor.caption).join(Favor,isouter=True).all() print(ret3) sql3 = session.query(Person.name,Favor.caption).join(Favor,isouter=True) print(sql3) ''' left join,打印结果:某些指定字段值 [('qiaomei0', 'white'), ('qiaomei1', 'blue'), ('qiaomei2', 'blue')] left join,打印sql:某些指定字段值 SELECT person.name AS person_name, favor.caption AS favor_caption FROM person LEFT OUTER JOIN favor ON favor.nid = person.favor_id '''
1)正向查询
正向查询指的是:多对一,多的那端开始查,也就是foreignkey写在哪里,从哪里查。
使用上面的方法很是麻烦,咱们用更高效的方法。
只要在表里加上这一句话:
favor = relationship("Favor", backref='pers')
class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers') # obj代指的是Person表的每一行数据 # obj.favor代指favor对象,obj.favor.nid就拿到了Person关联的favor对象的id。 # 因此你不用作联表,它内部帮你作联表。 ret = session.query(Person).all() for obj in ret: # 每一个obj就是一行数据。 print(obj.nid,obj.name,obj.favor_id,obj.favor,obj.favor.nid,obj.favor.caption)
'''
打印结果:
Person的id, name, favor_id,favor对象,favor的id,caption
1 qiaomei0 1 1-white 1 white
2 qiaomei1 2 2-blue 2 blue
3 qiaomei2 2 2-blue 2 blue
'''
2)反向查询
反向查询指的是:多对一,从一的那端开始查,也就是从没写foreignkey的表里反查。
# 多对一,从一的那端反查。
# Person和Favor是多对一,假如查询喜欢蓝色的全部人。Favor的caption为blue的全部对应的Person
# 传统方式,反向查询: ret3 = session.query(Person.name,Favor.caption).join(Favor,isouter=True).filter(Favor.caption == 'blue').all()
Person表里,写了backref='pers',就至关于在favor表里加了个字段pers
favor = relationship("Favor", backref='pers')
class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers') class Favor(Base): __tablename__ = 'favor' nid = Column(Integer, primary_key=True) caption = Column(String(50), default='red', unique=True) # Person表里写的:backref='pers',至关于在这里加上字段pers。只是用于查询,不会修改表结构。 # pers = 。。。。。。。。 def __repr__(self): return "%s-%s" %(self.nid, self.caption)
你能够直接经过Favor对象的pers字段找到跟这个颜色关联的全部person。
在数据库里没有真实的字段对应的,只是帮你生成sql语句而已。
# 新方式,反向查询 obj = session.query(Favor).filter(Favor.caption=='blue').first() # 先找到caption为blue的Favor对象 print(obj.nid) print(obj.caption) print(obj.pers) ''' 打印结果: 2 blue [<__main__.Person object at 0x0000000003B5BBE0>, <__main__.Person object at 0x0000000003B5BC50>] '''
3)总结
Foreignkey和relationship要成对写在一个表里。
class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers')
Person对Favor 是多对一的关系,foreignkey加在了多的那端(Person表)。
Person对象.favor.favor的字段:叫作正向查找
Favor对象.pers.person的字段:反向查找
咱们经过写个类来建立表。
两个步骤:
1)把这个类转为table对象。
2)根据这个table对象生成sql语句(create table。。。)。
一个类就是一张表。
用对象来建立表也能够,可是都不这么用。
class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers')
#!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'WangQiaomei' from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/s13", max_overflow=5) Base = declarative_base() # 主机 class Host(Base): __tablename__ = 'host' nid = Column(Integer,primary_key=True,autoincrement=True) hostname = Column(String(32)) port = Column(String(32)) ip = Column(String(32)) # 主机上的用户 class HostUser(Base): __tablename__ = 'host_user' nid = Column(Integer,primary_key=True,autoincrement=True) username = Column(String(32)) # 多对多表 class HostToHostUser(Base): __tablename__ = 'host_to_host_user' nid = Column(Integer,primary_key=True,autoincrement=True) host_id = Column(Integer,ForeignKey('host.nid')) host_user_id = Column(Integer,ForeignKey('host_user.nid')) def init_db(): Base.metadata.create_all(engine) def drop_db(): Base.metadata.drop_all(engine) # init_db() Session = sessionmaker(bind=engine) session = Session() session.add_all([ Host(hostname="c1",port="22",ip="1.1.1.1"), Host(hostname="c2",port="22",ip="1.1.1.2"), Host(hostname="c3",port="22",ip="1.1.1.3"), Host(hostname="c4",port="22",ip="1.1.1.4"), Host(hostname="c5",port="22",ip="1.1.1.5"), ]) session.add_all([ HostUser(username="root"), HostUser(username="db"), HostUser(username="nb"), HostUser(username="sb"), ]) session.commit() session.add_all([ HostToHostUser(host_id=1,host_user_id=1), HostToHostUser(host_id=1,host_user_id=2), HostToHostUser(host_id=1,host_user_id=3), HostToHostUser(host_id=2,host_user_id=2), HostToHostUser(host_id=2,host_user_id=4), HostToHostUser(host_id=2,host_user_id=3), ]) session.commit()
主机: 1 c1 2 c2 3 c3 服务器用户: 1 root 2 nb 3 db 4 sb 关系表 nid 主机ID 服务器ID 1 1 1 2 1 3 2 2 2 4 。。。。。。。。。。。。 约束:外键
1) 传统方式
若是咱们想查:主机c1上有几个用户。
经过传统的方式应该:
1)经过主机表:找到c1对应的主机id。
2)经过第三张关联表查询:主机id对应的几个用户id。
3)经过用户表:找到这些用户id,对应的用户名。
# 需求来了。。。
# 获取主机c1的全部的用户
# 需求来了。。。 # 获取主机c1的全部的用户 # 1 获取c1主机对象 host_obj = session.query(Host).filter(Host.hostname=='c1').first() # host_obj.nid # 咱们只取映射,不取对象。若是取的是对象,还得循环对象列表,而后取出全部的nid。 # 2 跟c1关联的全部用户id host_2_host_user=session.query(HostToHostUser.nid).filter(HostToHostUser.host_id == host_obj.nid).all() print(host_2_host_user) # 打印:[(1,), (2,), (3,)] # 咱们拿到的是用户id,是个集合。接下来要找集合下任意一个的全部用户。应该用in操做 # 3 获取用户名 users = session.query(HostUser.username).filter(HostUser.nid.in_([1,2])).all() # 这样把id为1,2的全部用户都拿到了。 print(users) # [('root',), ('db',)] # 咱们怎样把[(1,), (2,), (3,)] 转换为 [1,2,3],用zip r=zip(*host_2_host_user) print(r) # print(list(r)[0]) # [(1, 2, 3)] ==> (1, 2, 3) # 元组或列表放在这里均可以 users = session.query(HostUser.username).filter(HostUser.nid.in_(list(r)[0])).all() # list(r)[0] 这个zip对象是迭代器,取一次就没了。 print(users) # [('root',), ('db',), ('nb',)] 获取了主机c1的全部的用户
2) 新方式1
host和HostUser是两张表,HostToHostUser是第三张表,是多对多关系表。
这个第三张表都有foreignkey关联着这两张表。
Host 和HostToHostUser是一对多的关系
HostUser和HostToHostUser是一对多的关系
两个一对多就变成多对多了。
因此咱们能够把relationship在HostToHostUser这张表里写一遍。
添加下面两行:
# 多对多表 class HostToHostUser(Base): __tablename__ = 'host_to_host_user' nid = Column(Integer,primary_key=True,autoincrement=True) host_id = Column(Integer,ForeignKey('host.nid')) host_user_id = Column(Integer,ForeignKey('host_user.nid')) host = relationship("Host",backref="h") host_user = relationship("HostUser",backref="u")
# 新方式
host_obj=session.query(Host).filter(Host.hostname=='c1').first() print(host_obj.nid) print(host_obj.hostname) # 主机c1对应的第三张表的对象(经过反查) # [<__main__.HostToHostUser object at 0x0000000003CBB470>, <__main__.HostToHostUser object at 0x0000000003CBB438>, # <__main__.HostToHostUser object at 0x0000000003CBB5F8>] print(host_obj.h) # 由于foreignkey写在第三张表上,因此主机或用户表来查第三张表就是反查,若是是第三张表查主机或用户就是正向查找。 # 循环获取第三张表的对象 for item in host_obj.h: print(item.host_user.username) ''' 打印: root db nb '''
多对多最终推荐方式:
A 关系(B,AB.__table__) AB ==> fk, B
AB.__table__就表示第三张表的对象。
更改方式:
1)把HostToHostUser类放在Host前面
2)去掉HostToHostUser的全部relationship
3)Host表加上relationship,关联HostUser表和第三张表的对象
# 多对多表 class HostToHostUser(Base): __tablename__ = 'host_to_host_user' nid = Column(Integer,primary_key=True,autoincrement=True) host_id = Column(Integer,ForeignKey('host.nid')) host_user_id = Column(Integer,ForeignKey('host_user.nid')) # 主机 class Host(Base): __tablename__ = 'host' nid = Column(Integer,primary_key=True,autoincrement=True) hostname = Column(String(32)) port = Column(String(32)) ip = Column(String(32)) host_user = relationship("HostUser", secondary=HostToHostUser.__table__, backref="h")
多对多就很是简单了:
host_obj=session.query(Host).filter(Host.hostname=='c1').first() print(host_obj.host_user) ''' 打印结果:找到了c1全部关联的主机用户名 [<__main__.HostUser object at 0x0000000003B18C50>, <__main__.HostUser object at 0x0000000003B18940>, <__main__.HostUser object at 0x0000000003B18BA8>] '''