牛客OJ SQL後30題的解答

題目來源:https://www.nowcoder.com/ta/sql
本文挑選了牛客OJ SQL比較典型的題目,有些題目爲什麼沒寫?那些重複性的,有些題目描述就不清楚的,看了討論區也講不清的,就沒做。
OJ系統的判題只支持SQLite,以下答案皆爲SQLite。
題目描述後面的標題是筆者自己簡化的,爲了體現題目重點。

想嘗試一下用摺疊把答案摺疊起來的,好像CSDN的markdown不支持?

題目 拼接

將employees表的所有員工的last_name和first_name拼接起來作爲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`));

輸出描述:
Name

			Facello Georgi
			Simmel Bezalel
			Bamford Parto
			Koblick Chirstian

解答

SELECT last_name || ' ' || first_name AS Name
FROM employees;

題目 創建

創建一個actor表,包含如下列信息
列表 類型 是否爲NULL 含義
actor_id smallint(5) not null 主鍵id
first_name varchar(45) not null 名字
last_name varchar(45) not null 姓氏
last_update timestamp not null 最後更新時間,默認是系統的當前時間

解答

CREATE TABLE actor
(
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')) -- ,
-- PRIMARY KEY(actor_id)
) 

題目 批量插入數據

對於表actor批量插入如下數據

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')))

actor_id first_name last_name last_update
1 PENELOPE GUINESS 2006-02-15 12:34:33
2 NICK WAHLBERG 2006-02-15 12:34:33

解答

INSERT INTO actor
VALUES(1, 'PENELOPE', 'GUINESS', '2006-02-15 12:34:33'),
    (2, 'NICK', 'WAHLBERG', '2006-02-15 12:34:33');

題目 批量插入不使用replace操作

對於表actor批量插入如下數據,如果數據已經存在,請忽略,不使用replace操作

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')))

actor_id first_name last_name last_update
‘3’ ‘ED’ ‘CHASE’ ‘2006-02-15 12:34:33’

解答

INSERT OR IGNORE INTO actor VALUES (3, 'ED', 'CHASE', '2006-02-15 12:34:33')

題目 導入到新表

對於如下表actor,其對應的數據爲:
actor_id first_name last_name last_update
1 PENELOPE GUINESS 2006-02-15 12:34:33
2 NICK WAHLBERG 2006-02-15 12:34:33

創建一個actor_name表,將actor表中的所有first_name以及last_name導入改表。 actor_name表結構如下:
列表 類型 是否爲NULL 含義
first_name varchar(45) not null 名字
last_name varchar(45) not null 姓氏

解答

CREATE TABLE actor_name AS
SELECT first_name,last_name FROM actor;

題目 唯一索引

針對如下表actor結構創建索引:

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')))

對first_name創建唯一索引uniq_idx_firstname,對last_name創建普通索引idx_lastname

解答

CREATE UNIQUE INDEX uniq_idx_firstname on actor(first_name);
CREATE INDEX idx_lastname on actor(last_name);

題目 創建視圖

針對actor表創建視圖actor_name_view,只包含first_name以及last_name兩列,並對這兩列重新命名,first_name爲first_name_v,last_name修改爲last_name_v:

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')))

解答

CREATE VIEW actor_name_view (first_name_v, last_name_v) AS
SELECT first_name, last_name FROM actor;

題目 強制索引

針對salaries表emp_no字段創建索引idx_emp_no,查詢emp_no爲10005, 使用強制索引。

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 index idx_emp_no on salaries(emp_no);

解答

MYSQL中強制索引查詢使用:FORCE INDEX(indexname);
SQLite中強制索引查詢使用:INDEXED BY indexname;

SELECT * FROM salaries INDEXED BY idx_emp_no WHERE emp_no = 10005;

題目 增加列

存在actor表,包含如下列信息:

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')));

現在在last_update後面新增加一列名字爲create_date, 類型爲datetime, NOT NULL,默認值爲’0000 00:00:00’

解答

ALTER table actor
ADD 'create_date' datetime NOT NULL DEFAULT '0000-00-00 00:00:00';

題目 觸發器

構造一個觸發器audit_log,在向employees_test表中插入一條數據的時候,觸發插入相關的數據到audit中。

CREATE TABLE employees_test(
ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL
);
CREATE TABLE audit(
EMP_no INT NOT NULL,
NAME TEXT NOT NULL
);

解答

CREATE TRIGGER audit_log AFTER INSERT ON employees_test
BEGIN
    INSERT INTO audit VALUES (NEW.ID, NEW.NAME);
END;

題目 刪除重複行

刪除emp_no重複的記錄,只保留最小的id對應的記錄。

CREATE TABLE IF NOT EXISTS titles_test (
id int(11) not null primary key,
emp_no int(11) NOT NULL,
title varchar(50) NOT NULL,
from_date date NOT NULL,
to_date date DEFAULT NULL);

insert into titles_test values ('1', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('2', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('3', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('4', '10004', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('5', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('6', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('7', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01');

解答

DELETE FROM titles_test 
WHERE id NOT IN (
    SELECT * 
    FROM(
        SELECT MIN(id) 
        FROM titles_test 
        GROUP BY emp_no
) AS a);

題目 更新行中多個元素

將所有to_date爲9999-01-01的全部更新爲NULL,且 from_date更新爲2001-01-01。

CREATE TABLE IF NOT EXISTS titles_test (
id int(11) not null primary key,
emp_no int(11) NOT NULL,
title varchar(50) NOT NULL,
from_date date NOT NULL,
to_date date DEFAULT NULL);

insert into titles_test values ('1', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('2', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('3', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('4', '10004', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('5', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('6', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('7', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01');

解答

UPDATE titles_test SET to_date = NULL, from_date = '2001-01-01'
WHERE to_date = '9999-01-01';

題目 使用REPLACE INTO

將id=5以及emp_no=10001的行數據替換成id=5以及emp_no=10005,其他數據保持不變,使用replace實現。

CREATE TABLE IF NOT EXISTS titles_test (
id int(11) not null primary key,
emp_no int(11) NOT NULL,
title varchar(50) NOT NULL,
from_date date NOT NULL,
to_date date DEFAULT NULL);

insert into titles_test values ('1', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('2', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('3', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('4', '10004', 'Senior Engineer', '1995-12-03', '9999-01-01'),
('5', '10001', 'Senior Engineer', '1986-06-26', '9999-01-01'),
('6', '10002', 'Staff', '1996-08-03', '9999-01-01'),
('7', '10003', 'Senior Engineer', '1995-12-03', '9999-01-01');

解答

REPLACE INTO的效果:有則更新,無則插入

REPLACE INTO titles_test VALUES (5, 10005, 'Senior Engineer', '1986-06-26', '9999-01-01');

題目 創建外鍵約束

在audit表上創建外鍵約束,其emp_no對應employees_test表的主鍵id。

CREATE TABLE employees_test(
ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR(50),
SALARY REAL
);

CREATE TABLE audit(
EMP_no INT NOT NULL,
create_date datetime NOT NULL
);

解答

由於SQLite中不能通過 ALTER TABLE … ADD FOREIGN KEY … REFERENCES … 語句來對已創建好的字段創建外鍵,因此只能先刪除表,再重新建表的過程中創建外鍵。

DROP TABLE audit;
 
CREATE TABLE audit(
    EMP_no INT NOT NULL,
    create_date datetime NOT NULL,
    FOREIGN KEY(EMP_no) REFERENCES employees_test(ID));

題目 JOIN

將所有獲取獎金的員工當前的薪水增加10%。

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

解答

UPDATE salaries SET salary = salary * 1.1 WHERE emp_no IN
(SELECT s.emp_no FROM salaries AS s INNER JOIN emp_bonus AS eb 
ON s.emp_no = eb.emp_no AND s.to_date = '9999-01-01');

題目 字符串相關函數(1)

查找字符串’10,A,B’ 中逗號’,'出現的次數cnt。

解答

SELECT length('10,A,B') -length(REPLACE('10,A,B',",",""))

題目 字符串相關函數(2)

獲取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

解答

SELECT first_name FROM employees
ORDER BY substr(first_name,length(first_name)-1,2);

題目 MAX() MIN() AVG()

查找排除當前最大、最小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

解答

參考討論區的解答:本題邏輯有問題,在挑選當前最大、最小salary時沒加 to_date = ‘9999-01-01’ 作條件限制,導致挑選出來的是全表最大、最小salary,然後對除去這兩個salary再作條件限制 to_date = ‘9999-01-01’ ,求平均薪水,此時求出的平均薪水與題目邏輯要求的不同。
鏈接:https://www.nowcoder.com/questionTerminal/95078e5e1fba4438b85d9f11240bc591?f=discussion

SELECT AVG(salary) AS avg_salary FROM salaries 
WHERE to_date = '9999-01-01' 
AND salary NOT IN (SELECT MAX(salary) FROM salaries)
AND salary NOT IN (SELECT MIN(salary) FROM salaries);

題目 LIMIT OFFSET

分頁查詢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`));

