常用SQL笔记

记录下SQL笔记,久了没用忘掉了,咳,真TMD郁闷

分组后WHERE用having

SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee GROUP BY FAge HAVING COUNT (*) IN (1,3)

Group by 按需求取得指定数据

SELECT data.* from table as data right join (select max(id) as id from table group by gbfield) as temp on temp.id=data.id

GROUP BY 的时候可以获取用函数获得指定字段的值,通过以上方法可以获取指定结果集 但group by 的字段要做索引,否则效率很低

防止重复数据的产生
SELECT DISTINCT FDepartment FROM T_Employee;

字段间计算

SELECT 125+521 as staticnm,FNumber,FName,FAge * FSalary FROM T_Employee;

字符串处理

SELECT FName, LENGTH(FName) AS namelength FROM T_Employee WHERE FName IS NOT NULL

SELECT FName, SUBSTRING(FName,2,3) FROM T_Employee WHERE FName IS NOT NULL

SELECT CONCAT('年龄:',FAge) FROM T_Employee

结果集联合(需要遵守:一是每个结果集必须有相同的列数;二是每个结果集的列必须类型相容。)

SELECT FNumber,FName,FAge FROM T_Employee UNION SELECT FIdCardNumber,FName,FAge FROM T_TempEmployee

默认情况下,UNION运算符合并了两个查询结果集,需要在联合结果集中返回所有的记录而不管它们是否唯一,则需要在 UNION运算符后使用ALL操作符,比如下面的SQL语句:
SELECT FName,FAge FROM T_Employee UNION ALL SELECT FName,FAge FROM T_TempEmployee

使用UNION的时候各列的顺序最好相同,不然有很多意想不到的结果

MYSQL中使用DATEDIFF()函数用于计算两个日期之间的差额

SELECT FRegDay,FBirthDay, DATEDIFF(FRegDay, FBirthDay) , DATEDIFF(FBirthDay ,FRegDay)FROM T_Person

CASE函数

SELECT FName,

(CASE FName

WHEN 'Tom' THEN 'GoodBoy'
WHEN 'Lily' THEN 'GoodGirl'
WHEN 'Sam' THEN 'BadBoy'
WHEN 'Kerry' THEN 'BadGirl'
ELSE 'Normal'
END) as isgood

FROM T_Person

但字段值为NULL的时候case NULL 无效

该使用 

 

SELECT FName,

if (isnull(isgood),'good','bad') as isgood

FROM T_Person

 

 

MYSQL不支持如下,当DB2等数据库支持

一次定义多次使用

WITH person_tom AS
(
SELECT * FROM T_Person
WHERE FName='TOM'
)
SELECT * FROM T_Person
WHERE FAge=person_tom.FAge
OR FSalary=person_tom.FSalary

 

ANY关键词的意思是“对于在子查询返回的列中的任一数值,如果比较结果为TRUE的话,则返回TRUE”。
有一真为真
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
词语IN是=ANY的别名。因此,这两个语句是一样的:
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN    (SELECT s1 FROM t2);
词语ALL必须接在一个比较操作符的后面。ALL的意思是“对于子查询返回的列中的所有值,如果比较结果为TRUE,则返回TRUE。”例如:
多个比较
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);
如果在表t2的一个行中,column1=1并且column2=2,则查询结果均为TRUE。

 

EXISTS和NOT EXISTS
EXISTS (有结果为真 无结果为假) 下个相反
如果一个子查询返回任何的行,则EXISTS subquery为FALSE 
子查询结果为单个时候可以直接等于~(小心使用~)
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
正常表达式
select * from xxx where  aa regexp 'xxx';
select * from xxx where aa regexp "";

join 将两个表合到一个表进行查询 字段合并 合并条件以on为准
select * from test1 join test2 on test1.a=test2.d
select * from t1 join  (t2, t3, t4) on (t1.id=t2.id and t2.id=t3.id and t3.id=t1.id ) #复杂查询
记得跟ON 语句
left join  以左表为基准
right join 以右表为基准
join 两个表都因同时存在记录为基准

 

链表删除
delete t1 from test1 as t1 join test2 ad t2 on t1.a=t2.a where t2.c='3'

链表更新

update test1 ad t1 join test2 as t2 on t1.a=t2.a set t1.b='100' where t2.c='4';

链表同步
update test1 as t1 join test2  as t2 set t1.b=t2.c where t1.a=t2.a

查询插入

 

insert into b (level,name) select level,name from a order by level desc limit 20 ; 

 

连表分页

select * from (select * from test1 union select * from test2) as temp limit 0,100;

返回一个不同值的数目。
mysql> select COUNT(DISTINCT results) from student;

 

group by 中字段中使用函数是对汇总子表的操作
汇总并返回平均数
mysql> select student_name, AVG(test_score)
           from student
           GROUP BY student_name;

链表的时候尽量不要GROUP BY ,是非常缓慢的...

INSTR(str,substr)
返回子串substr在字符串str中的第一个出现的位置。这与有2个参数形式的LOCATE()相同,除了参数被颠倒。
mysql> select INSTR('foobarbar', 'bar');
        -> 4
mysql> select INSTR('xbar', 'foobar');
        -> 0

 

LPAD(str,len,padstr)
返回字符串str,左面用字符串padstr填补直到str是len个字符长。
mysql> select LPAD('hi',4,'??');
        -> '??hi'
 
LEFT(str,len)
返回字符串str的最左面len个字符。
mysql> select LEFT('foobarbar', 5);
        -> 'fooba'

该函数是多字节可靠的。

RIGHT(str,len)
返回字符串str的最右面len个字符。
mysql> select RIGHT('foobarbar', 4);
        -> 'rbar'

该函数是多字节可靠的。


