SQL-1

1  SELECT * FROM table  LIMIT [offset,] rows | rows OFFSET offset

 

   在我們使用查詢語句的時候,經常要返回前幾條或者中間某幾行數據,這個時候怎麼辦呢?不用擔心,mysql已經爲我們提供了上面這樣一個功能。

 

   LIMIT 子句可以被用於強制 SELECT 語句返回指定的記錄數。LIMIT 接受一個或兩個數字參數。參數必須是一個整數常量。如果給定兩個參數,第一個參數指定第一個返回記錄行的偏移量,第二個參數指定返回記錄行的最大數目。初始記錄行的偏移量是 0(而不是 1) 爲了與 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #

mysql> SELECT * FROM table LIMIT 5,10; //檢索記錄行6-15 

 

   //爲了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數爲 -1
mysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.


   //如果只給定一個參數,它表示返回最大的記錄行數目: 
   mysql> SELECT * FROM table LIMIT 5;     //
檢索前 5 個記錄行

   //換句話說,LIMIT n 等價於 LIMIT 0,n

 

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

 

由於 SQLite 中沒有直接統計字符串中子串出現次數的函數,因此本題用length()函數與replace()函數的結合靈活地解決了統計子串出現次數的問題,屬於技巧題,即先用replace函數將原串中出現的子串用空串替換,再用原串長度減去替換後字符串的長度,最後除以子串的長度(本題中此步可省略,若子串長度大於1則不可省)。

 

SELECT (length("10,A,B")-length(replace("10,A,B",",","")))/length(",") AS cnt

 

還可以利用OJ系統的Bug直接輸出2次來通過測試

SELECT 2 AS cnt

replace函數的用法:

replace('A','b','c') c替換字符串A中所有的b

 

獲取Employees中的first_name,查詢按照first_name最後兩個字母,按照升序進行排列

 

select first_name

from employees 

order by substr(first_name,-2)

 

select first_name

from employees 

order by substr(first_name,length(first_name)-1,length(first_name))

4  按照dept_no進行彙總,屬於同一個部門的emp_no按照逗號進行連接,結果給出dept_no以及連接出的結果employees  

 

本題要用到SQLite的聚合函數group_concat(X,Y),其中X是要連接的字段,Y是連接時用的符號,可省略,默認爲逗號。此函數必須與 GROUP BY 配合使用。此題以 dept_no 作爲分組,將每個分組中不同的emp_no用逗號連接起來(即可省略Y)。

 

SELECT dept_no, group_concat(emp_no) AS employees

FROM dept_emp GROUP BY dept_no

 

5  查找排除當前最大、最小salary之後的員工的平均工資avg_salary

 

