语法汇总:添加链接描述
基本思路 Loop Join
首先想到的思路是一个类似于Loop Join的方法:
A. 取出2012-1-1到2012-1-11的每一条记录.
B. 对取出的每一条记录,再去表中查询这个用户的接下来6天的记录。
如果总数为6条记录,则满足连续7天的条件
- Range Join
Loop Join的思路可以通过一个Join语句来实现。姑且称之为Range Join。通常join时,使用的都是
等值join. 如果join列的值是唯一的,那么就是左表的一条记录对应右表的一条记录。而Range Join
中,左表的一行数据对应右表的一个范围内的所有记录。
- COUNT(DISTINCT)
“计算连续7天”,可以通过GROUP BY分组和COUNT()来完成。因为一个用户在1天内可能会有多次登录,
这里需要使用(COUNT DISTINCT). SQL 语句为:
SELECT DISTINCT t.uid FROM tmp_test AS t JOIN tmp_test AS t1
ON date(t.login_time) + 1 <= date(t1.login_time) AND
date(t.login_time) + 7 > date(t1.login_time) AND
t.uid = t1.uid
WHERE t.login_time BETWEEN ’2012-1-1 00:00:00′ AND ’2012-1-11 23:59:59′ AND
t1.login_time >= ’2012-1-2′ AND t.login_time < ’2012-1-18′(可去掉)
GROUP BY t.login_time, t.uid
HAVING COUNT(DISTINCT date(t1.login_time))=6
参考 :添加链接描述
1.“Where” 是一个约束声明,使用Where来约束来之数据库的数据,Where是在结果返回之前起作用的,且Where中不能使用聚合函数。
“Having”是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在Having中可以使用聚合函数。
2. 执行顺序where-group by -having
. WHERE语句在GROUPBY语句之前;SQL会在分组之前计算WHERE语句。
HAVING语句在GROUPBY语句之后;SQL会在分组之后计算HAVING语句。
3.where是对原始数据条件的筛选,having是对分组后数据的筛选。
**举例:**下面以一个例子来具体的讲解:
写:select -from -where -group by -having -order by
执行: from -where -group by -having -select- order by
添加链接描述
(1)用法
<窗口函数> over (partition by <用于分组的列名>
order by <用于排序的列名>)**只能用在select语句
(2)专用窗口函数:rank(),dense_rank(),row_number()
聚合函数:sum,avg,count,max,min
1.窗口函数语法
<窗口函数> over (partition by <用于分组的列名>
order by <用于排序的列名>)
<窗口函数>的位置,可以放以下两种函数:
1) 专用窗口函数,比如rank, dense_rank, row_number等
2) 聚合函数,如sum. avg, count, max, min等
专用窗口函数使用规则:
rank函数:这个例子中是5位,5位,5位,8位,也就是如果有并列名次的行,会占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,4。
dense_rank函数:这个例子中是5位,5位,5位,6位,也就是如果有并列名次的行,不占用下一名次的位置。比如正常排名是1,2,3,4,但是现在前3名是并列的名次,结果是:1,1,1,2。
row_number函数:这个例子中是5位,6位,7位,8位,也就是不考虑并列名次的情况。比如前3名是并列的名次,排名是正常的1,2,3,4。
2.窗口函数有以下功能**:
1)同时具有分组(partition by)和排序(order by)的功能
2)不减少原表的行数,所以经常用来在每组内排名
3.注意事项
窗口函数原则上只能写在select子句中
4.窗口函数使用场景
业务需求“在每组内排名”,比如:
排名问题:每个部门按业绩来排名
topN问题:找出每个部门排名前N的员工进行奖励
Case具有两种格式。简单Case函数和Case搜索函数。
第一种 格式 : 简单Case函数 :
格式说明
case 列名
when 条件值1 then 选项1
when 条件值2 then 选项2.......
else 默认值 end
eg:
select
case job_level
when '1' then '1111'
when '2' then '1111'
when '3' then '1111'
else 'eee' end
from dbo.employee
第二种 格式 :Case搜索函数
格式说明
case
when 列名= 条件值1 then 选项1
when 列名=条件值2 then 选项2.......
else 默认值 end
eg:
update employee
set e_wage =
case
when job_level = '1' then e_wage*1.97
when job_level = '2' then e_wage*1.07
when job_level = '3' then e_wage*1.06
else e_wage*1.05
end
提示:通常我们在写Case When的语句的时候,会容易忘记 end 这个结束,一定要记得哟!
比较: 两种格式,可以实现相同的功能。
简单Case函数的写法相对比较简洁,但是和Case搜索函数相比,功能方面会有些限制,比如写判断式。还有一个需要注意的问题,Case函数只返回第一个符合条件的 值,剩下的Case部分将会被自动忽略。
二、case when使用案例
关于case when的使用情况有三种,第一、等值转换,第二、范围转换,第三、列转行操作。
1.等值转换
咱们在设计数据库的时候总是会把用户的性别用int存储**('0’为女,'1’为男),但是怎么把它转换成汉字显示**呢?
原始表数据
SQL语句
select
name as '名字',
(case sex when 0 then '女' else '男' end) as '性别'
from test.student;
2.范围转换
有的时候,也会遇到这种情况,按照用户成绩显示优(90+)、良(80-90)、及格(60-80)、未及格(60-),这个跟第一个不同的是,他是一个分数的范围,要怎么转换成汉子显示呢?你可能觉得很简单,不就是吧when那换成条件吗?先打住咱们往下看
原始表数据
SQL语句
select name as '姓名',
(case
when score>=90 then '优'
when score>=80 then '良'
when score>=60 then '及格'
else '不及格' end)
as '等级'
from test.stu_score;
3.列转行操作
还是用学生的例子吧,现在有图1学生成绩数据, 现在要怎么按图2显示出来呢?
图1图2
第一步 先按照科目分开, 符合条件的设置分数,不符合的给置零。
select name as '姓名'
,(case course when '语文' then score else 0 end) as '语文'
,(case course when '数学' then score else 0 end) as '数学'
,(case course when '英语' then score else 0 end) as '英语'
from test.course_score
select name as '姓名'
,max(case course when '语文' then score else 0 end) as '语文'
,max(case course when '数学' then score else 0 end) as '数学'
,max(case course when '英语' then score else 0 end) as '英语'
from test.course_score group by name;
SELECT
UserName,
MAX(CASE Subject WHEN '语文' THEN Score ELSE 0 END) AS '语文',
MAX(CASE Subject WHEN '数学' THEN Score ELSE 0 END) AS '数学',
MAX(CASE Subject WHEN '英语' THEN Score ELSE 0 END) AS '英语',
MAX(CASE Subject WHEN '生物' THEN Score ELSE 0 END) AS '生物'
FROM dbo.[StudentScores]
GROUP BY UserName
2.PIVOT 函数
SELECT * FROM [StudentScores] /*数据源*/
AS P
PIVOT
(
SUM(Score/*行转列后 列的值*/) FOR
p.Subject/*需要行转列的列*/ IN ([语文],[数学],[英语],[生物]/*列的值*/)
) AS T
limit 和 limit offset用法
两种方法:
(1)LIMIT A;
#表示从第一条记录开始取A条记录;
(2)LIMIT A,B;
#参数A为可选参数,表示跳过A条数据(默认为0)
#参数B为必选参数,表示取B行数据;
eg1:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
等价于
SELECT * FROM table LIMIT 0,5; //检索前 5 个记录行
eg2:
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
#为了检索某行开始到最后的所有数据,可以设置第二个参数为-1
eg3:
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last
LIMIT OFFSET:
1 LIMIT a OFFSET b
2 #表示跳过b个数据,取a个数据
3 #参数a表示读取a条数据
4 #参数b表示跳过b个数据
5 eg4:
6 SELECT * FROM table LIMIT 2 OFFSET 1; //跳过1条数据读取2条数据,即读取2-3条数据
LIMINT 和 LIMIT OFFSET区别
1 eg5:
2 SELECT * FROM table LIMIT 2,1; //跳过2条数据读取1条数据,即读取3条数据
3 SELECT * FROM table LIMIT 2 OFFSET 1; //跳过1条数据读取2条数据,即读取2-3条数据
Sql Server
DATEDIFF() 函数返回两个日期之间的时间。
DATEDIFF(datepart,startdate,enddate)
yy-mm-dd,hh-mi-ss-ms-mcs-ns qq季度ww周
添加链接描述
MySql
DATEDIFF() 函数返回两个日期之间的天数。
语法
DATEDIFF(date1,date2)
返回date1-date2
反引号
反引号:反引号一般在Esc键的下方,为了区分MySQL的保留字与普通字符而引入的符号。
一般我们建表时都会将表名,库名都加上反引号来保证语句的执行度。
例如:
SELECT * FROM user
WHERE username LIKE ‘%王%’;
在user表中,有个user字段,如果不用反引号,MYSQL将把user视为保留字而导致出错,所以,有MYSQL保留字作为字段的,必须加上反引号来区分。
引号
单引号 和 双引号
在标准SQL中,字符串使用的是单引号。
如果字符串本身也包括单引号,则使用两个单引号(注意,不是双引号,字符串中的双引号不需要另外转义)。
MySQL对 SQL 的扩展,允许使用单引号和双引号两种。
参考自添加链接描述
%出来的数有正有负,符号取决于左操作数,而mod只能是正;
所以要用%来计算mod的话就要用这样的公式:a mod b = (a % b + b) % b;
括号中的式子可以把左操作数转变为正数。
参考链接:添加链接描述
学习链接:添加链接描述
select *,
concat(round(100 * 次日留存用户数/活跃用户数, 2), '%') 次日留存率,
concat(round(100 * 三日留存用户数/活跃用户数, 2), '%') 三日留存率,
concat(round(100 * 七日留存用户数/活跃用户数, 2), '%') 七日留存率
from (
select
a.log_day 日期,
count(distinct(concat(a.device_id, a.app_id))) 活跃用户数,
count(distinct(concat(b.device_id, b.app_id))) 次日留存用户数,
count(distinct(concat(c.device_id, c.app_id))) 三日留存用户数,
count(distinct(concat(d.device_id, d.app_id))) 七日留存用户数
from user_log a
left join user_log b on concat(a.device_id, a.app_id) = concat(b.device_id, b.app_id) and b.log_day = a.log_day + 1
left join user_log c on concat(a.device_id, a.app_id) = concat(c.device_id, c.app_id) and c.log_day = a.log_day + 3
left join user_log d on concat(a.device_id, a.app_id) = concat(d.device_id, d.app_id) and d.log_day = a.log_day + 7
group by a.log_day
) p;
union 对两个结果集进行并集操作,重复数据只显示一次
Union All,对两个结果集进行合并操作,重复数据全部显示
1.distinct
用distinct关键字只能过滤查询字段中所有记录相同的(记录集相同),而如果要指定一个字段却没有效果,另外distinct关键字会排序,效率很低 。
2.下面语句可以查询出那些数据是重复的: (部分字段相同的过滤)
有聚合函数的条件写在having 后面
如果在上句中having加 count()>1 就可以查出记录A的重复次数大于1的记录
如果在上句中having加 count()>2 就可以查出记录A的重复次数大于2的记录
如果在上句中having加 count()>=1 就可以查出所有的记录,但重复的只显示一条,并且后面有显示重复的次数----这就是所需要的结果,而且语句可以通过Hibernate
**group by having count()**
select 字段1,字段2,count(*) from 表名 group by 字段1,字段2 having count(*) >= 1
将上面的>号改为=号就可以查询出没有重复的数据了。
参考自
3.部分字段相同,有主键
SELECT * FROM TABLE WHERE ID IN (SELECT MAX(ID) FROM TABLE GROUP BY [去除重复的字段名列表,....])
4.部分字段相同,没有主键
两条记录之间之后只有部分字段的值是有重复的,但是表不存在主键或者唯一性ID。这种情况可以使用临时表,将数据复制到临时表并添加一个自增长的ID,在删除重复数据之后再删除临时表。
//创建临时表,并将数据写入到临时表
SELECT IDENTITY(INT1,1) AS ID,* INTO NEWTABLE(临时表) FROM TABLE
//查询不重复的数据
SELECT * FROM NEWTABLE WHERE ID IN (SELECT MAX(ID) FROM NEWTABLE GROUP BY [去除重复的字段名列表,....])
//删除临时表
DROP TABLE NEWTABLE
参考自
一、AVG()求平均值
注意AVE()忽略NULL值,而不是将其作为“0”参与计算
二、COUNT()
两种用法
1、COUNT()
对表中行数进行计数 不忽略
不管是否有NULL
2、COUNT(字段名)
对特定列有数据的行进行计数
忽略NULL值
三、SUM()
可以对单个列求和,也可以对多个列运算后求和
忽略NULL值,且当对多个列运算求和时,如果运算的列中任意一列的值为NULL,则忽略这行的记录。
例如: SUM(A+B+C),A、B、C 为三列,如果某行记录中A列值为NULL,则不统计这行。
结论:忽略NULL值,count()某一列位空不忽略
count(*):所有行进行统计,包括NULL行
count(1):所有行进行统计,包括NULL行
count(column):对column中非Null进行统计
结论:count(*)与count(1)基本等价,
转载自
sql,left join执行原理,on和where区别。inner join是一样的,笛卡尔积;sql遇见名和关键字是一样的情况(‘group’)
参考自
1在使用left jion时,on和where条件的区别如下:
.数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。
1、 on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。
其实以上结果的关键原因就是left join,right join,full join的特殊性,不管on上的条件是否为真都会返回left或right表中的记录,full则具有left和right的特性的并集。
而inner join没这个特殊性,则条件放在on中和where中,返回的结果集是相同的。on为了反映外连接中一方的全连接,而where没有这个功能,内连接配对是可以的。
1.执行顺序
on、where、having这三个都可以加条件的子句中,on是最先执行,where次之,having最后。有时候如果这先后顺序不影响中间结果的话,那最终结果是相同的。但因为on是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的。
2.执行速度
根据上面的分析,可以知道where也应该比having快点的,因为它过滤数据后才进行sum,所以having是最慢的。但也不是说having没用,因为有时在步骤3还没出来都不知道那个记录才符合要求时,就要用having了。
在两个表联接时才用on的,所以在一个表的时候,就剩下where跟having比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where可以使用rushmore技术,而having就不能,在速度上后者要慢。
如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据上篇写的工作流程,where的作用时间是在计算之前就完成的,而having就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。
在多表联接查询时,on比where更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什幺时候起作用,然后再决定放在那里
3.不起作用的时候
对于JOIN参与的表的关联操作,如果需要不满足连接条件的行也在我们的查询范围内的话,我们就必需把连接条件放在ON后面,而不能放在WHERE后面,如果我们把连接条件放在了WHERE后面,那幺所有的LEFT,RIGHT,等这些操作将不起任何作用,对于这种情况,它的效果就完全等同于INNER连接。对于那些不影响选择行的条件,放在ON或者WHERE后面就可以。
记住:所有的连接条件都必需要放在ON后面,不然前面的所有LEFT,和RIGHT关联将作为摆设,而不起任何作用。
详细可参考链接
select a.* from tb a where exists(select 1 from tb where name =a.name)
返回真假,当where 后面的条件成立,则列出数据,否则为空。
exists强调的是是否返回结果集,不要求知道返回什么。比如:
select name from student where sex = 'm' and mark exists(select 1 from grade where ...)
只要exists引导的子句有结果集返回,那么exists这个条件就算成立了,大家注意返回的字段始终为1,如果改成“select 2 from grade where …”,那么返回的字段就是2,这个数字没有意义。所以exists子句不在乎返回什么,而是在乎是不是有结果集返回。
转载自
2. EXISTS与IN的使用效率
通常情况下采用exists要比in效率高,因为IN不走索引,但要看实际情况具体使用:
IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。
3. not in 和 not exists
3.1. not in和not exists的区别:
not in 只有当子查询中,select 关键字后的字段有not null约束或者有这种暗示时用not in,另外如果主查询中表大,子查询中的表小但是记录多,则应当使用not in,
例如:查询那些班级中没有学生的,
select * from class where cid not in(select distinct cid from stu)
当表中cid存在null值,not in 不对空值进行处理
解决:
select * from class
where cid not in
(select distinct cid from stu where cid is not null)
not in的执行顺序是:
是在表中一条记录一条记录的查询(查询每条记录)符合要求的就返回结果集,不符合的就继续查询下一条记录,直到把表中的记录查询完。也就是说为了证明找不到,所以只能查询全部记录才能证明。并没有用到索引。
3.2 not exists:
如果主查询表中记录少,子查询表中记录多,并有索引。
例如:查询那些班级中没有学生的,
select * from class2
where not exists
(select * from stu1 where stu1.cid =class2.cid)
not exists的执行顺序是:
在表中查询,是根据索引查询的,如果存在就返回true,如果不存在就返回false,不会每条记录都去查询。
之所以要多用not exists,而不用not in,也就是not exists查询的效率远远高与not in查询的效率。
转载自
转载自
一般模糊查询语句如下:
SELECT 字段 FROM 表 WHERE 某字段 Like 条件
其中关于条件,SQL提供了四种匹配模式:
1,% :表示任意0个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,请使用两个百分号(%%)表示。
比如 SELECT * FROM [user] WHERE u_name LIKE '%三%'
将会把u_name为“张三”,“张猫三”、“三脚猫”,“唐三藏”等等有“三”的记录全找出来。
另外,如果需要找出u_name中既有“三”又有“猫”的记录,请使用and条件
SELECT * FROM [user] WHERE u_name LIKE '%三%' AND u_name LIKE '%猫%'
若使用 SELECT * FROM [user] WHERE u_name LIKE '%三%猫%'
虽然能搜索出“三脚猫”,但不能搜索出符合条件的“张猫三”。
2,_ : 表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字符长度语句:
比如 SELECT * FROM [user] WHERE u_name LIKE '_三_'
只找出“唐三藏”这样u_name为三个字且中间一个字是“三”的;
再比如 SELECT * FROM [user] WHERE u_name LIKE '三__';
只找出“三脚猫”这样name为三个字且第一个字是“三”的;
3,[ ] :表示括号内所列字符中的一个(类似正则表达式)。指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个。
比如 SELECT * FROM [user] WHERE u_name LIKE '[张李王]三'
将找出“张三”、“李三”、“王三”(而不是“张李王三”);
如 [ ] 内有一系列字符(01234、abcde之类的)则可略写为“0-4”、“a-e”
SELECT * FROM [user] WHERE u_name LIKE '老[1-9]'
将找出“老1”、“老2”、……、“老9”;
4,[^ ] :表示不在括号所列之内的单个字符。其取值和 [] 相同,但它要求所匹配对象为指定字符以外的任一个字符。
比如 SELECT * FROM [user] WHERE u_name LIKE '[^张李王]三'
将找出不姓“张”、“李”、“王”的“赵三”、“孙三”等;
SELECT * FROM [user] WHERE u_name LIKE '老[^1-4]';
将排除“老1”到“老4”,寻找“老5”、“老6”、……
转载自
一、SQL中的语法
1、drop table 表名称 eg: drop table dbo.Sys_Test
2、truncate table 表名称 eg: truncate table dbo.Sys_Test
3、delete from 表名称 where 列名称 = 值 eg: delete from dbo.Sys_Test where test=‘test’
二、drop,truncate,delete区别
1、drop (删除表):删除内容和定义,释放空间。简单来说就是把整个表去掉.以后要新增数据是不可能的,除非新增一个表。
drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger)索引(index);依赖于该表的存储过程/函数将被保留,但其状态会变为:invalid。
2、truncate (清空表中的数据):删除内容、释放空间但不删除定义(保留表的数据结构)。与drop不同的是,只是清空表数据而已。
注意:truncate 不能删除行数据,要删就要把表清空。
3、delete (删除表中的数据):delete 语句用于删除表中的行。delete语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。
truncate与不带where的delete :只删除数据,而不删除表的结构(定义)
4、truncate table 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用delete。
如果要删除表定义及其数据,请使用 drop table 语句。
5、对于由foreign key约束引用的表,不能使用truncate table ,而应使用不带where子句的delete语句。由于truncate table 记录在日志中,所以它不能激活触发器。
6、执行速度,一般来说: drop> truncate > delete。
7、delete语句是数据库操作语言(dml),这个操作会放到 rollback segement 中,事务提交之后才生效;如果有相应的 trigger,执行的时候将被触发。
truncate、drop 是数据库定义语言(ddl),操作立即生效,原数据不放到 rollback segment 中,不能回滚,操作不触发 trigger。