1. 程式人生 > >【MySQL】多表查詢、分組求和、並對和排序、取top n

【MySQL】多表查詢、分組求和、並對和排序、取top n

查漏補缺MySQL的相關知識

1. 有一個使用者資金流水錶(如上的sql程式碼),找出流水金額最多的前10個使用者:

create table tb_user_finance (
  id bigint primary key auto_increment
, uid bigint not null default 0 comment '使用者id', money decimal(10, 2) not null default 0.00 comment '資金流水', type tinyint not null default 0 comment '1: 轉賬, 10: 提現, 20: 充值', created_at timestamp not null default current_timestamp, updated_at timestamp not null default current_timestamp on update current_timestamp
, key ix_uid (uid) ) engine = innodb default charset=utf8 comment '使用者資金流水錶'; insert into tb_user_finance (uid, money, type) values(10, 20, 1); insert into tb_user_finance (uid, money, type) values(10, 20, 1); insert into tb_user_finance (uid, money, type) values(10, 20, 1); insert into tb_user_finance (
uid, money, type) values(10, 200, 1); insert into tb_user_finance (uid, money, type) values(20, 10, 10); insert into tb_user_finance (uid, money, type) values(30, 20, 20); insert into tb_user_finance (uid, money, type) values(30, 10, 20); insert into tb_user_finance (uid, money, type) values(31, 10, 20); insert into tb_user_finance (uid, money, type) values(32, 20, 20); insert into tb_user_finance (uid, money, type) values(33, 45, 20); insert into tb_user_finance (uid, money, type) values(34, 100, 20); insert into tb_user_finance (uid, money, type) values(35, 1000, 20); insert into tb_user_finance (uid, money, type) values(36, 1090, 20);

答案:

select uid, sum(money) as total from tb_user_finance group by uid order by total desc limit 10;

2. 查詢分組後的最大值,最小值所在的整行記錄或者分組後的top n行的記錄。

2.1 建立測試表:

