牛客數據庫SQL實戰 51-60(substr切割字符串、group_concat組拼接、limit_offset分頁、exists條件成立判斷、case分支、表的複用)


歡迎訪問筆者個人技術博客: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

  • 方法一:利用 LIMITOFFSET 關鍵字。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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章