一些sql用法例子【Updating】

一、利用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.htmlhtml

二、find_in_set 用法:

有兩張表:mysql

a:
id name
1  tom
2  terry
...

b:
fid  ids
1    1,2
...sql

若是須要根據表b的ids列找出表a對應的name:segmentfault

 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分佈式

三、MySQL group by with rollup的用法:對列作統計

GROUP BY Modifiers  官方手冊裏面對這個rollup有一個專門的頁面介紹 地址在這裏,說得很是詳細,我這裏作一個簡單的例子重現函數

建一個簡單的表並插入幾條簡單的數據post

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 產生了列數據,即生成了一張行列交錯的統計報表。ui

四、自鏈接生成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/390420571spa

五、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

六、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

七、自鏈接求子節點記錄數:

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

八、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

九、利用函數返回值進行 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

十、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=一、二、四、5;
2)利用id與table1關聯,並根據key一、key二、key三、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

十一、 獲得一天中每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 ;

十二、從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

1三、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

1四、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;

1五、多字段更新: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;

1六、mysql 裏的二次排序

表 score,包含三個字段 stdno(int),subject(int),score(int)
分別表示 學號、科目、成績
數據示例:1, 1, 50  表示學號爲1的學生,第1個科目成績爲50
   2,2,60 表示學號爲2的學生,第2個科目的成績爲60

如今要求按照如下規則排序:
一、以科目3的成績從大到小對學生進行排序
二、單個學生的記錄按科目從小到大進行排序

排序後的結果以下:
五、一、xxx
五、二、xxx
五、三、100
五、四、xxx
二、一、xxx
二、二、xxx
二、三、99
二、四、xxx
八、一、xxx
八、二、xxx
八、三、98
八、四、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

1七、巧用 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

1八、常見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

來源:

http://bit.ly/2r0f9mx        

https://www.sensorsdata.cn/manual/query.html

1九、

相關文章
相關標籤/搜索