SQL结构化查询语言,是一种访问和处理数据库的计算机语言
mysql --version
mysql -u root -p
进入环境;exit
;-- 创建数据库
CREATE DATABASE grep_list;
-- 查看所有数据库
SHOW databases;
-- 切换数据库
USE grep_list;
-- 展示所有表
SHOW tables;
-- 删除表
DROP TABLE my_contacts;
命令大写 下划线分隔 结尾分号;字段名 使用单反引号包裹;小括号 指明 列名及数据类型等;
数据类型的选择很重要:
查看数据类型 及 某个类型:
help data types
help DATE
数据类型举例:
NULL:
DEFAULT:
doughnut_cost
DEC(3,2) NOT NULL DEFAULT 1.00插入数据:
INSERT INTO table ( columns, column1, … ) VALUES ( ‘values1’,1,… ),( ‘values2’,2,… );
-- 省略列名时 数据需要全部插入,且与表初创时列序相同;
INSERT INTO table VALUES (’values’, …);
查询数据:
SELECT * FROM table;
SELECT field1, field2 FROM table;
WHERE子句、AND、OR综合查询;
IS NULL:
LIKE+通配符:
%
也是一种通配符,是实际存在于该处的字符的替身;_
下划线是LIKE喜欢的第二个通配符:仅是一个未知字符的替身;可以连续使用多个;main LIKE '%juice_’ OR second LIKE '%juice%’;
IN:集合匹配
drink_name IN ('Blackthorn','Blue Moon','Oh My Gosh’);
drink_name NOT IN ('Blackthorn','Blue Moon','Oh My Gosh’);
NOT:
AND NOT second LIKE '%juice%'
AND NOT amount2 BETWEEN 1 AND 2
AND NOT drink_name IS NULL;
UPDATE:改变数据;
UPDATE drink_info
SET color = 'yellow'
WHERE drink_name = 'Blackthorn' AND color = 'black’;
UPDATE drink_info
SET cost = 3.5 + 1
WHERE cost = 3.5;
DELETE:删除不需要的数据;
DELETE FROM drink_info WHERE drink_name = 'Blue Moon' AND color = 'blue’;
排序,归组,对结果进行数学运算,对查询条件进行限制等
CASE检查:
UPDATE tablename
SET column =
CASE
WHEN column1 = someone OR column1 = sometwo
THEN newValue
WHEN column2 = someone
THEN newValue
ELSE newValue
END;
WHERE ...
ORDER BY排序:
SELECT …
FROM …
WHERE …
ORDER BY columnName1,columnName2;
SUM加总:
SELECT name, SUM(cost)
FROM table
WHERE name = 'xxxx';
-- 对加总的结果进行排序:
SELECT name, SUM(cost)
FROM table
GROUP BY name
ORDER BY SUM(cost) DESC;
GROUP BY:数据归组;
DISTINCT:去重(这是个关键字,放在所有查询字段的开头)
SELECT DISTINCT sale_date
FROM table
WHERE name = ‘xx’
ORDER BY sale_date DESC;
-- 注意,SELECT DISTINCT col1,col2; mysql会将两列都去重,因此DISTINCT一般用于查询不重复记录的条数;
SELECT COUNT(DISTINCT sale_date)
FROM table
WHERE name = ‘xx’;
LIMIT限制查询结果的数量:
LIMIT 2
返回2条数据LIMIT 0,2
从第0个位置开始返回4条数据LIMIT 2,1
返回第3条数据 (默认从0开始,只有字符串下标特殊,从1开始)SELECT
FROM
WHERE
ORDER BY
LIMIT 2;
联接都会生成一张临时的中间表;
交叉连接(cross join):笛卡尔积
mysql> SELECT t.toy , b.boy
-> FROM
-> toys AS t
-> CROSS JOIN
-> boys AS b;
内连接(INNER JOIN):
mysql> SELECT b.boy,t.toy
-> FROM
-> boys AS b
-> INNER JOIN
-> toys AS t
-> ON b.toy_id = t.toy_id;
值得注意的是:
- ON和WHERE并不等价,尤其在LEFT JOIN和RIGHT JOIN中区别明显;
- 以左联接为例,ON是在生成临时表时使用条件,但不管ON中条件是否为真,都会返回左边表中的记录;
- WHERE则是在临时表生成之后,在对临时表进行条件过滤,此时已经没有了联接的概念,条件为假的全部过滤掉;
外联接
mysql> SELECT mc.last_name,mc.first_name,jc.title
-> FROM my_contacts mc LEFT OUTER JOIN job_current jc
-> ON mc.contact_id = jc.contact_id;
-- +-----------+------------+-----------+
-- | last_name | first_name | title |
-- +-----------+------------+-----------+
-- | Joy | HQ | EngineerM |
-- | Mary | DM | EngineerS |
-- | July | FM | NULL |
mysql> SELECT title FROM job_current
-> UNION
-> SELECT title FROM job_desired
-> UNION
-> SELECT title FROM job_list;
从联合创建表:
mysql> CREATE TABLE job_titles AS
-> SELECT title FROM job_current
-> UNION
-> SELECT title FROM job_desired
-> UNION
-> SELECT title FROM job_list
有了联接确实很好用,我们可以将多张关联的表联接成一张临时表,然后设置条件,从中查询需要的记录;但有时要问数据库的数据不只一个,或者把甲查询的结果作为乙查询的输入,这时就需要子查询了;
IN关键字:(IN、NOT IN)
SELECT mc.last_name,mc.first_name,mc.phone,jd.title
-> FROM my_contacts mc NATURAL JOIN job_desired jd
-> WHERE jd.title IN ('EngineerM','EngineerS');
结合子查询:
SELECT mc.last_name,mc.first_name,mc.phone,jd.title
-> FROM my_contacts mc NATURAL JOIN job_desired jd
-> WHERE jd.title IN (
-> SELECT title
-> FROM job_list
-> GROUP BY title
-> ORDER BY title
-> );
关联子查询
-- 查询my_contacts表中有1项兴趣的人
select mc.last_name, mc.first_name
from my_contacts mc
where 1 = (
select count(*)
FROM contact_intrest
-- 此处子查询 依赖外层查询的结果
where contant_id = mc.contact_id
);
EXISTS与NOT EXISTS:
select mc.last_name, mc.first_name
from my_contacts mc
WHERE exists (
select 1 from contact_intrest where contant_id = mc.contact_id
);
把自联接变成子查询:
mysql> SELECT cb1.name clown ,cb2.name boss
-> FROM clown_boss cb1
-> INNER JOIN clown_boss cb2
-> ON cb1.boss_id = cb2.id;
--
mysql> SELECT cb1.name,(
-> SELECT name FROM clown_boss
-> WHERE cb1.boss_id = id
-> ) boss
-> FROM clown_boss cb1;
用于对结果集进行排序
select [列] from [表]
order by [列] [DESC]|[ASC];
用于规定要返回的记录数
select top [number] [列] from [表]; -- sql server
select [列] from [表]
limit [startIndex], [size]; -- mysql
select [列] from [表]
where rownum <= [number];
用在where子句中,搜索列的指定模式,如匹配字符串
%
代表0或多个字符_
代表一个字符select [列] from [表]
where [列] LIKE [pattern];
基于表的共同字段,将两个及以上的表结合起来
select [列]
from [表1]
inner join [表2]
on [表1.列] = [表2.列];
-- 平均数
select AVG([列]) from [表];
-- 数量统计
select COUNT(*) from [表];
select COUNT(DISTINCT [列]) from [表];
-- 转换大小写
select UCASE([列]) from [表];
select LCASE([列]) from [表];
-- 文本长度
select LEN([列]) from [表];
-- 小数舍入
select ROUND([列], [小数位]) from [表];
-- 当前系统日期和时间
select NOW() from [表];
-- 获取系统当前时间
SELECT SYSDATETIME()
SELECT SYSDATETIMEOFFSET()
SELECT SYSUTCDATETIME()
SELECT CURRENT_TIMESTAMP
SELECT GETDATE()
SELECT GETUTCDATE() -- 带UTC的系统时间是世界标准时间,其他为当前时区时间
用不同的格式显示日期/时间数据:
CONVERT(data_type(length),data_to_be_converted,style)
Style ID | Style 格式 |
---|---|
100 或者 0 | mon dd yyyy hh:miAM (或者 PM) |
101 | mm/dd/yy |
102 | yy.mm.dd |
103 | dd/mm/yy |
104 | dd.mm.yy |
105 | dd-mm-yy |
106 | dd mon yy |
107 | Mon dd, yy |
108 | hh:mm:ss |
109 或者 9 | mon dd yyyy hh:mi:ss:mmmAM(或者 PM) |
110 | mm-dd-yy |
111 | yy/mm/dd |
112 | yymmdd |
113 或者 13 | dd mon yyyy hh:mm:ss:mmm(24h) |
114 | hh:mi:ss:mmm(24h) |
120 或者 20 | yyyy-mm-dd hh:mi:ss(24h) |
121 或者 21 | yyyy-mm-dd hh:mi:ss.mmm(24h) |
126 | yyyy-mm-ddThh:mm:ss.mmm(没有空格) |
130 | dd mon yyyy hh:mi:ss:mmmAM |
131 | dd/mm/yy hh:mi:ss:mmmAM |
SELECT CONVERT(varchar(100), GETDATE(), 8)
--结果:21:33:18
SELECT CONVERT(varchar(100), GETDATE(), 20)
--结果:2020-12-07 21:33:18
SELECT CONVERT(varchar(100), GETDATE(), 23)
--结果:2020-12-07
SELECT CONVERT(varchar(100), GETDATE(), 24)
--结果:21:33:18
SELECT CONVERT(varchar(100), GETDATE(), 108)
--结果:21:33:18
SELECT CONVERT(varchar(100), GETDATE(), 111)
--结果:2020/12/07
SELECT CONVERT(varchar(100), GETDATE(), 120)
--结果:2020-12-07 21:33:18
DATEADD (datepart , number , date )
datepart | 缩写 |
---|---|
年 | yy, yyyy |
季度 | qq, q |
月 | mm, m |
年中的日 | dy, y |
日 | dd, d |
周 | wk, ww |
星期 | dw, w |
小时 | hh |
分钟 | mi, n |
秒 | ss, s |
毫秒 | ms |
微妙 | mcs |
纳秒 | ns |
-- 查询上个月的今天,下个月的今天
SELECT DATEADD(month, -1, '20211208');
SELECT DATEADD(month, 1, '20211208');
时间跨度
DATEDIFF ( datepart , startdate , enddate )
-- 计算去年第一天到今天之间有多少天
SELECT DATEDIFF(DAY,'20200101','20211208')
此函数返回映射到指定年、月、日值的 date 值
DATEFROMPARTS ( year, month, day )
SELECT DATEFROMPARTS ( 2021, 12, 8 ) AS Result;
-- 2021-12-08
DATENAME ( datepart , date )
SELECT DATENAME(year, getdate()) 'Year'
,DATENAME(month, getdate()) 'Month'
,DATENAME(day, getdate()) 'Day'
,DATENAME(weekday,getdate()) 'Weekday';
-- 2021 12 8 星期三
DATEPART ( datepart , date )
SELECT DATEPART(year, getdate()) 'Year'
,DATEPART(month, getdate()) 'Month'
,DATEPART(day, getdate()) 'Day'
,DATEPART(weekday,getdate()) 'Weekday';
-- 2021 12 8 4
如果表达式是有效的 date、time、或 datetime 值,则返回 1;否则返回 0
IF ISDATE('2021-12-08') = 1
SELECT '合法日期' Result
ELSE
SELECT '不合法日期' Result;
-- 本月第一天
SELECT DATEADD(mm,DATEDIFF(mm,0,getdate()),0)
--2021-12-01 00:00:00.000
-- 本周星期一
SELECT DATEADD(wk,DATEDIFF(wk,0,getdate()),0)
--2021-12-06 00:00:00.000
-- 今年第一天
SELECT DATEADD(yy,DATEDIFF(yy,0,getdate()),0)
--2021-01-01 00:00:00.000
-- 下个季度第一天
SELECT DATEADD(qq,DATEDIFF(qq,-1,getdate()),0)
--2021-01-01 00:00:00.000
-- 上个月最后一天
SELECT DATEADD(dd,-DAY(getdate()),getdate())
--2021-11-30 20:14:21.850
-- 今年最后一天
SELECT DATEADD(year,DATEDIFF(year,0,DATEADD(year,1,getdate())),-1)
--2021-12-31 00:00:00.000
-- 去年同一天
SELECT DATEADD(YEAR,-1,GETDATE())
--2020-12-08 20:19:05.987
在第二个字符表达式中搜索一个字符表达式,这将返回第一个表达式(如果发现存在)的开始位置
CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )
SELECT CHARINDEX('数据','SQL数据库开发SQL数据库开发');
-- 4
SELECT CHARINDEX('数据','SQL数据库开发SQL数据库开发',6);
-- 12
返回模式在指定表达式中第一次出现的起始位置;如果在所有有效的文本和字符数据类型中都找不到该模式,则返回0;
与CHARINDEX类似;PATINDEX 的起始位置为 1;
PATINDEX ( '%pattern%' , expression )
SELECT PATINDEX('%数据库%', 'SQL数据库开发');
SELECT PATINDEX('%数_库%', 'SQL数据库开发');
串联或联接的两个或更多字符串值生成的字符串,用第一个函数参数中指定的分隔符分隔连接的字符串值;
CONCAT_WS ( separator, argument1, argument2 [, argumentN]... )
SELECT CONCAT_WS('-','a','b',NULL,'c');
-- a-b-c
CONCAT_WS 会忽略列中的 NULL 值。 用 ISNULL 函数包装可以为 null 的列,并提供默认值; (
isnull( check_expression , replacement_value )
)
STRING_AGG ( expression, separator ) [
WITH t AS (
SELECT '张三' Name,'语文' Course,89 Score
UNION ALL
SELECT '张三' ,'数学' ,91
UNION ALL
SELECT '李四' ,'语文' ,78
UNION ALL
SELECT '李四' ,'数学' ,96
)
SELECT Name,
STRING_AGG(Course,',') Course ,
STRING_AGG(Score,',') Score
FROM t
GROUP BY Name
-- 李四 语文,数学 78,96
-- 张三 数学,语文 91,89
输出行可以按任意顺序排列。 顺序不保证与输入字符串中的子字符串顺序匹配。 可以通过在 SELECT 语句中使用 ORDER BY 子句覆盖最终排序顺序 (ORDER BY value);
当输入字符串包含两个或多个连续出现的分隔符字符时,将出现长度为零的空子字符串。 空子字符串的处理方式与普通子字符串相同。 可以通过使用 WHERE 子句筛选出包含空的子字符串的任何行 (WHERE value <> ‘’)。 如果输入字符串为 NULL,则 STRING_SPLIT 表值函数返回一个空表;
STRING_SPLIT ( string , separator )
SELECT Value FROM STRING_SPLIT('SQL-数据库-开发', '-');
-- Value
-- SQL
-- 数据库
-- 开发
WITH t AS (
SELECT 1 ID,'张三' Name,'足球,篮球,羽毛球' Hobby
UNION ALL
SELECT 2 ,'李四','足球,游泳,爬山'
)
SELECT ID, Name, Value
FROM t
CROSS APPLY STRING_SPLIT(Hobby, ',');
-- ID Name Value
-- 1 张三 足球
-- 1 张三 篮球
-- 1 张三 羽毛球
-- 2 李四 足球
-- 2 李四 游泳
-- 2 李四 爬山
返回的列不再是Hobby,而是Value,必须写成Value,否则得不到想要的结果;
将字符串插入到另一个字符串中:
STUFF ( character_expression , start , length , replaceWith_expression )
SELECT STUFF('abcdef', 2, 3, 'ijklmn');
-- aijklmnef
以指定的次数重复字符串值;
REPLICATE( string_expression ,integer_expression )
SELECT '2'+REPLICATE ('3',5)
-- 233333
返回使用指定格式和可选区域性格式化的值
使用 FORMAT 函数将日期/时间和数字值格式化为识别区域设置的字符串。 对于一般的数据类型转换,请使用 CAST 或 CONVERT;
SELECT FORMAT( GETDATE(), 'dd/MM/yyyy', 'zh-cn' ) AS '自定义日期'
,FORMAT(123456789,'###-##-####') AS '自定义数字';
字符串截取和替换
-- 字符串下标从1开始 区间[2,4]为闭区间
SELECT REPLACE('abcdefg',SUBSTRING('abcdefg',2,4),'**')
SELECT REPLACE('13512345678',SUBSTRING('13512345678',4,11),'********')
SELECT REPLACE('12345678@qq.com','1234567','******')
返回字符串值的逆序
SELECT REVERSE('SQL数据库开发')
select * from HR.Employees
where title in (
select title from HR.Employees
group by title
having count(1)>1);
select * from HR.Employees
where title+titleofcourtesy in
(select title+titleofcourtesy
from HR.Employees
group by title,titleofcourtesy
having count(1)>1);
SELECT
id,
name,
SUM(CASE WHEN quarter=1 THEN number ELSE 0 END) '一季度',
SUM(CASE WHEN quarter=2 THEN number ELSE 0 END) '二季度',
SUM(CASE WHEN quarter=3 THEN number ELSE 0 END) '三季度',
SUM(CASE WHEN quarter=4 THEN number ELSE 0 END) '四季度'
FROM test
GROUP BY id,name;
语法1:Insert INTO table(field1,field2,...) values(value1,value2,...)
语法2:Insert into Table2(field1,field2,...) select value1,value2,... from Table1
要求目标表Table2必须存在,由于目标表Table2已经存在,所以我们除了插入源表Table1的字段外,还可以插入常量;
SELECT vale1, value2 into Table2 from Table1
要求目标表Table2不存在,因为在插入时会自动创建表Table2,并将Table1中指定字段数据复制到Table2中;
如果是使用【编写查询以指定要传输的数据】,那么在大数据表的复制就会有问题,因为复制到一定程度就不再动了,内存不够用,它也没有写入到表中,而使用上面3种语法直接执行是会马上刷新到数据库表中的;
mysql> CREATE TABLE drink_des
-> (
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> drink_des VARCHAR(100),
-> meter INT
-> );
mysql> INSERT INTO drink_des
-> (drink_des,meter)
-> SELECT drink_des,meter FROM drink_list;
mysql> CREATE TABLE drink_des
-> (
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> drink_des VARCHAR(100),
-> meter INT
-> )AS
-> SELECT drink_des,meter FROM drink_list;
AS:
列别名AS:
SELECT saler AS si_er, sale_date AS si_date FROM drink_list
WHERE NOT saler IS NULL
ORDER BY si_date;
注意:这里的WHERE子句并不能直接使用列的别名,这是由于语句的执行顺序决定的,WHERE执行时,别名尚未生效;
表别名AS:
1.关闭所有修改该表
的数据服务(定时任务等);
2.查看该表
的创建 sql,修改表名为“表名_copy”,重新执行生成新表
;
3.执行sql向新表
导入数据:
INSERT INTO table_copy SELECT
t.*
FROM
TABLE t
LEFT JOIN table_copy tc ON t.id = tc.id
WHERE
t.condition_id > 10001
AND tc.id IS NULL
LIMIT 100000;
原表
和 新表
,使用id关联;原表
进行条件过滤,condition_id一般使用主键 id(自增特点)筛选出指定之间之后的数据;新表
的过滤条件为 id为空,表示 原表
存在但 新表
不存在的数据;4.执行多次直到原表
中符合条件的数据全部插入到新表
;
5.查看新表
数据无误后,直接删除原表
,然后修改 新表
的表名为 原表
的表名(去掉copy);
6.恢复所有该表
关联的数据服务(定时任务等);
--方法1:
Update Table1
set c = (select c from Table2 where a = Table1.a)
where c is null
--方法2:
update A
set newqiantity=B.qiantity
from A,B
where A.bnum=B.bnum
--方法3:
update
(select A.bnum ,A.newqiantity,B.qiantity from A
left join B on A.bnum=B.bnum) AS C
set C.newqiantity = C.qiantity
where C.bnum ='001'
索引的名称,通常按命名规范以index或idx开头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J0Op5JoR-1668753236373)(attachment:image.png)]
外键名称,通常以fk开头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1KRPYry-1668753236375)(attachment:image.png)]
区别于主键,唯一键具有唯一性
右键数据库(也可以是表)‘导入向导’,引导用户导入数据到数据库对应的表:
右键数据库(也可以是表)‘导出向导’,将数据库里的数据进行导出:
函数和存储过程共用模板;区别在于函数有返回值;
选中已有备份,即可还原;‘工具’-》‘历史日志’