CREATE TABLE `test1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `course` varchar(20) DEFAULT NULL,
  `score` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

2.2 插入資料:

insert into test1(name,course,score)
values
('張三','語文',80),
('李四','語文',90),
('王五','語文',93),
('張三','數學',77),
('李四','數學',68),
('王五','數學',99),
('張三','英語',90),
('李四','英語',50),
('王五','英語',89);

檢視結果:select * from test1;

+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  1 | 張三   | 語文   |    80 |
|  2 | 李四   | 語文   |    90 |
|  3 | 王五   | 語文   |    93 |
|  4 | 張三   | 數學   |    77 |
|  5 | 李四   | 數學   |    68 |
|  6 | 王五   | 數學   |    99 |
|  7 | 張三   | 英語   |    90 |
|  8 | 李四   | 英語   |    50 |
|  9 | 王五   | 英語   |    89 |
+----+--------+--------+-------+

3.TOP 1

查詢每門課程分數最高的學生以及成績
1、使用自連線【推薦】

select a.name, a.course, a.score from 
test1 a
join (select course, MAX(score) score from test1 group by course)b
on a.course = b.course  and a.score = b.score;
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+

2、使用相關子查詢

select name, course, score from test1 a 
where score=(select max(score) from test1 where a.course = test1.course);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+

這個有點不理解,where條件:score = (select max(score) from test1 where a.course = test1.course),我想這個應該是返回的每一科目的最大值,但是score使用等號連線表明後面應該是一個單獨的值,但是直接執行這個語句就報錯了,將括號內的where去掉的話 直接查出來的是整個表裡的最大值了。

看到這裡我試著自己寫了一個,但是結果不對,不知道哪裡出了問題,多了一行資料。
這條語句可以查出來每一科目的最高分,返回三個值:

select max(score) score from test1 group by course;
+-------+
| score |
+-------+
|    93 |
|    99 |
|    90 |
+-------+

然後再查詢一次,新增一個where條件限制score:

select name, course, score from test1  
where score in (select max(score) score from test1 group by course);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 李四   | 語文   |    90 |       //這一行是哪來的????
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+

但是結果竟然多了一行,不知道這一行是從哪裡多出來的??????這種寫法我在專案中用過,但是好像沒有發現這種會多一行不正確的資料的情況。

3.另一種相關子查詢

select name, course, score from test1 a
where not exists (select 1 from test1 where a.course = test1.course and a.score < test1.score)
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 王五   | 數學   |    99 |
| 張三   | 英語   |    90 |
+--------+--------+-------+

這種子查詢,我之前還真的沒有遇到過,還能這麼寫,真的很神奇,有空需要多補補SQL方面的知識了。

4.TOP N

N>=1

查詢每門課程前兩名的學生以及成績

  1. 使用union all

如果結果集比較小,可以用程式查詢單個分組結果後拼湊,也可以使用union all

(select name, course, score from test1 where course='語文' order by score desc limit 2)
union all 
(select name, course, score from test1 where course='數學' order by score desc limit 2)
union all 
(select name, course, score from test1 where course='英語' order by score desc limit 2);
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 語文   |    93 |
| 李四   | 語文   |    90 |
| 王五   | 數學   |    99 |
| 張三   | 數學   |    77 |
| 張三   | 英語   |    90 |
| 王五   | 英語   |    89 |
+--------+--------+-------+
  1. 自身左連線
select a.name, a.course, a.score from test1 a

left join test1 b

on a.course = b.course and a.score<b.score

group by a.name, a.course, a.score

having count(b.id)<2

order by a.course, a.score desc;
+--------+--------+-------+
| name   | course | score |
+--------+--------+-------+
| 王五   | 數學   |    99 |
| 張三   | 數學   |    77 |
| 張三   | 英語   |    90 |
| 王五   | 英語   |    89 |
| 王五   | 語文   |    93 |
| 李四   | 語文   |    90 |
+--------+--------+-------+
  1. 相關子查詢
select a.name, a.course, a.score from test1 a

where 2>(select count(*) from test1 where course = a.course and score > a.score)

order by a.course, a.score desc
+----+--------+--------+-------+
| id | name   | course | score |
+----+--------+--------+-------+
|  6 | 王五   | 數學   |    99 |
|  4 | 張三   | 數學   |    77 |
|  7 | 張三   | 英語   |    90 |
|  9 | 王五   | 英語   |    89 |
|  3 | 王五   | 語文   |    93 |
|  2 | 李四   | 語文   |    90 |
+----+--------+--------+-------+

5.LEFT JOIN後面的on和where的區別

5.1建立測試表

CREATE TABLE `product` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `amount` int(10) unsigned default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;

CREATE TABLE `product_details` (
  `id` int(10) unsigned NOT NULL,
  `weight` int(10) unsigned default NULL,
  `exist` int(10) unsigned default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO product (id,amount)
       VALUES (1,100),(2,200),(3,300),(4,400);

INSERT INTO product_details (id,weight,exist)
       VALUES (2,22,0),(4,44,1),(5,55,0),(6,66,1);

表資料:

SELECT * FROM product;
+----+--------+
| id | amount |
+----+--------+
|  1 |    100 |
|  2 |    200 |
|  3 |    300 |
|  4 |    400 |
+----+--------+
SELECT * FROM product_details;
+----+--------+-------+
| id | weight | exist |
+----+--------+-------+
|  2 |     22 |     0 |
|  4 |     44 |     1 |
|  5 |     55 |     0 |
|  6 |     66 |     1 |
+----+--------+-------+
select * from product a

left join product_details b

on a.id = b.id
// 後面仍然可以新增where條件進行過濾
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 |    4 |     44 |     1 |
+----+--------+------+--------+-------+

ON 子句和 WHERE 子句有什麼不同?

一個問題:下面兩個查詢的結果集有什麼不同麼?

select * from product a

left join product_details b

on a.id = b.id

and  b.id = 2
select * from product a

left join product_details b

on a.id = b.id

where  b.id = 2

看執行結果就很明顯的看出來區別了:

SELECT * FROM product LEFT JOIN product_details
       ON (product.id = product_details.id)
       AND product_details.id=2;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL |  NULL |
|  2 |    200 |    2 |     22 |     0 |
|  3 |    300 | NULL |   NULL |  NULL |
|  4 |    400 | NULL |   NULL |  NULL |
+----+--------+------+--------+-------+
SELECT * FROM product LEFT JOIN product_details
       ON (product.id = product_details.id)
       WHERE product_details.id=2;
+----+--------+----+--------+-------+
| id | amount | id | weight | exist |
+----+--------+----+--------+-------+
|  2 |    200 |  2 |     22 |     0 |
+----+--------+----+--------+-------+
  1. 第一條查詢使用 ON 條件決定了從 LEFT JOIN的 product_details表中檢索符合的所有資料行。

  2. 第二條查詢做了簡單的LEFT JOIN,然後使用 WHERE 子句從 LEFT JOIN的資料中過濾掉不符合條件的資料行。

再來看一些示例,ON後面的AND條件是怎麼匹配資料的:

SELECT * FROM product LEFT JOIN product_details
       ON product.id = product_details.id
       AND product.amount=100;
+----+--------+------+--------+-------+
| id | amount | id   | weight | exist |
+----+--------+------+--------+-------+
|  1 |    100 | NULL |   NULL 
            
           

相關推薦

MySQL查詢分組求和排序top n

查漏補缺MySQL的相關知識 1. 有一個使用者資金流水錶(如上的sql程式碼),找出流水金額最多的前10個使用者: 2. 查詢分組後的最大值,最小值所在的整行記錄或者分組後的top n行的記錄。 3.TOP 1 4.TOP N

MySQL查詢

首先,為了方便說明問題,建立兩個表emp(僱員資訊)和dept(僱員部門資訊),其資料如下: 在之前的部落格中,我們分享了單表查詢的方法,但是在實際應用中,我們要查的資料很可能不在同一個表中,而是來自於不同的表。多表查詢如果不加任何條件,得到的結果稱為笛卡

MySQL聯合查詢(新增查詢欄位引數設定)

所羅門王說:沒有智慧解決不了的問題。SELECT * from tb_corporation_and_user      人員所在團隊 (`user_id`, `corporation_id` ,  `role_id` ) SELECT * from tb_corporati

MySQL基礎入門學習10刪除

clas id號 mys 更新 IT from 查詢 基礎入門 where DELETE tbl_name [.*] [, tbl_name[.*]]... FROM table_references [WHERE where_condition] 現在想把重復的

8mysql資料庫查詢(資料內連線左連結右連結全連線)

目錄 1 內連線 場景:A和B資料 的交集 2 左連結 場景1:得到 “AB交集後和A“ 的並集  (得到A的所有資料+滿足某一條件的B的資料) 場景2:得到A減去AB的交集  (A中所有資料減去同時滿足B某一條件的資料) 3 右連結 場景1:得到“A

補12.關於mysql查詢

sql mysql select 首先先準備兩張表。首先是員工信息表,表名為employee。create table employee( emp_id int primary key auto_increment not null, emp_name varchar(50), age int,

Mysql ==》 查詢

相同 ext 右連接 連接查詢 val nav 信息 出了 set 主要內容: 1.多表連接查詢 2.符合條件連接查詢 3.子查詢 4.綜合練習 插入數據庫,準備表。 #建表 create table department( id int, name varchar(20

MySQL查詢

lap max not 包含 one 插入記錄 比較運算符 ffice create 一,多表連接查詢 ex:創建2張表 部門表(department)、員工表(employee) create table department( id int, name varcha

MYSQL查詢

保留 name left 兩張 技術 笛卡兒 對應關系 pre 全連接 1、笛卡兒積 select * from emp,dep; select * from emp,dep where emp.dep_id = dep.id; select * from emp,d

MySqlGroup By數據分組

根據 round 技術 ack 使用 sele bsp inf span GROUP BY 語句根據一個或多個列對結果集進行分組。 在分組的列上我們可以使用 COUNT, SUM, AVG,等函數。 因為聚合函數通過作用於一組數據而只返回一個單個值, 因此,在SELECT

MySQL查詢練習

info 工資 join ada 員工 ear 利潤表 mgr 沒有 一、表格 表一 emp 表二 dept 表三 salgrade; 表四 年度利潤表 二、習題 1. 查出至少有一個員工的部門。顯示部門編號、部門名稱、部門位置、部門人數。 2. 列出所有員

mysql查詢的其他查詢

1,臨時表查詢 (1)需求:查詢高於本部門平均工資的人員 select * from person as p, (select dept_id, avg(salary) as '平均工資' from person GROUP BY dept_id) as ptable where p.dept_

MYSQL與大事務帶來的問題

前言 相對來說,什麼情況下的資料庫表能夠稱為“大表”呢? 當一個表的資料超過千萬行的時候,就會對資料庫造成影響 當表資料檔案巨大,表資料檔案超過10G(資料值相對硬體而言) 大表的影響 大表對查詢的影響 慢查詢:很難在一定的時間內過濾出所需要的資料(Eg:顯示訂

mysql資料庫查詢例項

有以下幾張表: 學生表s:sid(主鍵)、sname(姓名)、sex(性別)、age(年齡) 班級表c:cid(主鍵)、cname(班級名) 教師表t:tid(主鍵)、tname(教師名稱) 關係表sc:id(主鍵)、sid(學生主鍵)、ci

mysql資料庫查詢練習題

下面練習題中設計四個表。分別為: dept表 emp表 salgrade表 tbyear表 1. 查出至少有一個員工的部門。顯示部門編號、部門名稱、部門位置、部門人數。 SELECT d.deptno,d.dname,d.loc,e1.`count