解答

SELECT * FROM employees LIMIT 5 OFFSET 5;

題目 LEFT JOIN

獲取所有員工的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,
recevied 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

解答

SELECT de.emp_no, de.dept_no, eb.btype, eb.recevied
FROM dept_emp AS de LEFT JOIN emp_bonus AS eb 
ON de.emp_no = eb.emp_no;

題目 EXISTS

使用含有關鍵字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

解答

SELECT * FROM employees WHERE NOT EXISTS 
(SELECT emp_no FROM dept_emp WHERE emp_no = employees.emp_no);

題目 CASE條件

獲取有獎金的員工相關信息。

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

解答

SELECT e.emp_no, e.first_name, e.last_name, b.btype, s.salary, 
(CASE b.btype 
 WHEN 1 THEN s.salary * 0.1
 WHEN 2 THEN s.salary * 0.2
 ELSE s.salary * 0.3 END) AS bonus
FROM employees AS e INNER JOIN emp_bonus AS b ON e.emp_no = b.emp_no
INNER JOIN salaries AS s ON e.emp_no = s.emp_no AND s.to_date = '9999-01-01';

題目 窗口函數

按照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

解答

題幹表述有誤,running_total給出的應該是前面所有員工的salary之和。
答案要加上to_date的條件是因爲:一個人的工資可能有多條記錄,9999-01-01對應的記錄則是最新的記錄。
參考別人的解答,把sum聚合函數作爲窗口函數使用,所有聚合函數都能用做窗口函數,其語法和專用窗口函數完全相同。

SUM(<彙總列>) OVER(<排序列>) AS 別名; 

答案:

SELECT emp_no,salary,
SUM(salary) over(ORDER BY emp_no) AS running_total
FROM salaries
WHERE to_date= '9999-01-01';
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章