多表查询
union
union:去掉了一份重复
合并查询结果 利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并 时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION ALL关键字分隔。
语法格式:
SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2
UNION 操作符返回两个查询的结果集的并集,去除重复记录。
union all
union all:没有去掉一份重复
UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。
能用union all 尽量用union all,效率更高。
执行UNION ALL语句时所需要的资源比UNION语句少。如果明确知道合并数据后的结果数据 不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效率。
HAVING
过滤分组:HAVING子句
-
行已经被分组。
-
使用了聚合函数。
-
满足HAVING 子句中条件的分组将被显示。
-
HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary)>10000 ;
WHERE和HAVING的对比
区别1:WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件; HAVING 必须要与 GROUP BY 配合使用,可以把分组计算的函数和分组字段作为筛选条件。 这决定了,在需要对数据进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。这是因为, 在查询语法结构中,WHERE 在 GROUP BY 之前,所以无法对分组结果进行筛选。HAVING 在 GROUP BY 之 后,可以使用分组字段和分组中的计算函数,对分组的结果集进行筛选,这个功能是 WHERE 无法完成 的。另外,WHERE排除的记录不再包括在分组中。
区别2:如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接 后筛选。 这一点,就决定了在关联查询中,WHERE 比 HAVING 更高效。因为 WHERE 可以先筛选,用一 个筛选后的较小数据集和关联表进行连接,这样占用的资源比较少,执行效率也比较高。HAVING 则需要 先把结果集准备好,也就是用未被筛选的数据集进行关联,然后对这个大的数据集进行筛选,这样占用 的资源就比较多,执行效率也较低。
开发中的选择:
WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。包含分组 统计函数的条件用 HAVING,普通条件用 WHERE。这样,我们就既利用了 WHERE 条件的高效快速,又发 挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。当数据量特别大的时候,运行效率会有很 大的差别。
SELECT的执行过程
#方式1:
SELECT ...,....,...
FROM ...,...,....
WHERE 多表的连接条件
AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC LIMIT ...,...
#方式2:
SELECT ...,....,...
FROM ... JOIN ...
ON 多表的连接条件
JOIN ...
ON ...
WHERE 不包含组函数的过滤条件
AND/OR 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...
#其中:
#(1)from:从哪些表中筛选
#(2)on:关联多表查询时,去除笛卡尔积
#(3)where:从表中筛选的条件
#(4)group by:分组依据
#(5)having:在统计结果中再次筛选
#(6)order by:排序
#(7)limit:分页
需要记住 SELECT 查询时的两个顺序:
1.关键字的顺序是不能颠倒的:
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT...
2.SELECT 语句的执行顺序(在 MySQL 和 Oracle 中,SELECT 执行顺序基本相同):
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的字段 -> DISTINCT -> ORDER BY -> LIMIT
比如写了一个 SQL 语句,那么它的关键字顺序和执行顺序是下面这样的:
SELECT DISTINCT player_id, player_name, count(*) as num # 顺序 5
FROM player JOIN team ON player.team_id = team.team_id # 顺序 1
WHERE height > 1.80 # 顺序 2
GROUP BY player.team_id # 顺序 3
HAVING num > 2 # 顺序 4
ORDER BY num DESC # 顺序 6
LIMIT 2 # 顺序 7
在 SELECT 语句执行这些步骤的时候,每个步骤都会产生一个 虚拟表 ,然后将这个虚拟表传入下一个步 骤中作为输入。需要注意的是,这些步骤隐含在 SQL 的执行过程中,对于我们来说是不可见的。
索引
类型:B树、B+树、R树(空间数据库索引)
MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度。
打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。
拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。
索引分单列索引和组合索引。单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。组合索引,即一个索引包含多个列。
创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
索引口诀
回忆一下索引的几句口诀 摘自周阳老师的mysql高级课程
全值匹配我最爱,最左前缀要遵守
带头大哥不能死,中间兄弟不能断
索引列上少计算,范围之后全失效
LIKE符号写最右,覆盖索引不写星
不等空值还有or,索引失效要少用
var引号不能丢,SQL高级也不难
分组之前必排序,一定要上索引啊
普通索引
创建索引
这是最基本的索引,它没有任何限制。它有以下几种创建方式:
CREATE INDEX indexName ON table_name (column_name)
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。
修改表结构(添加索引)
ALTER table tableName ADD INDEX indexName(columnName)
创建表的时候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);
删除索引的语法
DROP INDEX [indexName] ON mytable;
唯一索引
它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
创建索引
CREATE UNIQUE INDEX indexName ON mytable(username(length))
修改表结构
ALTER table mytable ADD UNIQUE [indexName] (username(length))
创建表的时候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
UNIQUE [indexName] (username(length))
);
使用ALTER 命令添加和删除索引
有四种方式来添加数据表的索引:
-
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list):
该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
-
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
-
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
-
**ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):**该语句指定了索引为 FULLTEXT ,用于全文索引。
以下实例为在表中添加索引。
mysql> ALTER TABLE testalter_tbl ADD INDEX (c);
你还可以在 ALTER 命令中使用 DROP 子句来删除索引。尝试以下实例删除索引:
mysql> ALTER TABLE testalter_tbl DROP INDEX c;
使用 ALTER 命令添加和删除主键
主键作用于列上(可以一个列或多个列联合主键),添加主键索引时,你需要确保该主键默认不为空(NOT NULL)。实例如下:
mysql> ALTER TABLE testalter_tbl MODIFY i INT NOT NULL;
mysql> ALTER TABLE testalter_tbl ADD PRIMARY KEY (i);
你也可以使用 ALTER 命令删除主键:
mysql> ALTER TABLE testalter_tbl DROP PRIMARY KEY;
删除主键时只需指定PRIMARY KEY,但在删除索引时,你必须知道索引名。
显示索引信息
你可以使用 SHOW INDEX 命令来列出表中的相关的索引信息。可以通过添加 \G 来格式化输出信息。
尝试以下实例:
mysql> SHOW INDEX FROM table_name\G
........
建议按照如下的原则来创建索引:
- 当唯一性是某种数据本身的特征时,指定唯一索引。使用唯一索引需能确保定义的列的数据完整性,以提高查询速度。
- 在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引,如果待排序的列有多个,可以在这些列上建立组合索引。
下列几种情况,是不适合创建索引的:
- 频繁更新的字段不适合建立索引;
- where条件中用不到的字段不适合建立索引;
- 数据比较少的表不需要建索引;
- 数据重复且分布比较均匀的的字段不适合建索引,例如性别、真假值;
- 参与列计算的列不适合建索引。
该如何优化MySQL的查询?
参考答案
使用索引:
如果查询时没有使用索引,查询语句将扫描表中的所有记录。在数据量大的情况下,这样查询的速度会很慢。如果使用索引进行查询,查询语句可以根据索引快速定位到待查询记录,从而减少查询的记录数,达到提高查询速度的目的。
索引可以提高查询的速度,但并不是使用带有索引的字段查询时索引都会起作用。有几种特殊情况,在这些情况下有可能使用带有索引的字段查询时索引并没有起作用。
-
使用LIKE关键字的查询语句
在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引不会起作用。只有“%”不在第一个位置,索引才会起作用。
-
使用多列索引的查询语句
MySQL可以为多个字段创建索引。一个索引可以包括16个字段。对于多列索引,只有查询条件中使用了这些字段中的第1个字段时索引才会被使用。
-
使用OR关键字的查询语句
查询语句的查询条件中只有OR关键字,且OR前后的两个条件中的列都是索引时,查询中才使用索引。否则,查询将不使用索引。
优化子查询:
使用子查询可以进行SELECT语句的嵌套查询,即一个SELECT查询的结果作为另一个SELECT语句的条件。子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作。
子查询虽然可以使查询语句很灵活,但执行效率不高。执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就会随之增大。
在MySQL中,可以使用连接(JOIN)查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用索引,性能会更好。
联合主键
联合主键就是用2个或2个以上的字段组成主键。用这个主键包含的字段作为主键,这个组合在数据表中是唯一,且加了主键索引。 可以这么理解,比如,你的订单表里有很多字段,一般情况只要有个订单号bill_no做主键就可以了,但是,现在要求可能会有补充订单,使用相同的订单号,那么这时单独使用订单号就不可以了,因为会有重复。那么你可以再使用个订单序列号bill_seq来 作为区别。把bill_no和bill_seq设成联合主键。 即使bill_no相同,bill_seq不同也是可以的。 alter table 表 add constraint pk_name primary key (列1,列2,…)
联合主键的好处是不需要因为需要主键而增加一个无用的主键列
例如如果不用联合主键你必须增加个列ID设置主键
但这个ID列 无任何作用 至于在什么情况下使用,就像刚才举例的,当你这个表的主键ID无任何用处,那么就用联合主键好了,你可以节约 一个列的空间,但如果这表的ID列要做为别的表的外键的话,就不能用联合主键了。联合主键就是确定一条记录的唯一性啊 比如这种时候 商品品牌 商品型号 诺基亚 920 三星 NOTE2 诺基亚 8088 比如这样商品品牌可能有重复,都是诺基亚,但是诺基亚厂商生产的商品型号是不会重复的 也比如,可能好多品牌都有920这个型号,但是一个品牌只有一个920的型号 所以就靠这样的联合主键来确定这条记录的唯一性 建立方法如下 create table product( pro_name varchar(20), pro_type varchar(20), primary key (pro_name,pro_type) );
数据库不要外键的好处
**数据库设计:**三范式
添加外键的好处:数据更加完整,表结构更加清晰
去除外键的好处:
- 提高性能 (在进行插入,删除,更新时候数据库需要先检查数据完整性)
- 方便旧的数据的导入
大学时上数据库的课程,学的三个范式中有个第三范式就是专指的外键约束。可是出来工作以后第一次做数据库表设计的时候,组长大佬却让我在数据库中不要使用外键,改在代码中做相应处理。说得专业点,就是不要在数据库中使用物理外键,改为使用逻辑外键,即在代码中写相关的逻辑代替外键所起的作用。我从此便懂得了,解决实际的问题要从实际出发,不能照本宣科。
外键的作用
1.外键能保证数据的完整性。在没有外键的情况下,数据库就不能强制进行引用完整性检查,如果在高一层没有进行正确的处理,则可能会导致数据出现不一致的情况。
2.外键能使表之间的关系变得清晰。如果数据库中缺少外键,不了解表之间关系的人很难找到正确的关联表,这样可能会导致严重的数据库查询问题(关联错表、查错表)。
为什么数据库可以没有外键
既然外键有那么多好处,为什么这里说设计数据库的时候可以不要外键呢,想作死嘛?但是世事无绝对的,这个世界也不是非黑即白的,很多时候人生只能随波逐流,跟着环境改变。意思就是说,数据库设计还是要根据实际情况,其实有7个理由可以说明为什么数据库可以没有外键。
1.提高性能
在表上拥有活动的外键可以提高数据的质量,但是会影响插入、更新和删除操作的性能。因为在这些操作任务之前,数据库需要检查它是否违反数据完整性。这就是为什么一些架构师和DBA完全放弃外键的原因。数据仓库和分析数据库尤其如此,这些数据仓库和分析数据库不以业务方法(一次一行)处理数据,而是批量处理数据。性能是数据仓库和商业智能的一切。
2.方便旧数据的导入
许多数据库在设计的时候需要考虑导入来自旧数据库的数据的因素。这些数据可能对数据的质量和完整性没有那么严格,为了能够容纳旧的脏数据,架构师有两个选择,一是清理和转换旧的历史遗留数据(昂贵代价,需要人工去编制数据);二是放弃在数据库级别上强制执行参照完整性。哪个方法更好更节约成本更高效,我相信已经不言而喻了。
3.方便全表的重新加载
一些数据库,如数据仓库,分段或接口数据库,需要经常从外部重新加载数据。就像你本地的测试数据库需要从生产环境的正式数据库重新加载数据一样。这可能会导致重新加载数据时数据不一致(在父表为空的情况下,子表可能已经装满)。虽然可以通过在重新加载数据的时候禁用外键来绕过这个问题,然而这却引入了额外的逻辑和复杂性,以及另一个失败点,对性能有负面影响。
4.将外键起的作用交给更高层次的框架完成
一些应用程序使用编程框架,在物理数据库之上创建另一个逻辑层,开发人员不需要编写插入或更新语句来修改数据,而是调用提供的API在后台执行所有操作。ORM(对象关系映射)框架比如Hibernate就是这种情况,这些框架负责维护参照完整性,并与RDBMS一起创建更高级别的数据库引擎。
5.方便跨数据库
在一些大型系统,可能会有很多个数据库。比如说A表在A数据库,B表在B数据库,你想在A表和B表之间创建外键是不可能的。当然你可能会说A表和B表要创建外键就把A表和B表放在一个数据库里面啊,但是我偏不,嘿嘿。
6.节约一些工作成本(偷懒/提高效率)
在创建数据库的时候,如果要存储数据,最低限度是要创建一些表和一些字段。但是创建一些保证数据一致性的结构却不是必须的工作,比如外键等约束。这些工作需要人力和时间成本,但是却没有带来直接的好处。因此很多架构师和DBA都选择忽略掉这一部分。
7.让你在团队里变得不可替代
在现实的社会中,很多人都希望被需要和不可被替代。如果数据库表的设计者是你且只有你,那么表之间的关系就只有你知道,别人要知道表之间的关系就只能通过你,你就变成了不可替代的那个人了。当然在现实中是不可能的,数据库设计都是要留存的,比如说PDM;你也不可能成为不被替代的那个人。没有错,现实就是那么残酷。
"世界上没有谁是不可替代的,一个人离开了,马上就会有另外一个人取代他的位置。"
子查询
不相关子查询
相关子查询
内查询跟外查询有关系
范式
关键字函数
ROW_NUMBER() OVER()用法
row_number() over()分组排序功能: 在使用 row_number() over()函数时候,over()里头的分组以及排序的执行晚于 where 、group by、 order by 的执行。
语法格式:row_number() over(partition by 分组列 order by 排序列 desc)
CASE用法
使用case分组会对单个字段做类似switch case的情况处理,处理单个字段的不同情况,进行人为分组
#可以在where中使用
case 字段名
when 属性值1 then 被归类属性
when 属性值2 then 被归类属性
else 其他被归类属性
end
select stock_name ,sum(case when operation='Sell' then price else -price end) capital_gain_loss
from Stocks
group by stock_name
select stock_name ,sum(case operation when 'Sell' then price else -price end) capital_gain_loss
from Stocks
group by stock_name
substr()
SUBSTR(string ,pos,len)
string:指定字符串
pos:规定字符串从何处开始,(这里的第一个位置是1而不是0)为正数时则从字段开始出开始,为负数则从结尾出开始。
len:要截取字符串的长度。(是从1开始计数而不是0)
CAST
将给定表达式转换为指定数据类型的函数
CAST(expr AS CHAR | CHARACTER | VARCHAR | NCHAR | NVARCHAR)
CAST(expr AS CHAR(n) | CHARACTER(n) | VARCHAR(n) )
CAST(expr AS CHAR VARYING | CHARACTER VARYING)
CAST(expr AS INT | INTEGER | BIGINT | SMALLINT | TINYINT)
CAST(expr AS DEC | DECIMAL | NUMERIC)
CAST(expr AS DEC(p[,s]) | DECIMAL(p[,s]) | NUMERIC(p[,s]) )
CAST(expr AS DOUBLE)
CAST(expr AS MONEY | SMALLMONEY)
CAST(expr AS DATE)
CAST(expr AS TIME)
CAST(expr AS POSIXTIME)
CAST(expr AS TIMESTAMP | DATETIME | SMALLDATETIME)
CAST(expr AS BIT)
CAST(expr AS BINARY | BINARY VARYING | VARBINARY)
CAST(expr AS BINARY(n) | BINARY VARYING(n) | VARBINARY(n) )
CAST(expr AS GUID)
参数
expr - SQL表达式,通常是表的文字或数据字段。
n - 一个整数,指示要返回的最大字符数。
如果n小于expr数据,返回的数据将被截断为n个字符。
如果n大于expr数据,则不执行填充。
p,s - 可选 - p=精度(最大总位数),整数形式。
s=刻度(十进制数字的最大值),用整数表示。
如果未指定比例,则默认为15。
SQL CAST函数将表达式的数据类型转换为指定的数据类型。当Expr的数据类型是标准数据类型或标准数据类型(如%Library.String、%Library.Time、%Library.Date或%Library.TimeStamp)的子类时,CAST可以转换该数据类型。
right()函数
返回最右边的len个字符的字符串str
SELECT RIGHT('foobarbar', 4)
结果:rbar
将'2012-11-23-010-B-02' 转为 '2012-11-23-010-B-01'
select right('00'+(convert(nvarchar(2),SUBSTRING('2012-11-23-010-B-02',LEN('2012-11-23-010-B-02')-1,2)-1)),2)
LEFT(str, length) 函数
从左开始截取字符串,length 是截取的长度。
UPPER(str) 与 LOWER(str)
UPPER(str) 将字符串中所有字符转为大写
LOWER(str) 将字符串中所有字符转为小写
mod的的用法
Mod(a,b) 在sql中的意思是 a / b 的余数
基础用法:如果id需要是偶数或者奇数时就可以使用mod。
mod(id,2)=1 是指id是奇数。
mod(id,2)=0 是指id是偶数
CONCAT() 函数
CONCAT 可以将多个字符串拼接在一起。
SUBSTRING(str, begin, end) 截取字符串,end 不写默认为空。
SUBSTRING(name, 2) 从第二个截取到末尾,注意并不是下标,就是第二个。
SUBSTRING(str, begin, end)
截取字符串,end 不写默认为空。
SUBSTRING(name, 2) 从第二个截取到末尾,注意并不是下标,就是第二个。
if
IF第一个参数写条件,第二个参数写条件成立返回的内容,第三个参数写条件不成立返回的内容
SELECT employee_id, IF(MOD(employee_id,2)!=0 AND LEFT(name,1)!='M',salary,0) bonus FROM Employees ORDER BY employee_id
ifnull
IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。
IFNULL(expression, alt_value)
GROUP_CONCAT
mysql 中 group_concat() 函数 完整语法
group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符'])
执行如下sql 语句:
SELECT id,GROUP_CONCAT(score) from score GROUP BY id;
SELECT id,GROUP_CONCAT(DISTINCT score) from score GROUP BY id;
SELECT id,GROUP_CONCAT(DISTINCT score ORDER BY score DESC) from score GROUP BY id;
SELECT id,GROUP_CONCAT(DISTINCT score ORDER BY score DESC SEPARATOR ";") from score GROUP BY id;
dateDiff
MySQL 使用 DATEDIFF 来比较两个日期类型的值,两个日期的差值;
DATEDIFF(weather.date, w.date)
select a.Id from Weather as a join Weather as b on a.Temperature > b.Temperature and dateDiff(a.RecordDate,b.RecordDate) = 1
||
||表示拼接,如'a'||'b' 等价于'ab'
to_date()
格式转换
日期例子:
SELECT TO_DATE('2006-05-01 19:25:34', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL
SELECT TO_DATE('2006-05-01 19:25', 'YYYY-MM-DD HH24:MI') FROM DUAL
SELECT TO_DATE('2006-05-01 19', 'YYYY-MM-DD HH24') FROM DUAL
SELECT TO_DATE('2006-05-01', 'YYYY-MM-DD') FROM DUAL
SELECT TO_DATE('2006-05', 'YYYY-MM') FROM DUAL
SELECT TO_DATE('2006', 'YYYY') FROM DUAL
日期格式
格式控制 描述
YYYY、YYY、YY 分别代表4位、3位、2位的数字年
YEAR 年的拼写
MM 数字月
MONTH 月的全拼
MON 月的缩写
DD 数字日
DAY 星期的全拼
DY 星期的缩写
AM 表示上午或者下午
HH24、HH12 12小时制或24小时制
MI 分钟
SS 秒钟
SP 数字的拼写
TH 数字的序数词
group_concat
如果我们希望按分数score进行分组,并将分组后的学生姓名打印下来,就可以用group_concat实现。执行sql:
select score,group_concat(student) from exam group by score;
|score |group_concat(student) |
-------------------------------------
|70 |小王,小赵,小高,小高,小秦 |
|80 |小红,小李,小孙,小秦,小马 |
|90 |小张,小钱,小马,小朱,小朱,小钱 |
不难看出,在70分这一行有两条小高的记录,90分这一行有两条小钱和小朱的记录,如果我们需要去重,则需要给函数中加一个distinct参数:
select score,group_concat(distinct student) from exam group by score;
执行结果为:
|score |group_concat(student) |
-------------------------------------
|70 |小王,小赵,小高,小秦 |
|80 |小红,小李,小孙,小秦,小马 |
|90 |小张,小钱,小马,小朱 |
这样group_concat每行数据的结果中就没有了重复值,但是在数据中的分隔符为默认的逗号',',如果想修改默认的分隔符,只需要在上述指令中稍作修改:
select score,group_concat(distinct student separator '%') from exam group by score;
执行结果:
|score |group_concat(student) |
-------------------------------------
|70 |小王%小秦%小赵%小高 |
|80 |小孙%小李%小秦%小红%小马 |
|90 |小张%小朱%小钱%小马 |
now()获取当前时间
now() 函数能获得当前的日期时间外,MySQL 中还有下面的函数:
current_timestamp() current_timestamp
localtime() localtime
localtimestamp() localtimestamp
这些日期时间函数,都等同于 now()。鉴于 now() 函数简短易记,建议总是使用 now() 来替代上面列出的函数。
mysql隔离级别
mysql默认隔离级别是可重复读,要读到至少提交了的数据
下面的命令将当前会话设置为读未提交,可以读到没有提交的数据,方便事务调试时查看数据库变化
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;