java mysql查詢

資料庫概念圖 分組查詢 分頁查詢 一對多關係分析 多對多關係分析 1對1關係分析 1對多關係 使用者和角色和許可權的多對多關係 多表查詢-內連線查詢 多表查詢的內連線查詢 多

mysql關於子查詢的一個例子

假設表my_tbl包含三個欄位a,b,c;現在需要查詢表中列a的每個不同值下的列b為最小值的記錄量。 比如表記錄為: a  b  c 1  3  'cd' 2  3  'nhd' 1  5  'bg

MySQL資料庫查詢

多表查詢可使用的方法 外連線 左連線(left join 或left outer join) 右連線(right join 或 right outer join) 完全外連線(full join 或 full outer join(MySQL不支援)) 內

MySQL查詢問題

多表查詢為了消除資料的冗餘,我們存資料的時候,會把完整的資料資訊,分散到多張表來儲存。但是,使用者通常需要的是一個完整的全面的資訊,那麼在查詢的時候,就需要把這些分散的資訊 拼接 。——多表查詢“拼接” 《=》 連線連線查詢    交叉連線:(笛卡爾積)        cro

09--MySQL自學教程:查詢之內連線外連線以及查詢

1.為什麼要拆表? 去除冗餘資料 2.表與表之間的關係 一對一 比如 人和身份證 QQ和QQ密碼 一對多(多對一) 比如:學生和成績的關係 多對多 比如:老師和學生的關係 3