mysql sql语句

示例:

三张表, posts, tags, posts_tags, 

posts ---M:N--- tags

多对多, posts_tags为中间表

mysql> select * from posts;
+----+-------+
| id | title |
+----+-------+
| 1 | post1 |
| 2 | post2 |
| 3 | post3 |
| 4 | post4 |
+----+-------+

 

mysql> select * from tags;
+----+----------+
| id | tag_name |
+----+----------+
| 1 | java |
| 2 | mysql |
| 3 | python |
+----+----------+

 

mysql> select * from posts_tags;
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 3 |
| 3 | 2 |
+---------+--------+

 

1. select

   select [ distinct ] column1, column2...

   from table1, table2...

   where condition

   group by col_name

   having condition

   order by col_name [asc | desc]

   limit {[offset,] row_count | row_count OFFSET offset}]

 

 a.  group by

mysql> select * from posts p, tags t, posts_tags pt where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysql');
+----+-------+----+----------+---------+--------+
| id | title | id | tag_name | post_id | tag_id |
+----+-------+----+----------+---------+--------+
| 1 | post1 | 1 | java | 1 | 1 |
| 1 | post1 | 2 | mysql | 1 | 2 |
| 3 | post3 | 2 | mysql | 3 | 2 |
| 1 | post1 | 3 | python | 1 | 3 |
| 2 | post2 | 3 | python | 2 | 3 |
+----+-------+----+----------+---------+--------+
5 rows in set (0.00 sec)

 

select * from posts p, tags t, posts_tags pt
where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysql')
group by p.id

注意, 如果select中指明了group by 的字段,则除了group by column这个字段之外,别的columns必须在聚合函数中,不然会出错:

mysql> select p.id, * from posts p, tags t, posts_tags pt where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysql')grou
p by p.id;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use n
ear '* from posts p, tags t, posts_tags pt where p.id = pt.post_id and t.id = pt.tag_' at line 1
mysql>

 

mysql> select p.id, count(*) from posts p, tags t, posts_tags pt where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysq
l')group by p.id;
+----+----------+
| id | count(*) |
+----+----------+
| 1 | 3 |
| 2 | 1 |
| 3 | 1 |
+----+----------+
3 rows in set (0.00 sec)

 

mysql> select p.id, count(*) from posts p, tags t, posts_tags pt where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysq
l')group by p.id having count(*) >0;
+----+----------+
| id | count(*) |
+----+----------+
| 1 | 3 |
| 2 | 1 |
| 3 | 1 |
+----+----------+
3 rows in set (0.00 sec)

 

 

+----+-------+----+----------+---------+--------+
| id | title | id | tag_name | post_id | tag_id |
+----+-------+----+----------+---------+--------+
| 1 | post1 | 1 | java | 1 | 1 |
| 2 | post2 | 3 | python | 2 | 3 |
| 3 | post3 | 2 | mysql | 3 | 2 |
+----+-------+----+----------+---------+--------+
3 rows in set (0.00 sec)

当用group by p.id时, p.id为1的三行数据就只显示第一行了,尽管别的字段不同

 

mysql> select * from posts p, tags t, posts_tags pt
-> where p.id = pt.post_id and t.id = pt.tag_id and t.tag_name in ('java','python','mysql')
-> group by p.id having count(*) =3;
+----+-------+----+----------+---------+--------+
| id | title | id | tag_name | post_id | tag_id |
+----+-------+----+----------+---------+--------+
| 1 | post1 | 1 | java | 1 | 1 |
+----+-------+----+----------+---------+--------+
1 row in set (0.00 sec)

用having 来获取有三个标签的文章

 

 b.  limit

     后跟一个数字,是 row_count , 如果是两个数字, 是offset, row_count , 就是获取第offset+1 之后的 row_count行数据

     SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

    

mysql> select * from tags;
+----+----------+
| id | tag_name |
+----+----------+
| 1 | java |
| 2 | mysql |
| 3 | python |
+----+----------+
3 rows in set (0.00 sec)

mysql> select * from tags limit 1;
+----+----------+
| id | tag_name |
+----+----------+
| 1 | java |
+----+----------+
1 row in set (0.00 sec)

mysql> select * from tags limit 1, 1;
+----+----------+
| id | tag_name |
+----+----------+
| 2 | mysql |
+----+----------+
1 row in set (0.00 sec)

mysql> select * from tags limit 1, 2;
+----+----------+
| id | tag_name |
+----+----------+
| 2 | mysql |
| 3 | python |
+----+----------+
2 rows in set (0.00 sec)

 

 

mysql行转列转换