REPEAT(str,count)
返回由重复countTimes次的字符串str组成的一个字符串。如果count <= 0,返回一个空字符串。如果str或count是NULL,返回NULL。
mysql> select REPEAT('MySQL', 3);
        -> 'MySQLMySQLMySQL'
LOWER(str)
返回字符串str,根据当前字符集映射(缺省是ISO-8859-1 Latin1)把所有的字符改变成小写。该函数对多字节是可靠的。
mysql> select LCASE('QUADRATICALLY');
        -> 'quadratically'

 

查询插入:

insert into table1 select field21 as field11 ,field22 ad field12 from table2 where file11='test';

查询结果创建一个列并赋值默认值

select *,'test' as newfield from test;

 汇总后合并汇总那些行的结果到一行

SELECT g, group_concat( test1 SEPARATOR "-" ) AS bbb FROM a_test GROUP BY g

不一定搭配group by 使用

SELECT g, group_concat( test1 SEPARATOR "-" ) AS bbb FROM a_test

直接把表里指定字段的数据全链接,默认用,链接

除非简单查询,GROUP_CONCAT用于复杂查询将是不可行的

 

插入更新:ON DUPLICATE KEY UPDATE

条件更新:(非常有用~)

update t2
set b=case
when a<2 then b+1
when a>2 then 0
end

UNIX时间戳转日期格式

select FROM_UNIXTIME(1156219870);
 

连表join注意:join 的时候会连接一个表,组成新表后在连下一个表,如

 SELECT * FROM `a_ta` as ta join a_tc as tc on ta.id=tc.id  join a_tb as tb on ta.id=tb.id

先a_ta和a_tc组成一个表,在和a_tb组成一个表

没有on语句的时候 会由每一个记录来组成一个表,所以查出来的结果是两个表记录的卡迪尔积,

join on结果是两个表同时存在记录的那些记录 但ON不能加判断值.

如 on ta.id='1' 是不行的...

 

 

where between a and b;//在字段AB之间

where between 1 and 2;//在1和2之间

 

 

行转列

//转自:cnblogs.com/kerrycode

我们首先先通过一个老生常谈的例子,学生成绩表(下面简化了些)来形象了解下行转列 

代码
CREATE  TABLE [StudentScores]
(
    
[UserName]         NVARCHAR(20),        --学生姓名
    [Subject]          NVARCHAR(30),        --科目
    [Score]            FLOAT,               --成绩
)

INSERT INTO [StudentScores] SELECT 'Nick''语文'80

INSERT INTO [StudentScores] SELECT 'Nick''数学'90

INSERT INTO [StudentScores] SELECT 'Nick''英语'70

INSERT INTO [StudentScores] SELECT 'Nick''生物'85

INSERT INTO [StudentScores] SELECT 'Kent''语文'80

INSERT INTO [StudentScores] SELECT 'Kent''数学'90

INSERT INTO [StudentScores] SELECT 'Kent''英语'70

INSERT INTO [StudentScores] SELECT 'Kent''生物'85

 

 如果我想知道每位学生的每科成绩,而且每个学生的全部成绩排成一行,这样方便我查看、统计,导出数据

代码
SELECT 
      UserName, 
      
MAX(CASE Subject WHEN '语文' THEN Score ELSE 0 ENDAS '语文',
      
MAX(CASE Subject WHEN '数学' THEN Score ELSE 0 ENDAS '数学',
      
MAX(CASE Subject WHEN '英语' THEN Score ELSE 0 ENDAS '英语',
      
MAX(CASE Subject WHEN '生物' THEN Score ELSE 0 ENDAS '生物'
FROM dbo.[StudentScores]
GROUP BY UserName
解释:增加4列,并根据指定行的情况赋值该列,汇总结果并取得指定列的最大值,没有该记录结果就是0

 

 按照IN里的顺序取数据

id in (1,2,3) order by FIELD(id, 1,2,3)

id in (1,2,3) order by substring_index('1,2,3',id,1);

//效率都差不多~

 

重结果集里获取随机数据

SELECT * FROM ko_channel ORDER BY rand() LIMIT 2

 

分组结果并获取每条分组中的一个记录

select *, count(distinct name) from table group by name

 

SQL获取两个经纬度距离

6367000*2*ASIN(LEAST(
1,SQRT(
POW( SIN( (RADIANS(X(GEOMFROMTEXT('POINT({$point})'))) - RADIANS(X(location))) /2 ), 2)
+
COS(
RADIANS(X(location))
)
*COS(
RADIANS(X(GEOMFROMTEXT('POINT({$point})')))
)
*POW( SIN( (RADIANS(Y(GEOMFROMTEXT('POINT({$point})'))) - RADIANS(Y(location))) / 2 ), 2 )
)
))

 

存储过程动态调用存储过程

SET @fn = CONCAT('CALL order_rollback_',buy_type,'(?,?)');
PREPARE stmt1 FROM @fn;
SET @a = id_product;
SET @b = buy_num;
EXECUTE stmt1 USING @a, @b;
DEALLOCATE PREPARE stmt1;

 

事件

CREATE EVENT order_pay_rollback ON SCHEDULE AT '2016-11-11 11:11:11' ON COMPLETION NOT PRESERVE ENABLE DO CALL order_pay_rollback(11);

存储过程

CREATE PROCEDURE order_pay_rollback(id_order_pay int)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE id_product int;
DECLARE cur1 CURSOR FOR SELECT
id_product as id_product
FROM p  
WHERE id_order_pay=id_order_pay ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO id_product;
IF done THEN
LEAVE read_loop;
END IF;
CALL order_rollback(id_product);
END LOOP;
close cur1;
END;

posted @ 2010-08-22 01:25  liushan  阅读(365)  评论(0编辑  收藏  举报