1. 程式人生 > >資料庫查詢語句例項

資料庫查詢語句例項

 

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`));

查詢語句1

select * from employees where hire_date = (select max(hire_date) from employees)

           執行時間:21ms         佔用記憶體:3424k

查詢語句2

select * from employees order by hire_date desc limit 1;

          執行時間:22ms          佔用記憶體:3432k

討論:在執行時間及記憶體佔用上兩者差別不大,但需要注意的是如果hire_date的格式是2015-12-14這種,不排除當天入職的人不止一個的情況,因此,語句1會將當天入職的人都找出來,而語句二隻會找出你指定的數量。

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

還是上面的員工表,寫出查詢語句:

select * from employees order by hire_date desc limit 2,1;

      執行時間:19ms      佔用記憶體:3320k

select * from employees
where hire_date=(select distinct hire_date from employees order by hire_date desc limit 2,1);

     執行時間:23ms     佔用記憶體:3552k

討論:兩條語句考慮的點有些許差別,前一條語句直接考慮可能有重複的情況,哪怕當天有多人入職也一併進行排序取倒數第三個;後一條語句則先對同日期入職的資料進行去重然後再排序取倒數第三個;

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`));

查詢語句:

SELECT s.*, d.dept_no FROM salaries s ,  dept_manager d
WHERE s.to_date='9999-01-01' 
AND d.to_date='9999-01-01' 
AND s.emp_no = d.emp_no;

     執行時間:18ms     佔用記憶體:3552k

select s.* ,d.dept_no
from salaries as s 
join dept_manager as d 
on s.emp_no=d.emp_no
where s.to_date = '9999-01-01'
    and    d.to_date='9999-01-01';

       執行時間:21ms      佔用記憶體:3424k

討論:兩條語句查詢的本質是一樣的,只不過後一條用的是join關聯兩表,而前一條語句則是通過條件外來鍵關聯;注意一點小問題,因為查詢語句中s表在前,d表在後,因而查詢所得的結果也是這個順序。

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`));

查詢語句:

SELECT e.last_name, e.first_name, d.dept_no
FROM employees e, dept_emp d where d.emp_no = e.emp_no and dept_no is not null;

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

         表結構與上一題一樣,但與上一題的 區別在於這裡要找到所有員工的相關資訊;因此說明員工表的所有員工資訊都需要找到,左連線可以保證左表的資訊都得以保留;

查詢語句:

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`));

思路:

此題應注意以下四個知識點:

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 可以省略

查詢語句:

方法一:利用 INNER JOIN 連線兩張表
SELECT e.emp_no, s.salary FROM employees AS e INNER JOIN salaries AS s
ON e.emp_no = s.emp_no AND e.hire_date = s.from_date
ORDER BY e.emp_no DESC
方法二:直接用逗號並列查詢兩張表
SELECT e.emp_no, s.salary FROM employees AS e, salaries AS s
WHERE e.emp_no = s.emp_no AND e.hire_date = s.from_date
ORDER BY e.emp_no DESC

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`));

思路:
此題應注意以下四點:

1、用COUNT()函式和GROUP BY語句可以統計同一emp_no值的記錄條數

2、根據題意,輸出的漲幅次數為t,故用AS語句將COUNT(emp_no)的值轉換為t

3、由於COUNT()函式不可用於WHERE語句中,故使用HAVING語句來限定t>15的條件

4、最後存在一個理解誤區,漲幅超過15次,salaries中相應的記錄數應該超過16(從第2條記錄開始算作第1次漲幅),不過題目為了簡單起見,將第1條記錄當作第1次漲幅,所以令t>15即可

/**  注意: 嚴格來說,下一條salary高於本條才算漲幅,但本題只要出現了一條記錄就算一次漲幅,salary相同可以理解為漲幅為0,salary變少理解為漲幅為負 **/

SELECT emp_no, COUNT(emp_no) AS t FROM salaries 
GROUP BY emp_no HAVING t > 15;

注意where和having的區別:

WHERE語句在GROUP BY語句之前;SQL會在分組之前計算WHERE語句。   

HAVING語句在GROUP BY語句之後;SQL會在分組之後計算HAVING語句。

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

表結構與上題一致

方式一:
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;

對於distinct,groupby的效能解釋:

  1. 資料量非常巨大時候,比如1000萬中有300W非重複資料,這時候的distinct的效率略好於group by;
  2. 對於相對重複量較小的資料量比如1000萬中1萬非重複資料,用groupby的效能會遠優於distnct。

簡單點說就是重複的資料越多用groupby來分組統計效能更好。

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`));

查詢語句:

方式一:自然的使用條件where
select d.dept_no,d.emp_no,s.salary from dept_manager as d,salaries as s
where d.emp_no = s.emp_no and s.to_date='9999-01-01' and d.to_date='9999-01-01'
order by d.emp_no;

方式二:使用表連線
SELECT d.dept_no, d.emp_no, s.salary FROM salaries AS s INNER JOIN dept_manager AS d 
ON d.emp_no = s.emp_no AND d.to_date = '9999-01-01' AND s.to_date = '9999-01-01';

相關思路:

1、先用INNER JOIN連線兩張表,限制條件是兩張表的emp_no相同,即d.emp_no = s.emp_no,並且將salaries用別名s代替,dept_manager用別名d代替;

2、根據題意,要獲取當前manager的當前salary情況,再加上限制條件d.to_date = '9999-01-01' AND s.to_date = '9999-01-01'即可(因為同一emp_no在salaries表中對應多條漲薪記錄,而當s.to_date = '9999-01-01'時是該員工當前的薪水記錄);

3、使用表連線時由於題目沒有特別要求,因此內連線簡便,如若題目要求當前部門經理有工資的話,就顯示出來,沒有的話,salary就置為空的話,那麼就需要使用左連線或右連線。

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`));
方法一:使用NOT IN選出在employees但不在dept_manager中的emp_no記錄
1SELECT emp_no FROM employees
WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager);

方法二:先使用LEFT JOIN連線兩張表,再從此表中選出dept_no值為NULL對應的emp_no記錄
SELECT emp_no FROM (SELECT * FROM employees LEFT JOIN dept_manager
ON employees.emp_no = dept_manager.emp_no)
WHERE dept_no IS NULL;

方法三:方法二的簡版,使用單層SELECT語句即可
SELECT employees.emp_no FROM employees LEFT JOIN dept_manager
ON employees.emp_no = dept_manager.emp_no
WHERE dept_no IS NULL

注意:

         MySQL官方文件有說明,in關鍵字適合確定數量的情況,一般效率較低,不推薦使用。能用in關鍵字的語句都可以轉化為使用join的語句,推薦使用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`));

查詢語句:

SELECT de.emp_no, dm.emp_no AS manager_no FROM dept_emp AS de INNER JOIN dept_manager AS 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;

注意:

1、用 INNER JOIN 連線兩張表,因為要輸出自己的經理,得知自己與經理的部門要相同,故有限制條件 de.dept_no = dm.dept_no;

2、再用 WHERE 限制當前員工與當前經理的條件,即 dm.to_date 等於 '9999-01-01' 、de.to_date 等於 '9999-01-01' 、 de.emp_no 不等於 dm.emp_no;

3、為了增強程式碼可讀性,將 dept_emp 用別名 de 代替,dept_manager 用 dm 代替,最後根據題意將 de.emp_no 用別名 manager_no 代替後輸出。

 

 

持續更新。。。