1、查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断
select * from people
where peopleId in (select peopleId from people group by peopleId having count(peopleId) > 1)
2、删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断,只留有一个记录
delete from people
where peopleId in (select peopleId from people group by peopleId having count(peopleId) > 1)
and min(id) not in (select id from people group by peopleId having count(peopleId )>1)
3、查找表中多余的重复记录(多个字段)
select * from vitae a
where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
4、删除表中多余的重复记录(多个字段),只留有rowid最小的记录
delete from vitae a
where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)
5、查找表中多余的重复记录(多个字段),不包含rowid最小的记录
select * from vitae a
where (a.peopleId,a.seq) in (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)
6.mysql delete删除关联多表数据
DELETE reviews,reviews_description FROM reviews LEFT JOIN reviews_description ON reviews.reviews_id=reviews_description.reviews_id WHERE reviews.status='0'
7.mysql delete in操作
delete from sns_hits where id not in (select id from another_table)
delete from sns_hits where id not in (select id from sns_hits)# error
CREATE TEMPORARY TABLE tmp_sns_hits ( `id` BIGINT(20) )
DELETE FROM t_tag
WHERE id NOT IN (SELECT * FROM (SELECT MAX(t .id) AS id FROM t_tag t GROUP BY tagname)t)
8.一对多查询
select ID from 表2 where (select CONCAT(',', ksort , ',')AS ksort from 表1 ) LIKE CONCAT('%,', ID , ',%');
from [Mysql删除重复记录](http://blog.baitongda.cn/article/119)
9.group by先排序后分组,group by默认的是第一条记录,相同的iID的记录不会先进行排序再group by
select from (select from t where 你的查询条件 order by 你的排序字段) group by 你的分组字段
10.mysql case when
SELECT count(enq_id) AS total, sum(purchase_amount) AS purchase
FROM temp_stock
WHERE purchase_date <> '0000-00-00'
AND purchase_date < '2012-08-01'
AND ( STATUS = 'Sold'
OR STATUS = 'In Stock'
OR STATUS = 'Ref')
AND CASE STATUS
WHEN 'Sold'
THEN delivery_date >= '2012-08-01'
ELSE 1=1
END
SELECT *
FROM logs
WHERE pw='correct'
AND CASE
WHEN id<800 THEN success=1
ELSE 1=1
END
AND YEAR(TIMESTAMP)=2011
WHERE
pw='correct'
AND (id>=800 OR success=1)
AND YEAR(timestamp)=2011
WHERE
pw='correct'
AND CASE WHEN id<800 THEN success=1 ELSE TRUE END
AND YEAR(timestamp)=2011
--简单Case函数
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他' END
--Case搜索函数
CASE WHEN sex = '1' THEN '男'
WHEN sex = '2' THEN '女'
ELSE '其他' END
mysql 排序去重 sql 写法
| data_id | user_id | data_name |hits
| 1 | 2 | test1 | 140
| 2 | 2 | test2 | 200
| 3 | 3 | test2 | 110
| 4 | 3 | test2 | 10
| 5 | 1 | test2 | 130
| 6 | 4 | test2 | 10
| 7 | 4 | test2 | 100
查询出来下面的 3 条结果,也就是前 3 条点击量最多的数据, user_id 不能重复
SELECT
t.*
FROM
(
SELECT
user_id,
max(hits) AS max_hits
FROM
t
GROUP BY
user_id
) t2
LEFT JOIN t ON t.user_id = t2.user_id
AND t.hits = t2.max_hits
ORDER BY
t2.max_hits DESC
LIMIT 3
| data_id | user_id | data_name |hits
| 2 | 2 | test2 | 200
| 5 | 1 | test2 | 130
| 3 | 3 | test2 | 110
select `stock`.*, `stock1`.`price_current` as `price_current1`, `stock1`.`rank` as `rank1`, `stock`.`price_current` - `stock1`.`price_current` as `percent1` from `stock` inner join `stock` as `stock1` on `stock`.`code` = `stock1`.`code` and `stock`.`date` = '2016-10-10' and `stock1`.`date` = '2016-09-30' and `stock`.`code` = '600817' order by `percent1` desc\G
price_current 这个字段设置了 UNSIGNED ,用 order by 会生成临时表,而临时表也就会同样是 UNSIGNED ,这就导致所有percent1为负值的都变成 0.00 了
delete from `xxx` where id in (select * from (SELECT min(id) FROM `xxx` group by mail having count(mail)>1) as a);
create table tmp_xxx select min(id) as id,mail,password from xxx group by mail,password;
只保留一条不重复数据
DELETE T FROM MYTABLE T LEFT JOIN (SELECT MAX(A.ID) AS ID FROM MYTABLE A GROUP BY A.MAIL) TT ON T.ID = TT.ID WHERE TT.ID IS NULL
删除重复数据中的一条
DELETE T FROM MYTABLE T LEFT JOIN (SELECT MIN(A.ID) AS ID FROM MYTABLE A GROUP BY A.MAIL HAVING COUNT(A.MAIL) > 1) TT ON T.ID = TT.ID WHERE TT.ID IS NOT NULL
MySQL 唯一索引和插入重复自动更新
INSERT INTO table (id, user_id, token) VALUES (NULL, '2479031', '232') ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), token = VALUES(token), online = VALUES(online)
user_id 是唯一索引字段,如果 insert 的时候该 user_id 已经存在,那么就将触发更新而不是插入,此时相当于执行了
update table set user_id = 2479031 token = 232 where user_id = 2479031
mysql导入大批量数据出现MySQL server has gone away的解决方法
http://blog.csdn.net/fdipzone/article/details/51974165
source /tmp/user.sql
mysql> show global variables like 'max_allowed_packet';
+--------------------+---------+
| Variable_name | Value |
+--------------------+---------+
| max_allowed_packet | 4194304 |
+--------------------+---------+
mysql> set global max_allowed_packet=268435456;
使用set global命令修改 max_allowed_packet 的值,重启mysql后会失效,还原为默认值。
如果想重启后不还原,可以打开 my.cnf 文件,添加 max_allowed_packet = 256M 即可
查看当前使用的配置文件my.cnf的方法
locate my.cnf
mysql启动时加载这个配置文件
ps aux|grep mysql|grep 'my.cnf'
如果没有设置使用指定目录的my.cnf,mysql启动时会读取安装目录根目录及默认目录下的my.cnf文件。
mysql --help|grep 'my.cnf'
在mysql默认读取的目录中,创建一个my.cnf文件(例如:/etc/my.cnf),把需要修改的配置内容写入,重启mysql后即可生效
You can't specify target table for update in FROM clause错误的解决方法 不能在同一个sql语句中,先select同一个表的某些值,然后再update这个表
mysql> update message set content='Hello World' where id in(select min(id) from message group by uid);
解决方法:select的结果再通过一个中间表select多一次,就可以避免这个错误
update message set content='Hello World' where id in( select min_id from ( select min(id) as min_id from message group by uid) as a );
Mysql select 中嵌套带子句https://www.v2ex.com/t/318573
SELECT
tt.*,u.name,(SELECT group_concat(title) FROM tag WHERE id IN (tt.tag)) as tag
FROM content tt
LEFT JOIN user u ON tt.owner=u.id
ORDER BY ts_created DESC
SELECT
tt.*,u.name,(SELECT group_concat(title) FROM tag WHERE FIND_IN_SET(id,tt.tag)) as tag
FROM content tt
LEFT JOIN user u ON tt.owner=u.id
ORDER BY ts_created DESC
分组
select p.id,p.productname,p.productcode,p.price,l.num from p
left join (select pid, sum(num) as num from wlms_stock group by pid) l on p.id = l.pid 从表2中获得每个pid的总数sum(num),然后用pid跟表1去连接,这样就既能获得表1的所有数据也能获得表2中的总数了https://segmentfault.com/q/1010000005941808
获取 用户最近10条文章 和 回复的文章https://segmentfault.com/q/1010000007169518
(SELECT id,title,create_time,'article' as type FROM fb_articles WHERE user_id = 4)
UNION
(SELECT a.id,a.title,b.create_time,'reply' as type FROM fb_articles as a,fb_replys as b WHERE a.id = b.article_id AND b.user_id = 4)
ORDER BY
create_time
DESC
LIMIT 10
SELECT * FROM(SELECT user_id,title,create_time FROM article UNION ALL SELECT user_id,article_id,create_time FROM reply) ar WHERE ar.user_id=xxx ORDER BY create_time desc LIMIT 10
MySQL 中将 varchar 字段转换成数字进行排序
将 attr_price 转换为数字再进行排序, *1 即可
'ORDER BY a.sort_order, g.attr_price * 1, g.goods_attr_id';
order by cast(col as unsigned)这会把小数位去掉,不合理
查询并更新到另个表的字段update 表 a inner join
表1 b set a.Nums = b.rcmd_count
where a.id = b.id
数据库返回的整型数据被偷换成了字符串类型
问题出在了 PHP 的 MySQL 驱动上 http://stackoverflow.com/ques...
http://stackoverflow.com/ques...
更新 PHP 的 MySQL 驱动
sudo apt-get update
sudo apt-get install php5-mysqlnd
MySQL 慢查询定位
编辑 my.cnf, 注意,需置于 mysqld 的 section 下
log_slow_queries = /tmp/mysql-slow.log
long_query_time = 2
重启 mysql.
只有 insert, update, delete 慢
set profiling=1;
SHOW PROFILES;
show profile for query 1;
使用 Redis GeoHash 实现附近的XXX
这里 sicily 类似山东省,而 Palermo, Catania 类似烟台、威海,即 Palermo、Catania 是 sicily 辖区内的城市。
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEODIST Sicily Palermo Catania
"166274.15156960039"
redis> GEORADIUS Sicily 15 37 100 km
1) "Catania"
redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
添加时,经度在前,维度在后。
GEORADIUSBYMEMBER yeda "富士康" 1 km
小心,前方有坑! 返回的结果默认是无序的,即不会按照距离远近进行排序。需要手动加上 ASC, DESC 进行排序。
GEORADIUSBYMEMBER yeda "富士康" 10 km WITHDIST ASC
如何在 Laravel 中使用
composer require predis/predis
$items = Redis::georadius("yeda", $lng, $lat, 20, "km", "WITHDIST", "ASC");
2) "Catania"
MySQL 崩溃导致 Discuz! Database Error (2002) notconnect 错误
innodb_buffer_pool_size 的默认值,在 5.5 之后就被调成了 128M, 参考最新的 mysql 5.5, 5.6 文档
在 my.conf 中将这个 buffer 调小
innodb_buffer_pool_size=32M
Redis监控方法
redis-cli info
获取Redis所有Key的方法:
1.终端
获取所有Key命令:redis-cli keys ‘*’ ;
获取指定前缀的key:redis-cli KEYS “edu:*”
如果需要导出,可以redis-cli keys ‘*’ > /data/redis_key.txt
删除指定前缀的Key redis-cli KEYS “edu:*” | xargs redis-cli DEL
2.PHP获取Redis所有Key
获取Redis所有Key:$keys = $redis->keys(‘*’);
获取指定前缀的Key:$keys = $redis->keys(‘edu*’);
删除指定前缀的Key :$redis->delete($redis->keys(‘image*’));
mysql递归查询
https://segmentfault.com/q/1010000007523914
select id,name,pid from (select *from user order by pid,id) a,(select @pv := '8') init where (find_in_set(pid,@pv)>0) and @pv := concat(@pv,',',id) or id = 8;
mysql> delimiter //
mysql>
mysql> CREATE FUNCTION `getChildLst`(rootId INT)
-> RETURNS varchar(1000)
-> BEGIN
-> DECLARE sTemp VARCHAR(1000);
-> DECLARE sTempChd VARCHAR(1000);
->
-> SET sTemp = '$';
-> SET sTempChd =cast(rootId as CHAR);
->
-> WHILE sTempChd is not null DO
-> SET sTemp = concat(sTemp,',',sTempChd);
-> SELECT group_concat(id) INTO sTempChd FROM treeNodes where FIND_IN_SET(pid,sTempChd)>0;
-> END WHILE;
-> RETURN sTemp;
-> END
-> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> select * from treeNodes
-> where FIND_IN_SET(id, getChildLst(1));
+----+----------+------+
| id | nodename | pid |
+----+----------+------+
| 1 | A | 0 |
| 2 | B | 1 |
| 3 | C | 1 |
| 4 | D | 2 |
| 5 | E | 2 |
| 6 | F | 3 |
| 7 | G | 6 |
+----+----------+------+
7 rows in set (0.01 sec)
mysql分组
$res = ['2016-11-18','2016-11-19'];
$s=implode("','",$res);//"2016-11-18','2016-11-19"
echo '\''.$s.'\'';//"'2016-11-18','2016-11-19'"
$sql="select date_format(created,'%Y-%m-%d') as date,count(*) from test where date_format(created,'%Y-%m-%d') in ('\'.$s.'\') group by date order by id desc limit 5;"
mysql优化查询速度
select id from t where num=10 or num=20
select id from t where num=10
union all
select id from t where num=20
select num from a where num in(select num from b)
select num from a where exists(select 1 from b where num=a.num)
MySQL日志查询分析工具pt-query-digest
直接分析慢查询文件
pt-query-digest slow.log > slow_report.log
分析最近12小时内的查询
pt-query-digest --since=12h slow.log > slow_report2.log
批量更新
update table_name set field_name = CASE id
WHEN id1 THEN field_value,
WHEN id1 THEN field_value
END
一个 MySQL 用户名长度的坑
MySQL user names can be up to 32 characters long (16 characters before MySQL 5.7.8). http://dev.mysql.com/doc/refm...
grant all privileges on . to [email protected] identified by ‘123′;
Mysql FIND_IN_SET 语句原始排序
find_in_set单条记录没问题,比如唯一id的in。多条记录order会失效select * from act_log where answer in ('B','C','CD') order by find_in_set( answer,"'B','C','CD'")
排序错误:CD,C,BB,C
select * from tb1 order by a desc ,id desc limit 3; 用limit和order by 一个非唯一字段时,结果集并不总是确定的.已经确定为bughttp://www.codesec.net/view/2...
select SUM(fee
) AS income
, SUM(IF(type
=5, fee
, 0)) AS reward
mysql 如何实现先排序后分组
1、可以先把数据按照你的条件要求,使用order by排好序
2、在查询sql外面,再包一层查询,使用group by
例如: select from (select from t where 你的查询条件 order by 你的排序字段) group by 你的分组字段
MySQL中varchar最大长度是多少
(1)单个字段如果大于65535,则转换为TEXT 。
(2)单行最大限制为65535,这里不包括TEXT、BLOB
查询一个月当中每个人每天的第一次和最后一次记录
SELECT MIN(card_time) AS mintime, MAX(card_time) AS maxtime , user_sn, card_date FROM testtbl GROUP BY user_sn, card_date
数据库去除重复记录
insert into xxxx (select xxx from xxxx)
然后再 delete from xxx where id in (select xxx from xxxx)
alter table 锁表
新建表,数据复制到新表然后 rename 切换 http://www.cnblogs.com/wangta...
按ID降序排序,如果用户状态为0(未激活),则注册时间升序,排在结果最后
select *from user order by status desc,case status when 1 then id end desc,case status when 0 then created_at end asc;
过滤 三个字段 有重复的记录
select * FROM tt t1, tt t2 WHERE t1.userid = t2.userid and t1.pid = t2.pid and t1.tid = t2.tid and s1.id != s2.id
查询total_time > 100
SELECT *
FROM tuanke_time
LEFT JOIN tuanke_student ON tuanke_student.Sid = tuanke_time.studentID
GROUP BY tuanke_time.studentID having SUM(tuanke_time.time) > 100;
查每个用户第一次记录
select user,num from (select * from tb order by time asc) as a group by a.user;
删除重复记录
DELETE FROM price_monitor WHERE id NOT IN (
SELECT * FROM (
SELECT MAX(id) FROM price_monitor GROUP BY domain
)
as tmp
)
limit sum
select uid, sum(skip) as sumskip, time from (select uid, skip, time from attendance where uid = 8499 order by time limit 3) as subt;
mysql删除大量数据,直接delete会锁表
DELIMITER $$
CREATE PROCEDURE delete_temp_tab()
BEGIN
REPEAT
DELETE FROM test.`tab` WHERE id > 111352 LIMIT 1000;
UNTIL ROW_COUNT()=0 END REPEAT;
END $$
DELIMITER ;
CALL delete_temp_tab();
DROP PROCEDURE IF EXISTS delete_temp_tab;
mysql 分页查询优化
EXPLAIN
SELECT
`id`
FROM
`table`
WHERE `node` = 2
ORDER BY `create_at` DESC
LIMIT 12 OFFSET 69996
#查询1
SELECT
`id`
FROM
`table`
WHERE `node` = 2
ORDER BY `id` ASC
LIMIT 10
查询第二页的SQL如下
SELECT
`id`
FROM
`table`
WHERE `node` = 2 AND `id`>10
ORDER BY `id` ASC
LIMIT 10
每次取10000 三次取完
分块
$sql = 'SELECT xxx FROM table WHERE xxx LIMIT limit :limit offset :offset';
$limit = 10000;
$offset = 0;
do{
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$stmt->execute(array(':limit' => $limit, ':offset' => $offset));
$data = $stmt->fetchAll();
// 处理逻辑
$offset += $limit;
}while(count($data));
游标,按行读取返回
$sql = 'SELECT xxx FROM table WHERE xxx';
$stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_LAST);
do {
// 处理逻辑 $row
} while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_PRIOR));
正则匹配手机号前缀
SELECT name FROM users WHERE phone REGEXP '^15[1-4]';
redis setbit
setbit key offset,其中offset用userid取代,如果ID为1的用户是男性就setbit key 1 1,
如果是女性就setbit key 1 0,获取ID为1的性别就getbit key 1
数据迁移
在没有索引的情况下,我会采用先delete后insert。
但在有索引的情况下,我会采用以下方式先update后insert
每半个小时的数据
delimiter $$
CREATE PROCEDURE test()
begin
declare begintime int(10);
set begintime = unix_timestamp("2016-7-31 23:59:59");
loop1:LOOP
IF begintime > unix_timestamp("2016-9-30 23:59:59") then
leave loop1;
END IF;
select * from tablename where timestamp between begintime and begintime+1800;
set begintime = begintime + 1800;
END LOOP loop1;
end;$$
子查询不支持limit
SELECT * FROM yi_user_joke WHERE id in (SELECT id FROM yi_user_joke WHERE status='2' ORDER BY audit_time desc LIMIT 499950,10 ) ORDER BY audit_time desc LIMIT 10 ;
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
SELECT * FROM yi_user_joke a inner join (SELECT id FROM yi_user_joke WHERE status='2' ORDER BY audit_time desc LIMIT 499950,10 ) as b on a.id=b.id ORDER BY a.audit_time desc LIMIT 10 ;
SELECT * FROM yi_user_joke WHERE id in (select *from (SELECT id FROM yi_user_joke WHERE status='2' ORDER BY audit_time desc LIMIT 499950,10 ) as b) ORDER BY audit_time desc LIMIT 10 ;
分组取前五
select * from table as a where (select count(distinct(total)) from table as b where a.stage_id = b.stage_id and b.total > a.total) < 5;where中的select是保证遍历所有记录,取每条记录与当前记录做比较,只有当table表中同一stage_id不超过5个人total当前选择item的total高时,这个item就算是每组total排行的前5名
查询每个部门工资前3名
select * from table d1 where (select count(*) from table d2 where d2.bumen=d1.bumen and d2.salary>d1.salary) < 3 order by d1.salary desc
从一个表中选出最后几个元素
SELECT * FROM (
SELECT * FROM tmp_table ORDER BY id DESC LIMIT 50
) sub
ORDER BY id ASC
选出分组求和的平均数SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1)
FROM t1 GROUP BY column1) AS t1;
group by
group by 是用于分组统计的,会按照分组字段进行排序,如果 order by 和 group by 同时出现,order by 是对 group by 的结果排序,因此取的是根据 group by 排序后各组第一条,但这是有逻辑错误的,好像只有在 MySQL 中可行。
这句 SQL 就好比一个班级的女生按照寝室分组,然后你想知道分组的结果属于谁? 其实谁都不属于,但你可以得到每个组中属性的最大值,最小值,或者具有分组统计意义的信息。 从 MySQL 5.7.5 起,SELECT 不在 GROUP BY 中的字段将会导致数据库拒绝执行查询
order by 只有后面跟着 limit 在子查询才有意义
select * from (select * from table order by <字段 2> limit 1000) as temp group by <字段 1>