mysql 行列转换 ,在项目中应用的极其频繁,尤其是一些金融项目里的报表。其中最为头痛的就是多行转多列,动态的列行转换。最近在研究这些行里转换,还是从最为简单的行列转换开始。

sql 脚本


-- 创建表  学生表
CREATE TABLE `student` (
    `stuid` VARCHAR(16) NOT NULL COMMENT '学号',
    `stunm` VARCHAR(20) NOT NULL COMMENT '学生姓名',
    PRIMARY KEY (`stuid`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB; 


-- 课程表 

CREATE TABLE `courses` (
    `courseno` VARCHAR(20) NOT NULL,
    `coursenm` VARCHAR(100) NOT NULL,
    PRIMARY KEY (`courseno`)
)
COMMENT='课程表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;


-- 成绩表
CREATE TABLE `score` (
    `stuid` VARCHAR(16) NOT NULL,
    `courseno` VARCHAR(20) NOT NULL,
    `scores` FLOAT NULL DEFAULT NULL,
    PRIMARY KEY (`stuid`, `courseno`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

-- 插入数据

-- 学生表数据

Insert Into student (stuid, stunm) Values('1001', '张三');
Insert Into student (stuid, stunm) Values('1002', '李四');
Insert Into student (stuid, stunm) Values('1003', '赵二');
Insert Into student (stuid, stunm) Values('1004', '王五');
Insert Into student (stuid, stunm) Values('1005', '刘青');
Insert Into student (stuid, stunm) Values('1006', '周明');

-- 课程表数据 
Insert Into courses (courseno, coursenm) Values('C001', '大学语文');
Insert Into courses (courseno, coursenm) Values('C002', '新视野英语');
Insert Into courses (courseno, coursenm) Values('C003', '离散数学');
Insert Into courses (courseno, coursenm) Values('C004', '概率论与数理统计');
Insert Into courses (courseno, coursenm) Values('C005', '线性代数');
Insert Into courses (courseno, coursenm) Values('C006', '高等数学(一)');
Insert Into courses (courseno, coursenm) Values('C007', '高等数学(二)');

-- 成绩表数据

Insert Into score(stuid, courseno, scores) Values('1001', 'C001', 67);
Insert Into score(stuid, courseno, scores) Values('1002', 'C001', 68);
Insert Into score(stuid, courseno, scores) Values('1003', 'C001', 69);
Insert Into score(stuid, courseno, scores) Values('1004', 'C001', 70);
Insert Into score(stuid, courseno, scores) Values('1005', 'C001', 71);
Insert Into score(stuid, courseno, scores) Values('1006', 'C001', 72);
Insert Into score(stuid, courseno, scores) Values('1001', 'C002', 87);
Insert Into score(stuid, courseno, scores) Values('1002', 'C002', 88);
Insert Into score(stuid, courseno, scores) Values('1003', 'C002', 89);
Insert Into score(stuid, courseno, scores) Values('1004', 'C002', 90);
Insert Into score(stuid, courseno, scores) Values('1005', 'C002', 91);
Insert Into score(stuid, courseno, scores) Values('1006', 'C002', 92);
Insert Into score(stuid, courseno, scores) Values('1001', 'C003', 83);
Insert Into score(stuid, courseno, scores) Values('1002', 'C003', 84);
Insert Into score(stuid, courseno, scores) Values('1003', 'C003', 85);
Insert Into score(stuid, courseno, scores) Values('1004', 'C003', 86);
Insert Into score(stuid, courseno, scores) Values('1005', 'C003', 87);
Insert Into score(stuid, courseno, scores) Values('1006', 'C003', 88);
Insert Into score(stuid, courseno, scores) Values('1001', 'C004', 88);
Insert Into score(stuid, courseno, scores) Values('1002', 'C004', 89);
Insert Into score(stuid, courseno, scores) Values('1003', 'C004', 90);
Insert Into score(stuid, courseno, scores) Values('1004', 'C004', 91);
Insert Into score(stuid, courseno, scores) Values('1005', 'C004', 92);
Insert Into score(stuid, courseno, scores) Values('1006', 'C004', 93);
Insert Into score(stuid, courseno, scores) Values('1001', 'C005', 77);
Insert Into score(stuid, courseno, scores) Values('1002', 'C005', 78);
Insert Into score(stuid, courseno, scores) Values('1003', 'C005', 79);

-- 
select st.stuid,st.stunm  from student  st 

select sc.stuid , sc.courseno,sc.scores  from score sc 

select  cs.courseno,cs.coursenm   from courses cs

 

要求: 查询每个学生的 每门课程与每门成绩

 select   st.stuid ID ,  st.stunm 姓名, cs.coursenm 课程名 ,sc.scores 成绩     from  student st, score sc ,courses cs

where st.stuid = sc.stuid and sc.courseno = cs.courseno  

 

结果: 
这里写图片描述

这是4列27行

我们行转成列,ID对应姓名对应每门课程对应每门成绩

静态行专列

select st.stuid 编号, st.stunm 姓名 ,
Max(case c.coursenm when '大学语文' then s.scores else 0 end ) '大学语文',
max(case c.coursenm when '新视野英语' then IFNULL(s.scores,0)else 0 end) '新视野英语',
Max(case c.coursenm when '离散数学' then IFNULL(s.scores,0) ELSE 0 END) '离散数学',
MAX(case c.coursenm when '概率论与数理统计' then IFNULL(s.scores,0) else 0 end) '概率论与数理统计',
MAX(case c.coursenm  when '线性代数' then IFNULL(s.scores,0) else 0 END) '线性代数',
MAX(case c.coursenm when '高等数学(一)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(一)',
MAX(case c.coursenm when '高等数学(二)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(二)'
from  student st 
LEFT JOIN score s on st.stuid = s.stuid
LEFT JOIN courses c on c.courseno = s.courseno
GROUP BY st.stuid

再来看看 运行结果:

这里写图片描述

 

注意,这里必须加上max(比如Max(case c.coursenm when '大学语文' then s.scores else 0 end ) '大学语文',),因为如果不加分组,结果是这样的:

mysql> select st.stuid 编号, st.stunm 姓名,

(case c.coursenm when '大学语文' then s.scores else 0 end) '大学语文',

(case c.coursenm when '新视野英语' then IFNULL(s.scores,0)else 0 end) '新视野英语',

(case c.coursenm when '离散数学' then IFNULL(s.scores,0) ELSE 0 END) '离散数学',

(case c.coursenm when '概率论与数理统计' then IFNULL(s.scores,0) else 0 end) '概率论与数理统计',

(case c.coursenm when '线性代数' then IFNULL(s.scores,0) else 0 END) '线性代数',

(case c.coursenm when '高等数学(一)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(一)',

(case c.coursenm when '高等数学(二)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(二)' 

from student2 st

LEFT JOIN score s on st.stuid = s.stuid

LEFT JOIN courses c on c.courseno = s.courseno;

+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 编号 | 姓名 | 大学语文 | 新视野英语 | 离散数学 | 概率论与数理统计 | 线性代数 | 高等数学(一) | 高等数学(二) |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 1001 | 张三 | 67 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1001 | 张三 | 0 | 87 | 0 | 0 | 0 | 0 | 0 |
| 1001 | 张三 | 0 | 0 | 83 | 0 | 0 | 0 | 0 |
| 1001 | 张三 | 0 | 0 | 0 | 88 | 0 | 0 | 0 |
| 1001 | 张三 | 0 | 0 | 0 | 0 | 77 | 0 | 0 |
| 1002 | 李四 | 68 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1002 | 李四 | 0 | 88 | 0 | 0 | 0 | 0 | 0 |
| 1002 | 李四 | 0 | 0 | 84 | 0 | 0 | 0 | 0 |
| 1002 | 李四 | 0 | 0 | 0 | 89 | 0 | 0 | 0 |
| 1002 | 李四 | 0 | 0 | 0 | 0 | 78 | 0 | 0 |
| 1003 | 赵二 | 69 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1003 | 赵二 | 0 | 89 | 0 | 0 | 0 | 0 | 0 |
| 1003 | 赵二 | 0 | 0 | 85 | 0 | 0 | 0 | 0 |
| 1003 | 赵二 | 0 | 0 | 0 | 90 | 0 | 0 | 0 |
| 1003 | 赵二 | 0 | 0 | 0 | 0 | 79 | 0 | 0 |
| 1004 | 王五 | 70 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1004 | 王五 | 0 | 90 | 0 | 0 | 0 | 0 | 0 |
| 1004 | 王五 | 0 | 0 | 86 | 0 | 0 | 0 | 0 |
| 1004 | 王五 | 0 | 0 | 0 | 91 | 0 | 0 | 0 |
| 1005 | 刘青 | 71 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1005 | 刘青 | 0 | 91 | 0 | 0 | 0 | 0 | 0 |
| 1005 | 刘青 | 0 | 0 | 87 | 0 | 0 | 0 | 0 |
| 1005 | 刘青 | 0 | 0 | 0 | 92 | 0 | 0 | 0 |
| 1006 | 周明 | 72 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1006 | 周明 | 0 | 92 | 0 | 0 | 0 | 0 | 0 |
| 1006 | 周明 | 0 | 0 | 88 | 0 | 0 | 0 | 0 |
| 1006 | 周明 | 0 | 0 | 0 | 93 | 0 | 0 | 0 |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
27 rows in set (0.00 sec)

这样分组之后就变成了:

mysql> select st.stuid 编号, st.stunm 姓名,(case c.coursenm when '大学语文' then s.scores else 0 end) '大学语文',(case c.coursenm when '新视野英语' t
hen IFNULL(s.scores,0)else 0 end) '新视野英语',(case c.coursenm when '离散数学' then IFNULL(s.scores,0) ELSE 0 END) '离散数学',(case c.coursenm when '
概率论与数理统计' then IFNULL(s.scores,0) else 0 end) '概率论与数理统计',(case c.coursenm when '线性代数' then IFNULL(s.scores,0) else 0 END) '线性代
数',(case c.coursenm when '高等数学(一)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(一)',(case c.coursenm when '高等数学(二)' THEN IFNULL(s.scores,
0) else 0 end) '高等数学(二)'from student2 st LEFT JOIN score s on st.stuid = s.stuid LEFT JOIN courses c on c.courseno = s.courseno group by st.stui
d;
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 编号 | 姓名 | 大学语文 | 新视野英语 | 离散数学 | 概率论与数理统计 | 线性代数 | 高等数学(一) | 高等数学(二) |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 1001 | 张三 | 67 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1002 | 李四 | 68 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1003 | 赵二 | 69 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1004 | 王五 | 70 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1005 | 刘青 | 71 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1006 | 周明 | 72 | 0 | 0 | 0 | 0 | 0 | 0 |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
6 rows in set (0.06 sec)

mysql>

因为分组之后,同一个学生id只取一行数据,这时必须加上max函数,才能获得想要的数据。

mysql> select st.stuid 编号, st.stunm 姓名,max(case c.coursenm when '大学语文' then s.scores else 0 end) '大学语文',max(case c.coursenm when '新视野
英语' then IFNULL(s.scores,0)else 0 end) '新视野英语',max(case c.coursenm when '离散数学' then IFNULL(s.scores,0) ELSE 0 END) '离散数学',max(case c.co
ursenm when '概率论与数理统计' then IFNULL(s.scores,0) else 0 end) '概率论与数理统计',max(case c.coursenm when '线性代数' then IFNULL(s.scores,0) els
e 0 END) '线性代数',max(case c.coursenm when '高等数学(一)' THEN IFNULL(s.scores,0) else 0 end) '高等数学(一)',max(case c.coursenm when '高等数学(二)'
THEN IFNULL(s.scores,0) else 0 end) '高等数学(二)'from student2 st LEFT JOIN score s on st.stuid = s.stuid LEFT JOIN courses c on c.courseno = s.cou
rseno group by st.stuid;
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 编号 | 姓名 | 大学语文 | 新视野英语 | 离散数学 | 概率论与数理统计 | 线性代数 | 高等数学(一) | 高等数学(二) |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
| 1001 | 张三 | 67 | 87 | 83 | 88 | 77 | 0 | 0 |
| 1002 | 李四 | 68 | 88 | 84 | 89 | 78 | 0 | 0 |
| 1003 | 赵二 | 69 | 89 | 85 | 90 | 79 | 0 | 0 |
| 1004 | 王五 | 70 | 90 | 86 | 91 | 0 | 0 | 0 |
| 1005 | 刘青 | 71 | 91 | 87 | 92 | 0 | 0 | 0 |
| 1006 | 周明 | 72 | 92 | 88 | 93 | 0 | 0 | 0 |
+--------+--------+--------------+-----------------+--------------+--------------------------+--------------+-------------------+-------------------+
6 rows in set (0.08 sec)

mysql>

 

这就是实现了简单的行列

再来看看group_concat() 这个函数

group_concat(),手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果。 
比较抽象,难以理解。

通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一组,将属于同一组的列显示出来。要返回哪些列,由函

数参数(就是字段名)决定。分组必须有个标准,就是根据group by指定的列进行分组。

这些都是从网上看到的解释,但还是不好理解,我们直接上代码,看看run出来的结果,根据run之后的结果再回过来看!

select   s.stuid 编号 , GROUP_CONCAT(courseno) 课程号 , GROUP_CONCAT(s.scores)  成绩  from score s GROUP BY  s.stuid

看看运行后的结果: 
之前效果:

这里写图片描述

这里写图片描述

非常明显GROUP_CONCAT() 作用 ,将课程号courseno, 成绩 scores 的结果集放在一起。

posted @ 2018-01-15 15:34  alxe_yu  阅读(94)  评论(0)    收藏  举报