1、牛客網網址mysql
https://www.nowcoder.com/ta/sql,一共76道真題。sql
PS:不要過於相信在線編譯器!!!作完每一題要記得看各位網友大神解讀和總結。express
2、題目函數
一、查找最晚入職員工的全部信息,爲了減輕入門難度,目前全部的數據裏員工入職的日期都不是同一天(sqlite裏面的註釋爲--,mysql爲comment)
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`));性能
解題:spa
(1)假設員工入職的日期都不是同一天,日期降序排序後,直接截取第一條數據便可。code
select * from employees order by hire_date desc limit 1;
limit m,n:m爲起始索引位置(索引從0開始),日後獲取n行數據。如limit 6,10 獲取第7行到16行數據。另外一種寫法:limit n offset msqlite
limit 語句運行順序排到最後,由於它是從結果集中截取部分行數。blog
(2)假設員工入職的日期有可能同一天。排序
select * from employees where hire_date = ( select max(hire_date) from employees); #1.用子查詢獲取最遲入職日期; #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`));
解題:
(1)假設員工入職的日期都不是同一天
select * from employees order by hire_date desc limit 2,1; # 直接降序排序獲取第三行記錄便可
(2)假設員工入職的日期有可能同一天
select * from employees where hire_date=( select distinct hire_date from employees order by hire_date desc limit 1 offset 2 ); #1.先用distinct把重複的日期去重,獲得的日期都是惟一的 #2.再排序後,用limit獲取倒數第三天入職的日期 #3.最後把入職日期等於倒數第三天日期的員工信息所有獲取
三、
CREATE TABLE `dept_manager` (
`dept_no` char(4) NOT NULL, -- '部門編號'
`emp_no` int(11) NOT NULL, -- '員工編號'
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`));
解題:
select sa.*, dm.dept_no from salaries as sa inner join dept_manager as dm on dm.emp_no = sa.emp_no where sa.to_date='9999-01-01' and dm.to_date='9999-01-01' order by sa.emp_no asc; # 考察表的內鏈接和一些實際狀況業務的瞭解
四、查找全部已經分配部門的員工的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`));
解題:
select last_name, first_name, dept_no from employees e inner join dept_emp d on e.emp_no = d.emp_no where dept_no is not null; # 考察表內鏈接,不用指定dept_no是否爲null,由於內鏈接中,任何一邊有缺失數據就不會顯示。
五、查找全部員工的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`));
select last_name,first_name,dept_no from employees e left join dept_emp d on e.emp_no = d.emp_no; #即便沒有分配部門的員工也要顯示,意味着employees表中全部emp_no都要顯示,無論dept_emp表的對應dept_no是否缺失。考察左鏈接
多表鏈接查詢知識點總結:
表1 inner join 表2 兩邊表同時有對應的數據,即任何一邊有缺失數據就不顯示;
主 left join 從 左邊主表的數據所有讀取,右邊從邊無對應數據的填充NULL值;
從 right join 主 反之;
六、查找全部員工入職時候的薪水狀況,給出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)錶鏈接
select e.emp_no, s.salary from employees e inner join salaries s on e.emp_no = s.emp_no where s.from_date = e.hire_date order by e.emp_no desc; # 1.有漲薪或者降薪,說明salaries表中的每個emp_no至少有一個,薪水變過就有重複值。 # 2.只要from_date等於入職日期hire_date,薪水就是入職時的薪水。
(2)分組以後求日期最小值
select emp_no,salary from salaries group by emp_no having min(from_date) order by emp_no desc; # 1.先用emp_no分組,獲得每一個員工分組數據 # 2.再用having對每一個分組求最先日期,即剛入職的日期,不能求最小工資,由於員工有可能被降薪。 # 3.數據量大時,不建議用分組查詢,由於having以後,程序會在每一個分組表中在遍歷一遍,可能致使性能不佳。
七、查找薪水變更超過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`));
解題:
select emp_no,count(*) as t from salaries group by emp_no having count(*) > 15; # 考察點是分組統計查詢,
分組聚合篩選查詢知識點概括:
語法:
SELECT column1, column2, ... column_n, aggregate_function (expression),constant
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n
HAVING condition1 ... condition_n;
重點:
(12題,有典型的錯誤例子。)
八、找出全部員工當前(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`));
解題:
(1)distinct關鍵字排除重複
select distinct salary from salaries where to_date='9999-01-01' order by salary desc; # distinct 多列去重時,只有全部列的信息徹底一致才認爲時重複的。
(2)用group by去重,聽說數據量很大時,效率比較高
select salary from salaries where to_date='9999-01-01' group by salary order by salary desc;
九、獲取全部部門當前(dept_manager.to_date='9999-01-01')manager的當前(salaries.to_date='9999-01-01')薪水狀況,給出dept_no, emp_no以及salary(請注意,同一我的可能有多條薪水狀況記錄)
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 dept_no,d.emp_no,salary from dept_manager d inner join salaries s on d.emp_no = s.emp_no where d.to_date='9999-01-01' and s.to_date='9999-01-01';
十、獲取全部非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,
select e.emp_no from employees e left join dept_manager d on e.emp_no = d.emp_no where d.dept_no is null; # 1.假如員工不是manager,那麼dept_no字段應該爲null # 2.經過左鏈接的方式,使不是manager的dept_no字段爲null,再篩選便可
(2)子查詢
select emp_no from employees where emp_no not in( select d.emp_no from dept_manager d inner join employees e on d.emp_no = e.emp_no ); # 1.先用子查詢查出是manger的emp_no # 2.再判斷員工emp_no不在manger的emp_no裏面便可 # 3.子查詢能夠直接用select emp_no from dept_manager,畢竟dept_manager這個表存的是manage的信息。
十一、獲取全部員工當前的(dept_manager.to_date='9999-01-01')manager,若是員工是manager的話不顯示(也就是若是當前的manager是本身的話結果不顯示)。輸出結果第一列給出當前員工的emp_no,第二列給出其manager對應的emp_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,
select de.emp_no, dm.emp_no as manager_no from dept_emp de inner join dept_manager dm on dm.dept_no = de.dept_no where de.emp_no <> dm.emp_no and dm.to_date='9999-01-01' and de.to_date='9999-01-01'; # 1.兩表內鏈接後,只有manager的de.emp_no和dm.emp_no是同樣的,用where篩選掉便可。 # 2.由於部門的manager有可能會離職或者更換,要保證manage和普通員工都在同一時間在同一部門才能構成從屬關係。兩個跨時空的人戀愛會很慘的!!!
十二、獲取全部部門中當前(dept_emp.to_date = '9999-01-01')員工當前(salaries.to_date='9999-01-01')薪水最高的相關信息,給出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,