查询也称检索。
必须给出俩条信息:
要选择什么?
选择那一行或那几行;选择那些列或者全部列。
从什么地方选择?
要检索的数据来自那个表。
查询此时所在的数据库中的表(非系统表):
SELECT NAME FROM SYSOBJECTS where type = 'U';
查询数据库中所有表(包含表信息):
SELECT * FROM INFORMATION_SCHEMA.TABLES
知道了表名,根据表名查看表的结构(包含列名)
查询表结构时,最好单独执行
sp_columns table_1;
sp_help table_1;
知道了表的列名,可以开始查询表中数据了。
查询表中部分列的所有行:
表1中共有四列,此条语句选择三列
select id,age,gender from table_1;
更换检索列的排列,就可以得到排列不同的结果集:
select age,id,gender from table_1;
检索表中所有列的所有行
select * from table_1;
检索语句带星号(*)表示查询所有列
得到表中所有数据
如果表中数据记录非常多时,使用此语句就不太合适了。
select top 5 * from table_1;
只显示表的前5条数据,但每条数据包含所有列。
包含部分列的限制查询:
select top 3 id,age,phone from table_1;
检索表的前3条数据,包含3个选择列。
创建一个新的表:
包含三个列(column)
create table
distinct_table
(id int not null primary key,
name varchar(5) not null,
age int );
为新表插入数据:
因为我们是为了进行去重查询,所以为name,age列填入重复数据
insert into
distinct_table
(id,name,age)
values
(1,'张大',11),
(2,'张大',22),
(3,'张三',33),
(4,'张四',33);
开始去重查询:
select distinct age from table_33;
--得到只包含age列的不重复数据结果集。
select distinct age,name from distinct_table;
--distinct关键字后添加多个列虽然不会报错,但也不会再起到去重作用。
select distinct * from distinct_table;
--执行‘所有列’的去重,效果与不执行去重相同。
select * from distinct_table;
为检索数据添加条件,指定范围
检索条件在表名之后给出(from表名 where条件)
select * from distinct_table
where age = 11;
--添加过滤条件,年龄等于11
--检索年龄等于11的记录
select * from distinct_table
where name = '张大';
--where子句中用''单引号来限定字符串。
select * from distinct_table
where age <= 22;
--检索表中,年龄小于等于22的记录,包括22。
select * from distinct_table
where age >=22;
--检索年龄大于等于22的记录,包括22.
select * from distinct_table
where age < 33;
--检索年龄小于33的记录。
select * from distinct_table
where age > 22;
--检索年龄大于22的记录。
select * from distinct_table
where age != 33;
--检索年龄不等于33的记录。
select * from distinct_table
where age <> 33;
select * from distinct_table
where age !< 33;
--检索年龄不小于33的记录,不包括33.
select * from distinct_table
where age !> 33;
--检索年龄不大于33的记录,因为没有年龄大于33记录所有全部检索。
select * from table_2
where nowdate is null;
--检索现在时间列是空的记录。
select * from table_2
where nowdate is not null;
--检索现在时间列不为空的记录。
and ‘与’ 操作符,俩个或多个条件同时满足时,返回记录。
or ‘或’ 操作符,有一个条件满足时就返回数据。
WHERE语句可以包含任意数量的AND和OR操作符。
同时使用时and的优先级高于or
圆括号有着比and和or更高的优先级。
select * from distinct_table
where id =2 and name = '张大';
--检索id等于2与名称是张大的记录。
--俩个或多个条件同时满足时,返回记录。
select * from distinct_table
where id =2 or age = 77;
select * from distinct_table
where age = 77 or id =2;
/*
俩条检索的结果相同
检索id等于2或者年龄等于77的记录。
年龄列中没有77的值,所以只返回id等于2的记录。
*/
select * from distinct_table
where id =2 or age = 33;
--俩个条件都满足时,则俩个条件的结果都返回。
在俩者之间
select * from distinct_table
where age between 11 and 22;
--检索年龄在11与22之间的记录。and‘与’操作符
用来指定条件范围,范围中的每个条件都可以进行匹配,即使有不匹配 的选项也不会报错
select * from distinct_table
where name in ('张四', '张三') ;
--在有很多合法选项时,IN操作符的语法更加清楚,更加直观
select * from distinct_table
where name in ('张四', '张三','王五') ;
--表名称列中王五值不存在,但不会报错。
--IN操作符一般比一组OR操作符执行更快
select * from distinct_table
where age in (select age from distinct_table
where age = 33);
--它的功能与OR相当。
--IN的最大优点是可以包含其他SELECT语句,能更动态的建立WHERE子句
WHERE子句中用来否定其后面条件的关键字
NOT从不单独使用(它总是与其他操作符一起使用)NOT关键字可以用来在要过滤的列前
select * from distinct_table
where not age in (select age from distinct_table
where age = 33);
--检索年龄不包含33的记录
select * from distinct_table
where not name in ('张大');
--检索名称列不为张大的记录
--WHERE子句 NOT关键字 列名 IN关键字(?)
关键字like,用来匹配值的一部分
通配符的搜索只能用于文本字段(字符串),非文本数据类型不能使用通配符搜索
不要过多的使用通配符,如果其他操作符能达到相同的目的,应该使用其他操作符
尽量不要将他们放在搜索模式的开始处,这样的检索速度最慢
百分号(%)通配符
--%表示任意字符出现任意次数
select * from distinct_table
where name like '张%';
--检索名称中姓张的记录。
除了可以匹配一个到多个字符之外,还可以匹配0个字符
select * from distinct_table
where name like '张%大';
--检索名称列以张开头以三结尾,的记录。
--通配符无法匹配NULL
--注意通配符匹配时,值后是否为空格
--此表中的名称列数据类型为变长字符串,如果是定长字符串,则空余字节会用NULL填充
select * from distinct_table
where name like '张%大%';
--如果值后用空格填充,则增加一个通配符进行匹配。
下划线(_)通配符
匹配一个任意字符
select * from distinct_table
where name like '_大';
--匹配名称列中,一个任意字符一个为大的名称。
方括号([ ])通配符
select * from distinct_table
where age like '[12]%';
--检索年龄列中以1或2开头的任意数字。
select * from distinct_table
where age like '[12]%[2]';
--检索年龄列中以1或2开头的,以2结尾的任意数字。
将检索的数据按需要的列进行排序。
关键字DESC降序(从大到小),ASC升序(从小到大)为默认
select * from distinct_table
order by age desc;
--将检索的数据以年龄从大到小排列
select * from distinct_table
order by age asc;
--将检索的数据以年龄从小到大排序。
select * from distinct_table
order by age;
--将检索的数据以年龄从小到大排序,未使用关键字ASC,ASC为默认。
在指定一条ORDER
BY子句时,应该保证它是SELECT语句中的最后一条子句。否则会出现错误!
select * from distinct_table
where age < 33 order by age desc;
《按多个列进行排序》
按多个列排序时,简单的指定列名,列名之间用逗号隔开即可
select * from table_1
order by id,age desc;
--先按ID列进行排序,再按AGE列进行排序,排序为降序(从大到小)
《按检索列位置进行排序》
使用select语句中的检索列位置进行排序
select id,age,gender,phone from table_1
order by 1,2 desc;
--先以ID列进行排序,再以age列进行排序,排序方式为降序。
直接从数据库中,检索出转换,计算或格式化后的数据。
计算字段是在SELECT运行时创建的
拼接:将值连接到一起组成单个值
select name + site from table_2;
--将name列与site列连接到一起组成一个值。
select name +'('+site+')' from table_2;
--在连接的新值中添加()用于区分。
拼接时,字符串型和INT型不能混合。
select name +'('+id+')' from table_2;
--在将 varchar 值 ')' 转换成数据类型 int 时失败。
别名用关键字 AS赋予
别名也被称作导出列
拼接后的字段只是一个值没有名称,未命名的列不能用于客户端应用
select name +'('+site+') ' as ns2 from table_2;
--为检索出的数据集合添加别名,别名为ns2。
为表赋予别名
在这里插入代码片
当检索列为定长字符型时,如何去掉空格。
此表中存在定长字符串类型
关键字RTRIM()去掉列末尾空格
select name + '('+rtrim(gender)+')' from table_1;
--将gender列左侧的空格去掉
--将name列与gender列的值拼接为一个值,gender列末尾的空格去掉
select rtrim(name) + '('+gender+')' from table_1;
--去掉name列的空格,并将name与gender列的值拼接。
关键字LTRIM()去掉列开头空格
select name + '('+ltrim(string_1)+')' from table_1;
--去掉string_1列开头位置的空格,并与name列拼接
SQL算术计算符
--加 +
--减 -
--乘 *
--除 /
--SELCET语句忽略FROM子句之后,就是一个简单的访问和处理表达式
select 3 + 4 as addition;
--加法,addition
select 9999999 - 123456 as subtraction;
--减法,subtraction
select 78 * 88 as multiplication;
--乘法,multiplication
select 87879 / 2343 as division;
--除法,division
如果你决定使用函数,应该保证做好代码注释,方便以后你和其他人方便知道所编写的代码的含义
用于处理文本字符串的,《文本函数》
用于在数值数据上进行算数操作的,《数值函数》
用于处理日期和时间值并从中提取特定成分的,《日期和时间函数》
返回DBMS正在使用的特殊信息的,《系统函数》
UPPER()函数,将文本转换为大写
select
id,
name,
age,
gender,
phone,
upper(string_1),
order_date,
number_1
from table_1;
--upper()关键字,将string_1列的字符串转换为大写。
lower()函数,将文本转换为小写
id,
name,
age,
gender,
phone,
lower(string_1),
order_date,
number_1
from table_1;
--lower()将string_1列中的字符串转变为小写
left()返回字符串左侧的字符
select left('fhhjkiunk',3);
select left(string_1,6) from table_1;
--返回字符串左侧的字符,返回字符串左侧几个字符,包括空格。
RIGHT()返回字符串右边的字符
select right(string_1,6) from table_1;
--返回字符串右侧的指定字符,包括空格。
len()返回字符串的长度,不包括空格
select len(string_1) from table_1 order by id;
--返回string_1列所有行字符串的长度,并按id列排序。
select len(string_1) from table_1
where id = 3;
--返回指定行string_1列字符串的长度
ltrim()去掉字符串左边空格
select ltrim(string_1) from table_1;
--ltrim()去掉字符串左侧的空格。
rtrim()去掉字符串右边空格
select rtrim(string_1) from table_1;
--rtrim()去掉字符串右侧的空格。
select len(rtrim(string_1)) from table_1 order by id;
--返回去掉string_1列右侧的空格后的字符串数量并按照ID列排序。
SOUNDEX()返回字符串的SOUNDEX值(即发音比较)
时间单位
year(yy) 年份
quarter(qq) 季度
month(mm) 月份
day(dd) 日
week(wk) 周
hour(hh) 时
minute(mi) 分
second(ss) 秒
millisecond(ms) 毫秒
返回系统当前日期时间–getdate()
select getdate();
--返回系统当前的日期时间
增加并返回日期–dateadd()
select dateadd(year,33,'2020-7-17');
--为日期增加年数并返回结果。
select dateadd(yy,4,(select getdate()));
--为当前日期时间增加4年。
select dateadd(qq,4,(select getdate()));
--为当前日期时间增加4个季度。
select dateadd(mm,4,(select getdate()));
--为当前日期增加4个月。
select dateadd(dd,4,(select getdate()));
--当前日期增加4天。
select dateadd(wk,4,(select getdate()));
--当前日期增加4周。
select dateadd(hh,4,(select getdate()));
--当前日期增加4小时。
select dateadd(mi,4,(select getdate()));
--当前日期增加4分钟。
select dateadd(ss,40,(select getdate()));
--当前日期增加40秒
select dateadd(ms,40,(select getdate()));
--当前日期增加40毫秒。
datediff 返回俩个指定日期的边界数/差
select datediff(day,'2002-05-23','2200-03-03') ;
--检索俩个日期的相差天数,72237天。
select datediff(day,'2200-03-03','2002-05-23') ;
--检索俩个日期相差的天数,-72237天。
datepart 返回代表指定日期的指定日期部分的整数
select DATEPART(year, '2024-07-11');
--返回指定日期的年份,。
select datepart(month, '2024-07-11');
--返回指定日期的月份。
datename 返回代表指定日期的指定日期部分的字符串
select datename(weekday, '2030-07-09');
--返回指定日期为星期几,星期二。
select datename(quarter, '2020-07-17');
--返回当前日期的季度。
数值处理函数
select cos(66) as '返回一个角度的余玄';
--cos()返回一个角度的余玄。
select PI() as '返回圆周率';
--pi()返回圆周率。
select abs(66/33) AS '返回一个数的绝对值';
--abs()返回一个数的绝对值。
select EXP(78) AS '返回一个数的指数值';
--exp()返回一个数的指数值。
select SIN(90) AS '返回一个角度的正玄';
--sin()返回一个角度的正玄。
select SQRT(7) AS '返回一个数的平方根';
--sqrt()返回一个数的平方根.
select TAN(89) AS '返回一个角度的正切';
--tan()返回一个角度的正切.
count()返回某列的行数
select count(number_1) AS '返回行数' from table_1;
--count(),返回此列的行数。
AVG()返回某列的平均值
select AVG(age) from table_1;
--avg(),返回年龄列的平均值。
MAX() 返回某列的最大值
select MAX(age) as '返回某列的最大值'from table_1;
--max(),返回某列的最大值
MIN() 返回某列的最小值
select MIN(age) as '返回某列的最小值' from table_1;
--min(),返回某列的最小值
SUM() 返回某列值之和
select SUM(age) as '返回某列值之和' from table_1;
--sum(),返回某列值之和
返回列不同值的和
select SUM(distinct(age)) as '返回不同值的和' from table_1;
--关键字,sum(),distinct()
组合聚集函数
select
count(id),
max(age),
min(phone),
avg(number_1),
sum(number_1)
from table_1;
--不同列使用不同的聚集函数。
select
count(age),
max(age),
min(age),
avg(age),
sum(age)
from table_1;
--相同列使用不同的聚集函数。
分组数据是通过GROUP BY
分组过滤数据是通过HAVING
如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名
select name,count(*) from table_1 group by name;
--统计相同名称的数量,并以名称分组。
除聚集计算语句外,SELECT语句中的每一列都必须在GROUP BY中给出
select name,age,count(*) from table_1 group by name;
--age未曾在检索中列出,故报错。
/*
HAVING 子句中的列 'table_1.age' 无效,
因为该列没有包含在聚合函数或 GROUP BY 子句中。
*/
GROUP BY子句列未出现在检索列时,不报错
select name,count(*) from table_1 group by name,age;
GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前
过滤分组
select name,age from table_1 GROUP BY name HAVING age > 12;
--将age大于12的检索列按name列进行分组。
GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前
select
name,
age
from table_1
where
id < 8
GROUP BY
name,
age
HAVING
age > 12
ORDER BY
age;
/*
select name,age from table_1
where id < 8
GROUP BY name,age
HAVING age > 12
ORDER BY age;
*/
不可以使用,GROUP BY未给出的列进行ORDER BY排序
SELECT子句及其顺序
SELECT子句及其顺序
Select 要返回的列或表达式
From 从中检索数据的表
Where 行级过滤
Group by 分组说明
Having 组级过滤
Order by 输出排序顺序
即嵌套在其他查询中的查询。
select * from table_1 where age in
(select age from table_1 where age <= 12);
--将内查询的结果作为外查询的条件。
select * from table_1
where id in
(select id from table_2 where table_2.nowdate is not null );
--表1和表2通过外键连接。
--子查询可以用不同表的结果为条件
对于嵌套的子查询的数目没有限制,但是实际操作中由于性能的限制,不能嵌套太多的子查询
指定要联结的所有表,以及关联它们的方式即可。
要保证所有的联结都有WHERE子句,否则会返回比想要的多得多的数据
不使用WHERE子句会造成笛卡二积又被称为叉联结
select age,gender,name,site from
table_1,table_2;
--为使用where子句,造成笛卡尔积。又叫叉联结。
内联结–inner join where格式
select
table_1.id,table_1.age,table_1.gender,table_1.phone,
table_2.name,table_2.site,table_2.nowdate,table_2.id
from table_1,table_2
where table_1.id = table_2.id;
--没有使用 inner join 的等值联结
内联结 INNER JOIN 标准格式
select
table_1.id,table_1.age,table_1.gender,table_1.phone,
table_2.name,table_2.site,table_2.nowdate,table_2.id
from table_1 inner join table_2
on table_1.id = table_2.id;
--标准格式的内联结 inner join ...用on代替where。
为联结添加过滤,检索指定行。
select
table_1.id,table_1.age,table_1.gender,table_1.phone,
table_2.name,table_2.site,table_2.nowdate,table_2.id
from table_1 inner join table_2
on table_1.id = table_2.id
and table_1.id = 3;
--为联结添加过滤,检索指定行。只检索id为3的行。
SQL不限制一条SELECT语句可以联结的表的数目,联结的表越多,性能下降的越厉害。
使用联结的同时增加过滤
select
table_1.id,table_1.age,table_1.gender,table_1.phone,
table_2.name,table_2.site,table_2.nowdate,table_2.id
from table_1,table_2
where table_1.id = table_2.id
and table_1.id in(1,2,3);
--等值联结,联结并过滤数据。
表别名
SQL使用表别名。
缩短SQL语句;
允许在一条SELECT语句中多次使用相同的表。
缩短SQL语句;
select
t1.id,t1.age,t1.gender,t1.phone,
t2.name,t2.site,t2.nowdate,t2.id
from table_1 as t1,table_2 as t2
where t1.id = t2.id
and t1.id in(1,2,3);
--给table_1,table_2赋予别名t1,t2.
在查询中使用表别名可以缩短SQL语句,但是表别名只在查询中使用,表别名不会返回到客户端。
允许在一条SELECT语句中多次使用相同的表
自联结
自联结作为外部语句,用来替代从相同表中检索数据的子查询语句
虽然结果相同,但许多DBMS处理联结比子查询快得多。
select t1.name,t1.site,t1.nowdate,t1.id
from table_2 as t1 , table_2 as t3
where t1.id = t3.id
and t1.name in ('老大','老二','老三');
--将table_2表赋予别名t1,t3在同一个查询中引用俩次。
--当一个表在一条查询中出现俩次时,需要为他赋予别名。否则会报错!
自然联结
自然联结排除多次出现,使每一列只返回一次。
通配符(SELECT
*)只对第一个表使用。所有其他列明确列出,所以没有重复的列被检索出来
select * ,age,gender,phone from table_1 inner join table_2
on table_1.id = table_2.id;
--俩个表,一个用*表示全部使用,一个明确列出。
外联结–OUTER JOIN
包含哪些在相关表中没有关联的行。称为外联结
外联结关键字,left左,right右
在使用OUTER JOIN语法时,必须使用RIGHT(右)或LEFT(左)关键字指定包括其所有行的表
左外联结–LEFT OUTER JOIN
select table_1.id,table_1.age,table_1.gender,table_1.phone,
distinct_table.name,distinct_table.age,distinct_table.id
from table_1 left outer join distinct_table
on table_1.id = distinct_table.id ;
--左外联结,返回左侧表所有行,右侧表过滤行
右外联结–RIGHT OUTER JOIN
select table_1.id,table_1.age,table_1.gender,table_1.phone,
distinct_table.name,distinct_table.age,distinct_table.id
from table_1 right outer join distinct_table
on table_1.id = distinct_table.id ;
--右外联结,返回右侧表所有行,左侧表过滤行。
左外联结与右外联结唯一的差别是所关联的表的顺序,调整表顺序,左外联结可以转变为右外联结。
全外联结–FULL OUTER JOIN
包含所有关联的行与不关联的行,注意:是关联行与不关联行,不是列。
select table_1.id,table_1.age,table_1.gender,table_1.phone,
distinct_table.name,distinct_table.age,distinct_table.id
from table_1 full outer join distinct_table
on table_1.id = distinct_table.id ;
--全外联结,返回俩个表中的所有行。
使用带聚集函数的联结
select max(table_1.id) as id,
count(distinct_table.age) as age
from table_1 inner join distinct_table
on table_1.id = distinct_table.id;
--
SQL允许执行多个查询,并将结果作为一个查询结果集返回。这些组合查询称为并(union)或者复合查询(compound query)–带有自动去重的效果
使用组合查询的情况:
在一个查询中从不同的表返回结构数据;
对一个表执行多个查询,按一个查询返回数据。
(多数情况下,组合相同表的俩个查询所完成的工作与具有多个WHERE子句条件的一个查询所完成的工作相同。
任何具有多个WHERE子句的SELECT语句都可以作为一个组合查询。)
将同一个表中的俩次查询,返回到一个结果集。
select
name,age from table_1
union
select
gender,phone from table_1 ;
--将同一个表中的俩次查询,返回到一个结果集
将不同表的查询返回到一个结果集
select
name,age from table_1
union
select
name,age from join_1;
--将不同表的查询返回到一个结果集
组合查询规则
UNION 从查询结果集中自动去除重复的行
如果想返回所有的匹配行,可使用UNION ALL
select
name,age from table_1
union all
select
name,age from join_1;
--返回所有匹配行。
对结果集进行排序
select
name,age from table_1
union all
select
name,age from join_1
order by age;
/*
在用UNION组合查询时,只能使用一条ORDER BY子句,
他必须位于最后一条SELECT语句之后。
*/
/*
某些DBMS还支持另外的俩种UNION:
EXCEPT/MINUS,可以用来检索旨在第一个表中存在而在第二个表中不存在的行;
INTERSECT
可以用来检索俩个表中都存在的行。
*/