一些sql用法例子【Updating】
1、利用instr連線表做欄位查詢,group_concat做值的合併:
create table ab(product_id int,product_name varchar(10), product_type_id varchar(10)); insert into ab values(1,'產品A','1,2'),(2,'產品B','2,3'); create table ac(product_type_id int,product_type_name varchar(10)); insert into ac values(1,'類別1'),(2,'類別2'),(3,'類別3'); select product_id,product_name,ab.product_type_id,group_concat(product_type_name) as typename from ab,ac where instr(ab.product_type_id,ac.product_type_id) group by product_id,product_name; root @localhost : bbb 14:45:24>select * from ab; +------------+--------------+-----------------+ | product_id | product_name | product_type_id | +------------+--------------+-----------------+ | 1 | 產品A | 1,2 | | 2 | 產品B | 2,3 | +------------+--------------+-----------------+ 2 rows in set (0.01 sec) root @localhost : bbb 14:55:54>select * from ac; +-----------------+-------------------+ | product_type_id | product_type_name | +-----------------+-------------------+ | 1 | 類別1 | | 2 | 類別2 | | 3 | 類別3 | +-----------------+-------------------+ 3 rows in set (0.00 sec) root @localhost : bbb 14:55:56>select product_id,product_name,ab.product_type_id,group_concat(product_type_name) as typename from ab,ac where instr(ab.product_type_id,ac.product_type_id) group by product_id,product_name; +------------+--------------+-----------------+-----------------+ | product_id | product_name | product_type_id | typename | +------------+--------------+-----------------+-----------------+ | 1 | 產品A | 1,2 | 類別2,類別1 | | 2 | 產品B | 2,3 | 類別2,類別3 | +------------+--------------+-----------------+-----------------+ 2 rows in set (0.01 sec) root @localhost : bbb 14:56:00>
from:http://topic.csdn.net/u/20120913/15/22d39ecf-da3e-4088-a7d1-aa095cae4b7a.html
2、find_in_set 用法:
有兩張表:
a: id name 1 tom 2 terry ... b: fid ids 1 1,2 ...
如果需要根據表b的ids列找出表a對應的name:
select name from a where find_in_set (id ,(select ids from b where fid = 1))
http://topic.csdn.net/u/20120921/16/3f940141-7d64-46b9-9a87-c0dbf4ed4ae9.html
3、MySQL group by with rollup的用法:對列做統計
GROUP BY Modifiers 官方手冊裡面對這個rollup有一個專門的頁面介紹 地址在這裡,說得非常詳細,我這裡做一個簡單的例子重現
建一個簡單的表並插入幾條簡單的資料
CREATE TABLE `t` (
`id` int(11) DEFAULT NULL,
`id2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk
insert into t valeu(11,11),(12,12),(13,13);
先來做一個查詢
root@test 03:44:32>select id,sum(id2),avg(id2) from t group by id with rollup; +——+———-+———-+ | id | sum(id2) | avg(id2) | +——+———-+———-+ | 11 | 11 | 11.0000 | | 12 | 12 | 12.0000 | | 13 | 13 | 13.0000 | | NULL | 36 | 12.0000 | +——+———-+———-+ 4 rows in set (0.00 sec)
我們可以看到,對於group by的列,with rollup將不會做任何的操作,而是返回一個NULL,而沒有group by的列,則根據前面的avg函式和sum函式值產生的列做了統計處理。這樣 group by + 聚合函式 統計了行資料,而 with rollup 產生了列資料,即生成了一張行列交錯的統計報表。
4、自連線生成id範圍段
mysql> select * from table1;
+----+------+
| id | num |
+----+------+
| 1 | 1001 |
| 2 | 1001 |
| 3 | 1001 |
| 4 | 1001 |
| 5 | 1002 |
| 6 | 1002 |
| 7 | 1001 |
| 8 | 1001 |
| 9 | 1002 |
+----+------+
9 rows in set (0.00 sec)
mysql> select num,
-> concat('連續',count(*) ,'次 從', min(sid) ,'至',eid) as cnt
-> from (
-> select a.id as sid,max(b.id) as eid,a.num
-> from table1 a , table1 b
-> where a.id<=b.id
-> and a.num=b.num
-> and not exists (select 1 from table1 where id between a.id and b.id and num!=a.num)
-> group by a.id
-> ) t
-> group by eid;
+------+----------------+
| num | cnt |
+------+----------------+
| 1001 | 連續4次 從1至4 |
| 1002 | 連續2次 從5至6 |
| 1001 | 連續2次 從7至8 |
| 1002 | 連續1次 從9至9 |
+------+----------------+
4 rows in set (0.00 sec)
mysql>
http://bbs.csdn.net/topics/390420571
5、MySQL如何查詢兩列互不重複的記錄?
資料如下:
id date fromId toId -------------------------------------- 1 2013-01-01 1 2 2 2013-01-02 2 1 3 2013-01-03 1 3 4 2013-01-04 3 1 5 2013-01-05 4 1 6 2013-01-06 1 4
如何才能查詢出fromId或toId包含某個值,但fromId和toId不相互重複的資料? 例如,查詢fromId或toId包含1,去除fromId和toId中資料互換的列,僅取日期最大的值,查詢結果為:
id date fromId toId -------------------------------------- 2 2013-01-02 2 1 4 2013-01-04 3 1 6 2013-01-06 1 4
SELECT max(`date`),maxId,minId FROM (SELECT `date`,IF(fromId>toId,fromId,toId) AS maxId,IF(fromId>toId,toId,fromId) AS minId FROM `table`) AS `tmp` GROUP BY maxId,minId
http://segmentfault.com/q/1010000000191842
6、select sum(case when then end) as group by 按指定維度多行統計求和
我有表table_1 name class score 張三 數學 80 張三 語文 70 李四 數學 70 李四 語文 80 一個sql查詢出每個人每科的總分:
select name,
sum(CASE WHEN class ='數學' THEN score END) as `數學`,
sum(CASE WHEN class ='語文' THEN score END) as `語文`,
from table_1
where name='張三'
group by name
http://bbs.csdn.net/topics/390445500
7、自連線求子節點記錄數:
id pid (tab) 33 0 55 52 54 52 52 0
結果:
id 子結點數 33 0 52 2
select id,(select count(*) from tab where pid=t.id) as 子結點數
from tab t
where pid=0
http://bbs.csdn.net/topics/390473594
8、update join 關聯條件修改
abc表: 工程ID 專案 狀態 ---------------------------------------------------------- 1 東部汙水處理 正在進行中 1 建設路排水 未開始 1 東方廣場 已完成 1 德明旅館裝修 已完成 2 創業大廈 已完成 2 星光酒店水電 已完成 3 麗冬廣場 正在進行中 3 新世界廣場 已完成 xyz表: 工程ID 全部完成 ------------------------------------------ 1 否 2 是 3 否 判斷abc表同一工程ID下全部專案是否標記已完成,如果是,則update xyz表對應的列”全部完成“為”是“
update xyz inner join (select max(if(狀態='已完成',0,1)) as K from abc group by 工程ID) b on xyz.工程ID=b.工程ID
set 全部完成=IF(b.K=0,'是','否')
http://bbs.csdn.net/topics/390478379
9、利用函式返回值進行 order by 排序:
CREATE TABLE `goods` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`brand_id` varchar(5) NOT NULL DEFAULT '0',
`name` varchar(10) NOT NULL,
`click_count` varchar(10) NOT NULL DEFAULT '0',
`number` varchar(5) NOT NULL DEFAULT '0',
`salesnum` varchar(10) NOT NULL DEFAULT '0',
`desc` varchar(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARACTER SET utf8;
INSERT INTO `goods` VALUES (901, '26', 'T恤---售馨', '939', '1', '', '');
INSERT INTO `goods` VALUES (783, '26', '雪紡上衣', '639', '5', '', '');
INSERT INTO `goods` VALUES (814, '26', '雪紡上衣', '1059', '19', '', '');
INSERT INTO `goods` VALUES (1577, '26', '短袖荷葉領', '647', '87', '', '');
INSERT INTO `goods` VALUES (1769, '26', '透氣純色鈕釦上衣', '2451', '24', '', '');
INSERT INTO `goods` VALUES (1642, '26', ' 純色短袖', '534', '64', '', '');
-- 注意 find_in_set 中的待匹配字串不允許有空格
mysql> SELECT * FROM `goods` WHERE id IN ('783','769','814','1577','1769') ORDER BY FIND_IN_SET(id, '783,769,814,1577,1769' ) ;
+------+----------+--------------------------+-------------+--------+----------+------+
| id | brand_id | name | click_count | number | salesnum | desc |
+------+----------+--------------------------+-------------+--------+----------+------+
| 783 | 26 | 雪紡上衣 | 639 | 5 | | |
| 814 | 26 | 雪紡上衣 | 1059 | 19 | | |
| 1577 | 26 | 短袖荷葉領 | 647 | 87 | | |
| 1769 | 26 | 透氣純色鈕釦上衣 | 2451 | 24 | | |
+------+----------+--------------------------+-------------+--------+----------+------+
4 rows in set (0.02 sec)
mysql> SELECT * FROM `goods` WHERE id IN ('783','769','814','1577','1769') ORDER BY FIND_IN_SET(id, '814,1577,1769,783,769' ) ;
+------+----------+--------------------------+-------------+--------+----------+------+
| id | brand_id | name | click_count | number | salesnum | desc |
+------+----------+--------------------------+-------------+--------+----------+------+
| 814 | 26 | 雪紡上衣 | 1059 | 19 | | |
| 1577 | 26 | 短袖荷葉領 | 647 | 87 | | |
| 1769 | 26 | 透氣純色鈕釦上衣 | 2451 | 24 | | |
| 783 | 26 | 雪紡上衣 | 639 | 5 | | |
+------+----------+--------------------------+-------------+--------+----------+------+
4 rows in set (0.00 sec)
mysql>
http://bbs.csdn.net/topics/390528130
10、left join 左連線、去重、分組統計等
有兩個表:
create table t1(
id int,
key1 int,
key2 int,
key3 int,
key4 int
);
insert into t1 values
(1, 112, 222, 333, null),
(2, 112, 222, 333, null),
(3, 134, 222, 333, 444 ),
(4, 134, 000, 333, 444 ),
(5, 178, 212, 312, 412 );
create table t2(
id int
);
insert into t2 values
(1),
(1),
(2),
(4),
(5);
我想要對該表進行資訊的統計: 1)查詢table2,id去重;得到id=1、2、4、5; 2)利用id與table1關聯,並根據key1、key2、key3、key4進行統計:id=1和id=2的幾個key都一樣,因此這幾個key為一組,且出現次數為2 示例結果: key1 key2 key3 key4 times 112 222 333 null 2 134 222 333 444 0 134 000 333 444 1 178 212 312 412 1
SELECT a.`key1`,a.`key2`,a.`key3`,a.`key4`,COUNT(DISTINCT b.id) FROM t1 a
LEFT JOIN t2 b ON a.`id`=b.`id`
GROUP BY a.`key1`,a.`key2`,a.`key3`,a.`key4`;
http://bbs.csdn.net/topics/390598979
類似的問題:有一個表:
create table tt(
id int,
`key` int,
type varchar(10)
);
insert into tt values
(123,11111, "first"),
(456,11111, "second"),
(456,11111, "second" ),
(789,22222, "second" ),
(890,22222, "second" ),
(456,22222, "first" );
我想要對該表進行資訊的統計: 1)根據id要去重; 2)統計key的次數; 3)統計每個key對應的type的次數 示例結果: key times first_times second_times 11111 2 1 1 22222 3 1 2
select `key`,count(*),sum(if(type='first',1,0)),
sum(if(type='second',1,0))
from (
select distinct id,`key`,type from tt) a
group by `key`;
http://bbs.csdn.net/topics/390598827?page=1#post-395639648
11、 得到一天中每10分鐘的時間
DELIMITER $$
DROP PROCEDURE IF EXISTS tt$$
CREATE PROCEDURE tt()
BEGIN
SET @i=1;
SET @a=CONCAT(CURDATE(),' 00:00:00');
insert into lsb values(date_add(@a, interval 10 minute));
WHILE @i<=144 DO
insert into lsb values(date_add(@a, interval 10 minute));
SET @a=DATE_ADD(@a, INTERVAL 10 MINUTE);
SET @i=@i+1;
END WHILE;
END$$
DELIMITER ;
12、從8月26號到9月25號這段時間內記錄了每一天的重量,
現在想按 26-31號,1-5號,6-10號,11-15號,16-20號,21-15號
這6個時間段內重量的總和 這個sql要怎麼寫?
要點:使用 TIMESTAMPDIFF 求得每個日期的所屬區間範圍,進而分組求值。
select TIMESTAMPDIFF(day,recdate,'2013-08-26') div 5,sum(weight)
from tb
group by TIMESTAMPDIFF(day,recdate,'2013-08-26') div 5
13、find_in_set 判斷欄位關係做表間連線條件:
table 1 id table2_id 1 1,2,3 table 2 id value1 1 a 2 b 3 c 想要的是 id value 1 a,b,c
select table1.id,group_concat(table2.value1)
from table1,table2
where find_in_set(table2.id,table1.table2_id)
group by table1.id
http://bbs.csdn.net/topics/390706383
14、sql 表自連線組間比較大小:
求出所有人中,這次考試比上次考試得分高的有幾個 事例表如下 ID Name Score TestOrder 1 小明 90 1 2 小王 80 1 3 小紅 80 1 4 小明 60 2 5 小王 90 2 6 小紅 80 2
select A.*
from tb A,tb B
where A.name=B.name and A.testorder = B.testorder-1 and A.score>B.score;
或者:
select * from TABLE A
where exists (select 1 from TABLE where A.score> score and A.name = name and testorder = 2)
and A.testorder = 1;
15、多欄位更新:set 中使用 case when then else 表示式進行條件更新
CREATE TABLE user_test(
id int,
uid int
);
insert into user_test values(11,22),(22, 33),(44, 22),(11,22),(22, 33),(44, 22);
update user_test
set
id = case when id in (44) then 4444 else id end,
uid = case when uid in(22) then 2222 else uid end
where id > 0;
16、mysql 裡的二次排序
表 score,包含三個欄位 stdno(int),subject(int),score(int) 分別表示 學號、科目、成績 資料示例:1, 1, 50 表示學號為1的學生,第1個科目成績為50 2,2,60 表示學號為2的學生,第2個科目的成績為60 現在要求按照以下規則排序: 1、以科目3的成績從大到小對學生進行排序 2、單個學生的記錄按科目從小到大進行排序 排序後的結果如下: 5、1、xxx 5、2、xxx 5、3、100 5、4、xxx 2、1、xxx 2、2、xxx 2、3、99 2、4、xxx 8、1、xxx 8、2、xxx 8、3、98 8、4、xxx ...
select A.* from (
select stdno, score from score where subjectId = 3 order by score desc) B
inner join score A
on A.stdno = B.stdno order by B.score desc, A.subjectId asc;
select *
from score s
order by (select score from score where stdno=s.stdno and subject=3) desc, a.subject asc;
http://bbs.csdn.net/topics/390803079
17、巧用 ON DUPLICATE KEY UPDATE 實現原值+插入值更新
mysql表如下:
CREATE TABLE `test` (
`id`int(11) NOT NULL auto_increment,
`cnt` double(15,3) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8 PACK_KEYS=0;
我想在這張表裡批量修改cnt欄位,需要在這個欄位的原值上加上某一個值。 如果只是修改一行記錄,這樣寫就行了 update test set cnt = cnt+某值 where id = 某行id;
分2條SQL執行,
UPDATE、INSERT
或者:
INSERT INTO test4(id,cnt) VALUES
(167,2),
(4,3),
(6,5),
(7,9)
ON DUPLICATE KEY UPDATE id = VALUES(id), cnt= VALUES(cnt)+ cnt
http://bbs.csdn.net/topics/390840353
18、常見SQL統計函式示例:
108.聚合去重查詢優化:count(1) 在列為 Null 時的陷阱:
--談談分散式Aggregation
Q1:SELECT A, COUNT(DISTINCT B), SUM(C) FROM T GROUP BY A;
Q2:SELECT A, COUNT(1), SUM(SC) FROM
(SELECT A, COUNT(1), SUM(C) AS SC
FROM T GROUP BY A, B) TT GROUP BY A;
Q1和Q2的語義在B有null的時候並不等價,將Q2改為如下,這樣兩個查詢的語義就是相同的了:
SELECT A, COUNT(B), SUM(SC) FROM (SELECT A, B, SUM(C) AS SC FROM T GROUP BY A, B) TT GROUP BY A
109.查詢一段時間內的使用者下單次數分佈情況:
-- 首先計算每個使用者的下單次數,然後使用 CASE..WHEN 語法來分組。
SELECT
CASE
WHEN c < 10 THEN '<10'
WHEN c < 20 THEN '<20'
WHEN c < 100 THEN '<100'
ELSE '>100'
END,
COUNT(*)
FROM (
SELECT user_id, COUNT(*) AS c FROM events
WHERE date BETWEEN '2015-09-01' AND '2015-09-20' AND event = 'SubmitOrder'
GROUP BY 1
)a
GROUP BY 1
110.查詢做了行為 A 而沒有做行為 B 的使用者數
--使用 LEFT OUTER JOIN 計算差集。
SELECT a.user_id FROM (
SELECT DISTINCT user_id FROM events WHERE date='2015-10-1' AND event = 'BuyGold'
) a
LEFT OUTER JOIN (
SELECT DISTINCT user_id FROM events WHERE date='2015-10-1' AND event = 'SaleGold'
) b
ON a.user_id = b.user_id
WHERE b.user_id IS NULL
111.計算使用者的使用時長
--使用分析函式,根據每個使用者相鄰的兩個事件的間隔估算累計使用時長,如果兩次使用間隔超出10分鐘則不計算。
SELECT
user_id,
SUM(
CASE WHEN
end_time - begin_time < 600
THEN
end_time - begin_time
ELSE
0
END
) FROM (
SELECT
user_id,
EXTRACT(EPOCH FROM time) AS end_time,
LAG(EXTRACT(EPOCH FROM time), 1, NULL) OVER (PARTITION BY user_id ORDER BY time asc) AS begin_time
FROM events
WHERE date='2015-5-1'
) a
GROUP BY 1
112.查詢漏斗第 1 步的流失使用者的使用時長
SELECT
AVG(
CASE WHEN
end_time - begin_time < 600
THEN
end_time - begin_time
ELSE
0
END
) FROM (
SELECT
user_id,
EXTRACT(EPOCH FROM time) AS end_time,
LAG(EXTRACT(EPOCH FROM time), 1, NULL) OVER (PARTITION BY user_id ORDER BY time asc) AS begin_time
FROM events
WHERE date='2015-5-1' and user_id in (funnel_user(12, '2015-05-01', '2015-05-01', '1.8', true, 0))
) a
來源: