zoukankan      html  css  js  c++  java
  • [牛客数据库SQL实战] 11~20题及个人解答

    11. 获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date='9999-01-01'。

    结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no

    -- dept_emp部门员工表找到员工emp_no对应的部门dept_no, dept_manager部门管理表再找到管理者emp_no
    SELECT de.emp_no, dm.emp_no AS manager_no 
    FROM dept_emp AS de, dept_manager AS dm 
    WHERE de.emp_no!=dm.emp_no AND dm.dept_no=de.dept_no 
    AND de.to_date="9999-01-01" AND dm.to_date="9999-01-01";
    

    运行时间:30ms

    占用内存:3464k

    -- 使用内连接INNER JOIN关联部门员工表和管理员表
    SELECT de.emp_no, dm.emp_no AS manager_no 
    FROM dept_emp AS de 
    INNER JOIN dept_manager AS dm 
    ON dm.dept_no=de.dept_no 
    WHERE de.emp_no!=dm.emp_no 
    AND de.to_date="9999-01-01" AND dm.to_date="9999-01-01";
    

    运行时间:16ms

    占用内存:3344k

    12. 获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary

    当前(to_date="9999-01-01")各部门薪水最高员工
    注意:该题目和审核系统是有坑的...

    SELECT re1.dept_no, re2.emp_no, re1.salary
    FROM (
    	-- 先找出各部门最高薪水值 通过部门编号分组
    	SELECT dept_em.dept_no, MAX(em_sa.salary) AS salary
    	FROM (
    		SELECT emp_no, salary
    		FROM salaries
    		WHERE to_date = '9999-01-01'
    	) AS em_sa
    	LEFT JOIN (
    		SELECT emp_no, dept_no
    		FROM dept_emp
    		WHERE to_date = '9999-01-01'
    	) AS dept_em 
    	ON em_sa.emp_no = dept_em.emp_no
    	GROUP BY dept_no) re1
    JOIN (
    	-- 再找出各部门员工的薪水值 通过左连接
        SELECT dept_em.dept_no, em_sa.emp_no, em_sa.salary AS salary
        FROM (
    		SELECT emp_no, salary
    		FROM salaries
    		WHERE to_date = '9999-01-01'
    	) AS em_sa
    	LEFT JOIN (
    		SELECT emp_no, dept_no
    		FROM dept_emp
    		WHERE to_date = '9999-01-01'
    	) AS dept_em 
    	ON em_sa.emp_no = dept_em.emp_no) re2 
    -- 通过连接获得最高薪水值对应的员工编号
    ON re1.dept_no = re2.dept_no AND re1.salary = re2.salary
    ORDER BY re1.dept_no;
    

    运行时间:20ms

    占用内存:5076k

    • 分析SQL代码:
      第一种解法: 6.67's
    -- 通过to_date缩减需要选取的数据 
    -- 当前salaries表的emp_no和salary 
    SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01';
    -- 当前dept_emp表的dept_no和emp_no
    SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01';
    -- 通过部门编号分组, 当前各部门的最高薪水salary和部门编号dept_no
    SELECT dm.dept_no, MAX(se.salary) salary
    FROM (
    	(
    		SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
    	) AS se
    	LEFT JOIN
    	(
    		SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
    	) AS dm
    	ON se.emp_no=dm.emp_no)
    GROUP BY dm.dept_no;
    -- 无需分组, 将部门/员工/薪水合并到一个表内
    SELECT dm.dept_no, dm.emp_no, se.salary
    FROM (
    	(
    		SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
    	) AS se
    	LEFT JOIN
    	(
    		SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
    	) AS dm
    	ON se.emp_no=dm.emp_no);
    -- 通过`部门/最高薪水`的条件 去筛选/定位 `员工编号`
    SELECT re1.dept_no, re2.emp_no, re1.salary
    FROM (
    	SELECT dm.dept_no, MAX(se.salary) salary
    	FROM (
    		(
    			SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
    		) AS se
    		LEFT JOIN
    		(
    			SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
    		) AS dm
    		ON se.emp_no=dm.emp_no)
    	GROUP BY dm.dept_no
    ) AS re1 JOIN (
    	SELECT dm.dept_no, dm.emp_no, se.salary
    	FROM (
    		(
    			SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01'
    		) AS se
    		LEFT JOIN
    		(
    			SELECT dept_no, emp_no FROM dept_emp WHERE to_date='9999-01-01'
    		) AS dm
    		ON se.emp_no=dm.emp_no)
    ) AS re2
    ON re2.dept_no=re1.dept_no AND re2.salary=re1.salary
    ORDER BY re1.dept_no;
    

    第二种解法: 5.93's 结果是一样的,但无法通过牛客的审核

    SELECT de.dept_no,sa.emp_no,re.sal AS salary
    FROM (
        -- 通过分组,拿到各部门编号以及对应的最高薪水
        SELECT d.dept_no, MAX(s.salary) AS sal
        FROM dept_emp AS d JOIN salaries AS s
        ON 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
    ) AS re, dept_emp AS de, salaries AS sa
    -- 三表查询 re的最高薪水 部门员工表的部门编号 薪水表的员工编号
    WHERE re.dept_no=de.dept_no AND de.emp_no=sa.emp_no AND re.sal=sa.salary;
    

    13. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t

    SELECT title, COUNT(title) AS t FROM titles GROUP BY title HAVING t >= 2;
    

    运行时间:18ms

    占用内存:3424k

    • 注意:where和having的不同之处在于,where是查找之前的限定,而having是查找之后

    14. 从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。

    注意对于重复的emp_no进行忽略

    -- 统计拥有相同 title 的不同员工的个数 distinct可以放入函数体内
    SELECT title, COUNT(DISTINCT emp_no) AS t FROM titles GROUP BY title HAVING t >= 2;
    

    运行时间:17ms

    占用内存:3300k

    15. 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列

    -- 判断属性奇偶数 1)取余 2)除与2再乘与2 3)位运算
    SELECT * FROM employees WHERE emp_no%2=1 AND last_name!='Mary' ORDER BY hire_date DESC;
    

    运行时间:20ms

    占用内存:3400k

    mysql判断奇数偶数,并思考效率

    16. 统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。

    -- 注意avg是sql语法的关键字,需要``对其进行标注
    SELECT t.title, AVG(s.salary) AS `avg` FROM titles AS t INNER JOIN salaries AS s ON s.emp_no=t.emp_no AND s.to_date='9999-01-01' AND t.to_date='9999-01-01' GROUP BY title;
    

    运行时间:28ms

    占用内存:3404k

    17. 获取当前(to_date='9999-01-01')薪水第二多的员工的emp_no以及其对应的薪水salary

    -- 将salaries表按薪水salary逆序排列,再选取第二位
    SELECT emp_no, salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1;
    

    运行时间:22ms

    占用内存:3320k

    -- 以上方法是有缺陷的,题意是指薪水第二多,而同一薪水可能有多名员工
    -- 先求出当前第二多薪水数额(distinct和group by都可以)
    SELECT DISTINCT salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1;
    SELECT salary FROM salaries WHERE to_date='9999-01-01' GROUP BY salary ORDER BY salary DESC LIMIT 1,1;
    -- 再通过当前时间和薪水数额定位员工编号
    SELECT emp_no, salary FROM salaries WHERE salary = (
    	SELECT DISTINCT salary FROM salaries WHERE to_date='9999-01-01' ORDER BY salary DESC LIMIT 1,1
    ) AND to_date='9999-01-01';
    

    运行时间:22ms

    占用内存:3552k

    18. 查找当前薪水(to_date='9999-01-01')排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不准使用order by

    -- 先找出当前最多薪水数额
    SELECT MAX(salary) FROM salaries WHERE to_date='9999-01-01';
    -- 使用排除法,在去掉最大值的序列中,此时最大值就原序列的第二大值
    SELECT MAX(salary) FROM salaries 
    WHERE to_date='9999-01-01' AND salary NOT IN (
    	SELECT MAX(salary)  FROM salaries WHERE to_date='9999-01-01'
    );
    -- 使用以上求取得到的第二大值
    SELECT s.emp_no, s.salary, e.last_name, e.first_name 
    FROM salaries AS s INNER JOIN employees AS e ON s.emp_no=e.emp_no 
    WHERE s.to_date='9999-01-01'
    AND s.salary = (
    	SELECT MAX(salary) FROM salaries 
    	WHERE to_date='9999-01-01' AND salary NOT IN (
    		SELECT MAX(salary)  FROM salaries WHERE to_date='9999-01-01'
    	)
    );
    

    运行时间:24ms

    占用内存:3304k

    19. 查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工

    -- 先将员工表employees和部门员工表dept_emp连接 合成部门员工详细表ds
    SELECT e.emp_no, de.dept_no FROM employees AS e LEFT JOIN dept_emp AS de ON e.emp_no=de.emp_no;
    -- 再将部门信息表department和部门员工详细表ds连接
    SELECT ds.last_name, ds.first_name, d.dept_name FROM (
    	SELECT e.last_name, e.first_name, de.dept_no FROM employees AS e LEFT JOIN dept_emp AS de ON e.emp_no=de.emp_no
    ) AS ds LEFT JOIN departments AS d ON d.dept_no=ds.dept_no;
    

    运行时间:18ms

    占用内存:3312k

    -- 第一次 left join 是把未分配部门的员工算进去了,但是只得到了部门编号dept_no,没有部门名dept_name,
    -- 所以第二次也要 left join 把含有部门名 departments表 连接起来,
    -- 否则在第二次连接时就选不上未分配部门的员工了
    SELECT e.last_name, e.first_name, d.dept_name
    FROM employees AS e 
    LEFT JOIN dept_emp AS de ON e.emp_no = de.emp_no
    LEFT JOIN departments AS d ON de.dept_no = d.dept_no;
    

    运行时间:20ms

    占用内存:3404k

    20. 查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth

    个人理解为:获得入职时的工资距离最新的工资的涨幅情况

    -- 最大值-最小值 这种解法是有问题的 其是以薪水一直在涨/上升的前提下
    SELECT (MAX(salary)-MIN(salary)) AS growth FROM salaries WHERE emp_no='10001';
    

    运行时间:19ms

    占用内存:3424k

    -- 薪水salary涨幅值growth 当前薪水-入职薪水
    SELECT (ma.salary-mi.salary) AS growth
    FROM (
            -- 入职薪水
    	SELECT salary FROM salaries WHERE emp_no='10001' ORDER BY to_date LIMIT 0,1
    ) AS mi, (
            -- 当前薪水
    	SELECT salary FROM salaries WHERE emp_no='10001' ORDER BY to_date DESC LIMIT 0,1
    ) AS ma;
    

    运行时间:21ms

    占用内存:3688k

    完整的个人练习代码

    我的练习SQL代码已经上传至Github:https://github.com/slowbirdoflsh/newcode-sql-practice
    仅供参考~~~

  • 相关阅读:
    C# 上传图片前判断上传图片的宽和高
    PHP调用WebService
    js判断输入字符串长度(汉字算两个字符,字母数字算一个)
    js 验证电话号 座机及手机号
    C# 微信扫码支付 回调页面
    复制文件夹及文件
    html失去获得焦点
    SQL 大数据查询如何进行优化?
    sql表内存占用情况,并进行缩放
    查询被锁的表
  • 原文地址:https://www.cnblogs.com/slowbirdoflsh/p/11210684.html
Copyright © 2011-2022 走看看