1. 程式人生 > >資料庫SQL實戰:MySql練習(上)

資料庫SQL實戰:MySql練習(上)

文章目錄

1. 查詢最晚入職員工的所有資訊

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select * 
from employees 
where hire_date = (select max(hire_date) from employees);

2. 查詢入職員工時間排名倒數第三的員工所有資訊

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select * 
from employees 
order by hire_date 
desc limit 2,1;

3. 查詢各個部門當前(to_date=‘9999-01-01’)領導當前薪水詳情以及其對應部門編號dept_no

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select s.*, d.dept_no
from salaries s 
join dept_manager d 
on d.emp_no = s.emp_no 
andd.to_date='9999-01-01' 
and s.to_date='9999-01-01';

JOIN 按照功能大致分為如下三類:
INNER JOIN/JOIN(內連線,或等值連線):取得兩個表中存在連線匹配關係的記錄。
LEFT JOIN(左連線):取得左表(table1)完全記錄,即是右表(table2)並無對應匹配記錄。
RIGHT JOIN(右連線):與 LEFT JOIN 相反,取得右表(table2)完全記錄,即是左表(table1)並無匹配對應記錄。

注意:mysql不支援Full join,不過可以通過UNION 關鍵字來合併 LEFT JOIN 與 RIGHT JOIN來模擬FULL join.

4. 查詢所有已經分配部門的員工的last_name和first_name

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select e.last_name, e.first_name,d.dept_no
from dept_emp d  
left join employees e 
on e.emp_no = d.emp_no;

5. 查詢所有員工的last_name和first_name以及對應部門編號dept_no,也包括展示沒有分配具體部門的員工

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select e.last_name, e.first_name, d.dept_no 
from employees e 
left join dept_emp d 
on e.emp_no = d.emp_no;

6. 查詢所有員工入職時候的薪水情況,給出emp_no以及salary, 並按照emp_no進行逆序

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select e.emp_no,s.salary 
from employees e 
join salaries s 
on e.emp_no = s.emp_no 
and e.hire_date = s.from_date 
order by e.emp_no desc;

此題應注意以下四個知識點:
1、由於測試資料中,salaries.emp_no 不唯一(因為號碼為 emp_no 的員工會有多次漲薪的可能,所以在 salaries 中對應的記錄不止一條),employees.emp_no 唯一,即 salaries 的資料會多於 employees,因此需先找到 employees.emp_no 在 salaries 表中對應的記錄salaries.emp_no,則有限制條件 e.emp_no = s.emp_no;
2、根據題意注意到 salaries.from_date 和 employees.hire_date 的值應該要相等,因此有限制條件 e.hire_date = s.from_date;
3、根據題意要按照 emp_no 值逆序排列,因此最後要加上 ORDER BY e.emp_no DESC;
4、為了程式碼良好的可讀性,運用了 Alias 別名語句,將 employees 簡化為 e,salaries 簡化為s,即 employees AS e 與 salaries AS s,其中 AS 可以省略。

7. 查詢薪水漲幅超過15次的員工號emp_no以及其對應的漲幅次數t

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select emp_no,count(emp_no) count 
from salaries 
group by emp_no 
having count >15;

where、having之間的區別和用法:
where 後不能跟聚合函式,因為where執行順序大於聚合函式。
where 子句的作用是在對查詢結果進行分組前,將不符合where條件的行去掉,即在分組之前過濾資料,條件中不能包含聚組函式,使用where條件顯示特定的行。
having 子句的作用是篩選滿足條件的組,即在分組之後過濾資料,條件中經常包含聚組函式,使用having 條件顯示特定的組,也可以使用多個分組標準進行分組。

8. 找出所有員工當前(to_date=‘9999-01-01’)具體的薪水salary情況,對於相同的薪水只顯示一次,並按照逆序顯示

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select salary 
from salaries  
where to_date='9999-01-01' 
group by salary 
order by salary desc;
select distinct(salary) 
from salaries 
where to_date='9999-01-01' 
order by salary desc;

在不同記錄數較小時,count group by效能普遍高於count distinct,尤其對於text型別表現的更明顯。而對於不同記錄數較大的場景,count group by效能反而低於直接count distinct。

9. 獲取所有部門當前manager的當前薪水情況,給出dept_no, emp_no以及salary,當前表示to_date=‘9999-01-01’

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select d.dept_no, d.emp_no, s.salary 
from salaries s 
join dept_manager d 
on d.emp_no = s.emp_no
and d.to_date = '9999-01-01'
and s.to_date = '9999-01-01';

10. 獲取所有非manager的員工emp_no

CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select emp_no 
from employees 
where emp_no not in (select emp_no from dept_manager)
select e.emp_no
from employees e 
left join dept_manager d 
on e.emp_no = d.emp_no 
where d.emp_no is null;

方法一:使用NOT IN選出在employees但不在dept_manager中的emp_no記錄。
方法二:先使用LEFT JOIN連線兩張表,再從此表中選出dept_no值為NULL對應的emp_no記錄。
因為not in會轉化成多表連線,而且不使用索引。所以用left_join會好一點。

11. 獲取所有員工當前的manager,如果當前的manager是自己的話結果不顯示,當前表示to_date=‘9999-01-01’。結果第一列給出當前員工的emp_no,第二列給出其manager對應的manager_no。

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL,
`emp_no` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
  • sql語句
select de.emp_no, dm.emp_no manager_no 
from dept_emp de inner join dept_manager dm
on de.dept_no = dm.dept_no 
where dm.to_date = '9999-01-01' and de.to_date = '9999-01-01' and de.emp_no <> dm.emp_no;

12. 獲取所有部門中當前員工薪水最高的相關資訊,給出dept_no, emp_no以及其對應的salary

CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
  • sql語句
select d.dept_no,s.emp_no,max(salary) salary
from salaries s 
join dept_emp d 
on s.emp_no = d.emp_no
and d.to_date = '9999-01-01' 
and s.to_date = '9999-01-01'
group by d.dept_no;

13. 從titles表獲取按照title進行分組,每組個數大於等於2,給出title以及對應的數目t

CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
  • sql語句
select title,count(title) t 
from titles 
group by title 
having t>=2;

14. 從titles表獲取按照title進行分組,每組個數大於等於2,給出title以及對應的數目t。

注意對於重複的emp_no進行忽略。
CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
  • sql語句
select title, count(distinct emp_no) t 
from titles 
group by title 
having t>=2;

15. 查詢employees表所有emp_no為奇數,且last_name不為Mary的員工資訊,並按照hire_date逆序排列

CREATE TABLE `employees` (
`emp_no` int(11) NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` char(1) NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`));
  • sql語句
select * 
from employees 
where emp_no%2=1 
and last_name <> 'Mary' 
order by hire_date 
desc;

16. 統計出當前各個title型別對應的員工當前薪水對應的平均工資。結果給出title以及平均工資avg

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary` int(11) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`from_date`));
CREATE TABLE IF NOT EXISTS "titles" (
`emp_no` int(11) NOT NULL,
`title` varchar(50) NOT NULL,
`from_date` date NOT NULL,
`to_date` date DEFAULT NULL);
  • sql語句
select t.title,avg(s.salary) avg 
from titles t 
join salaries s 
on s.emp_no = t.emp_no
and s.to_date = '9999-01-01'
and t.to_date = '9999-01-01'
group by t.title;

17. 獲取當前(to_date=‘9999-01-01’)薪水第二多的員工的emp_no以及其對應的薪水salary

CREATE TABLE `salaries` (
`emp_no` int(11) NOT NULL,
`salary`