select avg(salary  as avg_salary 

from salaries 

where salary not in 

(select  max(salary)  from  salaries 

 union 

 select  min(salary)  from  salaries)  

and to_date='9999-01-01'

 

6  存在如下的視圖:
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關鍵字。
 

根據題意,不能使用 INTERSECT 關鍵字,但由於視圖 emp_v 的記錄是從 employees 中導出的,因此要判斷兩者中相等的數據,只需要判斷emp_no相等即可。

方法一:用 WHERE 選取二者 emp_no 相等的記錄

 

SELECT em.* FROM employees AS em, emp_v AS ev WHERE em.emp_no = ev.emp_no

方法二:由於emp_v的全部記錄均由 employees 導出,因此可以投機取巧,直接輸出 emp_v 所有記錄

 

SELECT * FROM emp_v

 

7  查找最晚入職員工的所有信息

 

select * from employees order by hire_date desc limit 0,1

 

查找入職員工時間排名倒數第三的員工所有信息

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

 

按照salary的累計和running_total,其中running_total爲前面所有員工的salary累計和,其他以此類推。

 

select s1.emp_no,s1.salary,(select sum(s2.salary) from salaries s2 where s1.emp_no >=s2.emp_no 

                            and s2.to_date='9999-01-01' ) 

as running_total

from salaries s1

where s1.to_date='9999-01-01' 

order by s1.emp_no

 

9  獲取所有員工當前的manager,如果當前的manager是自己的話結果不顯示

 

select  d.emp_no, dm.emp_no as manager_no

from dept_emp d ,dept_manager dm

where d.to_date='9999-01-01'

and dm.to_date='9999-01-01'

and d.dept_no=dm.dept_no 

and d.emp_no !=dm.emp_no

 

10  查找當前薪水(to_date='9999-01-01')排名第二多的員工編號emp_no、薪水salary、last_name以及first_name,不準使用order by

 

select s.emp_no,max(s.salary),e.last_name,e.first_name

from  employees e ,salaries s

where e.emp_no=s.emp_no

and s.to_date='9999-01-01'

and s.salary < (select max(salary) from salaries)

 

11  查找各個部門當前(to_date='9999-01-01')領導當前薪水詳情以及其對應部門編號

 

select salaries.*,dept_manager.dept_no from salaries,dept_manager 

where salaries.emp_no = dept_manager.emp_no 

and salaries.to_date='9999-01-01' 

and dept_manager.to_date = '9999-01-01'

 

12  查找所有員工入職時候的薪水情況,給出emp_no以及salary, 並按

 

select e.emp_no,s.salary 

from employees e,salaries s

where e.emp_no=s.emp_no

and e.hire_date=s.from_date ################重要

order by s.emp_no desc 

 

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

 

解析:由於有些員工可能沒有分配部門號,需要用左外連接就好了,即返回左表中所有的行,即便右表沒有滿足的條件

 

select a.last_name,a.first_name,b.dept_no from employees a left join dept_emp b on a.emp_no=b.emp_no

 

14 獲取員工其當前的薪水比其manager當前薪水還高的相關信息,當前表示to_date='9999-01-01',
結果第一列給出員工的emp_no,
第二列給出其manager的manager_no,
第三列給出該員工當前的薪水emp_salary,
第四列給該員工對應的manager當前的薪水manager_salary

 

 

本題主要思想是創建兩張表(一張記錄當前所有員工的工資,另一張只記錄部門經理的工資)進行比較,具體思路如下:

1、先用INNER JOIN連接salariesdemp_emp,建立當前所有員工的工資記錄sem

2、再用INNER JOIN連接salariesdemp_manager,建立當前所有員工的工資記錄sdm

3、最後用限制條件sem.dept_no = sdm.dept_no AND sem.salary > sdm.salary找出同一部門中工資比經理高的員工,並根據題意依次輸出emp_nomanager_noemp_salarymanager_salary

 

select sem.emp_no as emp_no,sdm.emp_no as manager_no,sem.salary as emp_salary,sdm.salary as manager_salary  

from 

(select s.emp_no,s.salary,de.dept_no from salaries s ,dept_emp de where s.emp_no=de.emp_no 

 and s.to_date='9999-01-01') 

as sem,

(select s.emp_no,s.salary,dm.dept_no from salaries s ,dept_manager dm where s.emp_no=dm.emp_no 

 and s.to_date='9999-01-01')

as sdm

where sem.dept_no=sdm.dept_no

and sem.salary >sdm.salary

 

15  查找所有已經分配部門的員工的last_name和first_name

 

select e.last_name,e.first_name,d.dept_no 

from employees e,dept_emp d 

where e.emp_no = d.emp_no

 

16  查找薪水漲幅超過15次的員工號emp_no以及其對應的漲幅次數t

 

select emp_no,count(emp_no) as t

from salaries s

group by emp_no having t >15

 

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

 

select distinct salary

from salaries

where to_date='9999-01-01'

order by salary desc

 

#### disticit 

 

18   獲取所有非manager的員工emp_no

 

select e.emp_no

from employees e

where e.emp_no not in (select d.emp_no from dept_manager d )

 

19  獲取所有部門中當前員工薪水最高的相關信息,給出dept_no, emp_no以及其對應的salary

 

select d.dept_no,s.emp_no ,max(s.salary) as salary 

from dept_emp d ,salaries s

where d.emp_no=s.emp_no

and d.to_date='9999-01-01'

and s.to_date='9999-01-01'

group by d.dept_no

 

20   統計出當前各個title類型對應的員工當前薪水對應的平均工資。結果給出title以及平均工資avg。

 

select t.title,avg(s.salary) as avg

from salaries s ,titles t

where s.emp_no = t.emp_no 

and s.to_date='9999-01-01'

and s.to_date=t.to_date

group by t.title

 

21  查找所有員工的last_name和first_name以及對應的dept_name,也包括暫時沒有分配部門的員工

 

select e.last_name,e.first_name,d.dept_name

from employees e  

left join dept_emp de 

on e.emp_no =de.emp_no

left join departments d

on d.dept_no=de.dept_no   

 

22  查找所有員工自入職以來的薪水漲幅情況,給出員工編號emp_no以及其對應的薪水漲幅growth,並按照growth進行升序

 

select e.emp_no,(s.salary-ss.salary) as growth

from employees e,salaries s,salaries ss

where e.emp_no=s.emp_no

and e.emp_no=ss.emp_no

and s.to_date='9999-01-01'

and ss.from_date=e.hire_date

order by growth asc

 

23  統計各個部門對應員工漲幅的次數總和,給出部門編碼dept_no、部門名稱dept_name以及次數sum

 

select d.dept_no,d.dept_name,count(salary)as  sum

from departments d,dept_emp de,salaries s

where d.dept_no=de.dept_no 

and de.emp_no=s.emp_no

group by d.dept_no

 

24 從titles表獲取按照title進行分組,每組個數大於等於2,給出ti

 

select title, count(distinct emp_no) as t

from titles

group by title having t>=2

 

輸出描述:

 

title

t

Assistant Engineer

2

Engineer

3

省略

省略

Staff

3

 

25  員工薪水排序

 

對所有員工的當前(to_date='9999-01-01')薪水按照salary進行按照1-N的排名,相同salary並列且按照emp_no升序排列

 

select s1.emp_no,s1.salary,  count(distinct s2.salary) as rank

from salaries s1 ,salaries s2

where s1.to_date='9999-01-01' 

and s2.to_date='9999-01-01'

and s1.salary <=s2.salary

group by s1.emp_no

order by s1.salary desc ,s1.emp_no asc

 

26  給出emp_no、first_name、last_name、獎金類型btype、對應的當前薪水情況salary以及獎金金額bonus。 bonus類型btype爲1其獎金爲薪水salary的10%,btype爲2其獎金爲薪水的20%,其他類型均爲薪水的30%。 當前薪水錶示to_date='9999-01-01'

 

select s.emp_no,e.first_name,e.last_name,eb.btype,s.salary,(

    case eb.btype

when 1 then s.salary*0.1

when 2 then s.salary*0.2

else s.salary*0.3 end) as bonus

from salaries s inner join emp_bonus eb on s.emp_no= eb.emp_no 

inner join employees e on s.emp_no=e.emp_no 

and s.to_date='9999-01-01'

 

其實觀察測試數據會發現 btype 只有1,2,3三種情況,即使不會 CASE 表達式,也能運用四則運算解出:(注意要除以10.0,如果除以10的話,結果的小數位會被捨去)

  

SELECT e.emp_no, e.first_name, e.last_name, b.btype, s.salary, 

(s.salary * b.btype / 10.0) 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'

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章