文章目錄
歡迎訪問筆者個人技術博客:http://rukihuang.xyz/
牛客網數據庫SQL實戰
51* 獲取Employees中的first_name
51.1 題目描述
獲取Employees中的first_name,查詢按照first_name最後兩個字母,按照升序進行排列
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`));
輸出格式:
first_name |
---|
Chirstian |
Tzvetan |
Bezalel |
Duangkaew |
Georgi |
Kyoichi |
Anneke |
Sumant |
Mary |
Parto |
Saniya |
51.2 題解 substr
select
first_name
from
employees
order by
substr(first_name, length(first_name)-1,length(first_name))
- 本題考查
substr(X,Y,Z)
或substr(X,Y)
函數的使用。其中X是要截取的字符串。Y是字符串的起始位置(注意第一個字符的位置爲1,而不爲0),取值範圍是±(1~length(X))
,當Y等於length(X)
時,則截取最後一個字符;當Y等於負整數-n時,則從倒數第n個字符處截取。Z是要截取字符串的長度,取值範圍是正整數,若Z省略,則從Y處一直截取到字符串末尾;若Z大於剩下的字符串長度,也是截取到字符串末尾爲止。
52* 按照dept_no進行彙總
52.1 題目描述
按照dept_no進行彙總,屬於同一個部門的emp_no按照逗號進行連接,結果給出dept_no以及連接出的結果employees
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`));
輸出格式:
dept_no | employees |
---|---|
d001 | 10001,10002 |
d002 | 10006 |
d003 | 10005 |
d004 | 10003,10004 |
d005 | 10007,10008,10010 |
d006 | 10009,10010 |
52.2 題解 group_concat(字段名,分隔符)
select
dept_no
,group_concat(emp_no, ",")
from
dept_emp
group by
dept_no
- 本題要用到SQLite的聚合函數
group_concat(X,Y)
,其中X是要連接的字段,Y是連接時用的符號,可省略,默認爲逗號。此函數必須與 GROUP BY 配合使用。此題以 dept_no 作爲分組,將每個分組中不同的emp_no用逗號連接起來(即可省略Y)。
53 查找排除當前最大、最小salary之後的員工的平均工資avg_salary
53.1 題目描述
查找排除當前最大、最小salary之後的員工的平均工資avg_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`));
輸出格式:
avg_salary |
---|
69462.5555555556 |
53.2 題解
- 正常邏輯,OJ過不了
select
avg(salary) as avg_salary
from
salaries
where
salary not in(
-- 1 找到最高工資和最小工資的salary
(select
max(salary)
from
salaries
where
to_date = '9999-01-01') -- OJ中需要把時間條件刪除,才能過
,(select
min(salary)
from
salaries
where
to_date = '9999-01-01') -- OJ中需要把時間條件刪除,才能過
)
and
to_date = '9999-01-01'
- OJ通過題解
select
avg(salary) as avg_salary
from
salaries
where
salary not in(
-- 1 找到最高工資和最小工資的salary
(select
max(salary)
from
salaries
)
,(select
min(salary)
from
salaries
)
)
and
to_date = '9999-01-01'
54 分頁查詢employees表,每5行一頁,返回第2頁的數據
54.1 題目描述
分頁查詢employees表,每5行一頁,返回第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`));
54.2 題解 limit offset
- 方法一:利用
LIMIT
和OFFSET
關鍵字。LIMIT
後的數字代表返回幾條記錄,OFFSET
後的數字代表從第幾條記錄開始返回==(第一條記錄序號爲0)==,也可理解爲跳過多少條記錄後開始返回。
select
*
from
employees
limit
5 -- 返回5條數據
offset
5 -- 從第6條數據開始返回
- 只利用
LIMIT
關鍵字。注意:在 LIMIT X,Y 中,Y代表返回幾條記錄,X代表從第幾條記錄開始返回(第一條記錄序號爲0),切勿記反。
select
*
from
employees
limit
5,5 -- 從第6條記錄開始,返回4條數據(第1條數據是第0條數據)
55 獲取所有員工的emp_no
55.1 題目描述
獲取所有員工的emp_no、部門編號dept_no以及對應的bonus類型btype和received ,沒有分配具體的員工不顯示
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`));
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`));
create table emp_bonus(
emp_no int not null,
received datetime not null,
btype smallint not null);
輸出格式:
e.emp_no | dept_no | btype | received |
---|---|---|---|
10001 | d001 | 1 | 2010-01-01 |
10002 | d001 | 2 | 2010-10-01 |
10003 | d004 | 3 | 2011-12-03 |
10004 | d004 | 1 | 2010-01-01 |
10005 | d003 | ||
10006 | d002 | ||
10007 | d005 | ||
10008 | d005 | ||
10009 | d006 | ||
10010 | d005 | ||
10010 | d006 |
55.2 題解
select
d.emp_no
,d.dept_no
,e.btype
,e.recevied -- 這個字段是題目打錯的,我日,建議擊斃
from
dept_emp d
left join
emp_bonus e
on
d.emp_no = e.emp_no
- 正常題解:本題嚴謹的思路爲,先將 employees與dept_emp 用 INNER JOIN 連接,挑選出分配了部門的員工,再用 LEFT JOIN 連接 emp_bonus(在前面的題中可看到此表),分配了獎金的員工顯示獎金類型和授予時間,沒分配獎金的員工則不顯示。
SELECT
em.emp_no
, de.dept_no
, eb.btype
, eb.recevied
FROM
employees AS em
INNER JOIN
dept_emp AS de
ON
em.emp_no = de.emp_no
LEFT JOIN
emp_bonus AS eb
ON
de.emp_no = eb.emp_no
56* 使用含有關鍵字exists查找未分配具體部門的員工的所有信息。
56.1 題目描述
使用含有關鍵字exists查找未分配具體部門的員工的所有信息。
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 `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`));
輸出格式:
emp_no | birth_date | first_name | last_name | gender | hire_date |
---|---|---|---|---|---|
10011 | 1953-11-07 | Mary | Sluis | F | 1990-01-22 |
56.2 題解 exists
- 不使用
exists
select
*
from
employees
where
emp_no not in (
select
emp_no
from
dept_emp d
)
- 使用
exists
select
*
from
employees
where not exists (
select
emp_no
from
dept_emp
where
emp_no = employees.emp_no -- 外面的表一定要和存在條件的子表差生關聯
)
SELECT
*
FROM
employees
WHERE emp_no NOT exists (
SELECT
emp_no
FROM
dept_emp) -- 過不了,在 employees 中沒有一條記錄能使 (SELECT emp_no FROM dept_emp) 不成立。(SELECT emp_no FROM dept_emp) 沒有跟 emplotees 產生聯繫,因爲無論選中 employees 中的哪條記錄,(SELECT emp_no FROM dept_emp) 都成立
57 獲取employees中的行數據,且這些行也存在於emp_v中
57.1 題目描述
存在如下的視圖:
create view emp_v as select * from employees where emp_no >10005;
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`));
獲取employees中的行數據,且這些行也存在於emp_v中。注意不能使用intersect關鍵字。
輸出格式:
emp_no | birth_date | first_name | last_name | gender | hire_date |
---|---|---|---|---|---|
10006 | 1953-04-20 | Anneke | Preusig | F | 1989-06-02 |
10007 | 1957-05-23 | Tzvetan | Zielinski | F | 1989-02-10 |
10008 | 1958-02-19 | Saniya | Kalloufi | M | 1994-09-15 |
10009 | 1952-04-19 | Sumant | Peac | F | 1985-02-18 |
10010 | 1963-06-01 | Duangkaew | Piveteau | F | 1989-08-24 |
10011 | 1953-11-07 | Mary | Sluis | F | 1990-01-22 |
57.2 題解
-- 這題真的智障
select
*
from
emp_v
58 獲取有獎金的員工相關信息。
58.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`));
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 emp_bonus(
emp_no int not null,
recevied datetime not null,
btype smallint not null);
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`));
給出emp_no、first_name、last_name、獎金類型btype、對應的當前薪水情況salary以及獎金金額bonus。 bonus類型btype爲1其獎金爲薪水salary的10%,btype爲2其獎金爲薪水的20%,其他類型均爲薪水的30%。 當前薪水錶示to_date=‘9999-01-01’
輸出格式:
emp_no | first_name | last_name | btype | salary | bonus |
---|---|---|---|---|---|
10001 | Georgi | Facello | 1 | 88958 | 8895.8 |
10002 | Bezalel | Simmel | 2 | 72527 | 14505.4 |
10003 | Parto | Bamford | 3 | 43311 | 12993.3 |
10004 | Chirstian | Koblick | 1 | 74057 | 7405.7 |
58.2 題解 case…when…then…else…end
select
em.emp_no
,em.first_name
,em.last_name
,eb.btype
,s.salary
,(case eb.btype
when 1 then 0.1 * s.salary
when 2 then 0.2 * s.salary
else 0.3 * s.salary end ) as bonus
from
employees em
left join
emp_bonus eb
on
em.emp_no = eb.emp_no
left join
salaries s
on
eb.emp_no = s.emp_no
where
s.to_date = '9999-01-01'
59* 統計salary的累計和running_total
59.1 題目描述
按照salary的累計和running_total,其中running_total爲前兩個員工的salary累計和,其他以此類推。 具體結果如下Demo展示。。
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`));
輸出格式:
emp_no | salary | running_total |
---|---|---|
10001 | 88958 | 88958 |
10002 | 72527 | 161485 |
10003 | 43311 | 204796 |
10004 | 74057 | 278853 |
10005 | 94692 | 373545 |
10006 | 43311 | 416856 |
10007 | 88070 | 504926 |
10009 | 95409 | 600335 |
10010 | 94409 | 694744 |
10011 | 25828 | 720572 |
59.2 題解
本題的思路爲複用 salaries 表進行子查詢,最後以 s1.emp_no 排序輸出求和結果。
1、輸出的第三個字段,是由一個 SELECT 子查詢構成。將子查詢內複用的 salaries 表記爲 s2,主查詢的 salaries 表記爲 s1,當主查詢的 s1.emp_no 確定時,對子查詢中不大於 s1.emp_no 的 s2.emp_no 所對應的薪水求和
2、注意是對員工當前的薪水求和,所以在主查詢和子查詢內都要加限定條件 to_date = ‘9999-01-01’
select
s2.emp_no
,s2.salary
,(
select
sum(salary)
from
salaries s1
where
s1.emp_no <= s2.emp_no -- 複用兩張表
and
s1.to_date = '9999-01-01'
) as running_total
from
salaries s2
where
s2.to_date = '9999-01-01'
60* 對於employees表中,給出奇數行的first_name
60.1 題目描述
對於employees表中,給出奇數行的first_name
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`));
輸出格式:
first_name |
---|
Georgi |
Chirstian |
Anneke |
Tzvetan |
Saniya |
Mary |
60.2 題解
SELECT
E1.first_name
FROM
employees E1
WHERE (
SELECT
COUNT(*) -- 序號 複用2張表,先對first_name進行排序,count(*)就是序號
FROM
employees E2
WHERE
E1.first_name >= E2.first_name) % 2 = 1;