8-adv_SQL_eval_inges2_1_sols Practice 1 Solutions 1. Display the department that has no employees. SQL> 2 3 4 5 6 SELECT FROM MINUS SELECT FROM WHERE deptno,dname dept e.deptno,d.dname emp e,dept d e.deptno = d.deptno; 2. Find the job that was filled in the last half of 1981 and the same job that was filled during the same period in 1982. SQL> 2 3 4 5 6 7 SELECT job FROM emp WHERE hiredate BETWEEN '01-JUN-81' AND '30-DEC-81' INTERSECT SELECT job FROM emp WHERE hiredate BETWEEN '01-JUN-82' AND '30-DEC-82'; Practice 1 Solutions (continued) 4. Produce a list of jobs for departments 10, 30, and 20 in that order. Display job and department number. COLUMN dummy NOPRINT SELECT FROM WHERE UNION SELECT FROM WHERE UNION SELECT FROM WHERE ORDER BY / job,deptno,'x' dummy emp deptno = 10 job,deptno,'y' emp deptno = 30 job,deptno,'z' emp deptno = 20 3 5. List the department number for departments without the job title ANALYST. SQL> 2 3 4 5 6 SELECT FROM MINUS SELECT FROM WHERE deptno dept deptno emp job = 'ANALYST'; 8-adv_SQL_eval_inges2_1_sols 6. List all job titles in department 10 and 20 that do not occur in both departments. SQL> 2 3 4 5 6 7 8 9 10 11 SELECT FROM WHERE MINUS job emp deptno in (20,10) (SELECT job FROM emp WHERE deptno = 10 INTERSECT SELECT job FROM emp WHERE deptno = 20); Practice 2 Solutions 2. Find all employees who are not a supervisor. a. Do this using the EXISTS operator first. SQL> SELECT outer.ename 2 FROM emp outer 3 WHERE EXISTS (SELECT empno 4 FROM emp inner 5 WHERE inner.mgr = outer.empno); b. Can this be done using the IN operator? Why, or why not? SQL> SELECT outer.ename 2 FROM emp outer 3 WHERE outer.empno NOT IN (SELECT inner.mgr FROM emp inner); This alternative solution is not a good one. The subquery picks up a NULL value, and hence the entire query returns no rows. The reason is that all conditions that compare a NULL value, result in NULL. So, whenever NULL values are likely to be part of the value set, do not use NOT IN as a substitute for NOT EXISTS. Practice 2 Solutions (continued) 3. Write a query to find all employees who make more than the average salary in their department. Display employee number, salary, department number, and the average salary for the department. Sort by average salary. SQL> 2 3 4 5 6 7 SELECT FROM WHERE AND e.ename ename, e.sal salary, e.deptno deptno, AVG(a.sal) dept_avg emp e, emp a e.deptno = a.deptno e.sal > (SELECT AVG(sal) FROM emp WHERE deptno = e.deptno) 8-adv_SQL_eval_inges2_1_sols 8 9 GROUP BY e.ename, e.sal, e.deptno ORDER BY AVG(a.sal); 4. Write a query to display employees who earn less than half the average salary in their department. SQL> SELECT 2 FROM 3 WHERE 4 5 6 ename emp outer outer.sal < (SELECT avg(inner.sal/2) FROM emp inner WHERE inner.deptno = outer.deptno); 5. Write a query to display employees who have one or more co-workers in their department with later hiredates but higher salaries. SQL> SELECT 2 FROM 3 WHERE 4 5 6 7 8 ename emp outer EXISTS (SELECT FROM WHERE AND AND inner.empno emp inner inner.deptno = outer.deptno inner.hiredate > outer.hiredate inner.sal > outer.sal); 3. Hierarchical Retrieval 2. Write a hierarchical query showing employee number, manager number, and employee name for all employees who are two levels below JONES (employee 7566). SQL> 2 3 4 5 SELECT empno, mgr, level, ename FROM emp WHERE LEVEL = 3 CONNECT BY mgr = PRIOR empno START WITH empno = 7566; 4. Generate Scripts to Generate Scripts 1. Write a SQL script file to drop all objects (tables, views, indexes, sequences, synonyms and so on) that you own. The output shown is just a guideline. SET HEADING OFF ECHO OFF FEEDBACK OFF TERMOUT OFF SET PAGESIZE 0 SPOOL dropall.sql SELECT 'drop ' || OBJECT_TYPE || ' ' || OBJECT_NAME || ';' FROM user_objects ORDER BY object_type / SPOOL off 8-adv_SQL_eval_inges2_1_sols SET HEADING ON ECHO ON FEEDBACK ON TERMOUT ON SET PAGESIZE 24 2. Write a SQL script to produce a CREATE TABLE statement for every table you own. Hints: • The data dictionary view USER_TAB_COLUMNS contains all the information that you need. • Assume that you have only relational tables in your database and no LOBs. • Write three SELECT statements combined with the UNION operator. – The first one builds the first part of the CREATE TABLE statement. – The second one picks up the column definition for all columns but the last column. – The third one picks up the column definition for the last column. 4. Generate Scripts to Generate Scripts (continued) SET FEEDBACK OFF ECHO OFF HEAD OFF SET PAGESIZE 9999 COLUMN sort1 NOPRINT COLUMN sort2 NOPRINT BREAK ON sort1 skip1 SPOOL c:\create.sql SELECT DISTINCT table_name sort1, 0 sort2, 'CREATE TABLE ' || table_name ||' (' FROM user_tab_columns UNION SELECT table_name sort1, column_id sort2, ' '|| column_name || DECODE(data_type,'DATE',' DATE', 'LONG',' LONG', 'CHAR',' CHAR('||data_length||')', 'VARCHAR2',' VARCHAR2('||data_length||')', 'NUMBER', DECODE(data_precision,null,' NUMBER', ' NUMBER('||data_precision||','|| data_scale||') '), '*****Invalid datatype******')|| DECODE(nullable,'N',' NOT NULL',null)||',' FROM user_tab_columns c WHERE column_id < (SELECT MAX(column_id) FROM user_tab_columns WHERE table_name = c.table_name) UNION SELECT table_name sort1, column_id sort2, 8-adv_SQL_eval_inges2_1_sols ' '|| column_name || DECODE(data_type,'DATE',' DATE', 'LONG',' LONG', 'CHAR',' CHAR('||data_length||')', 'VARCHAR2',' VARCHAR2('||data_length||')', 'NUMBER', DECODE(data_precision,null,' NUMBER', ' NUMBER('||data_precision||','|| data_scale||') '), '*****Invalid datatype*****')|| DECODE(nullable,'N',' NOT NULL',null)||') /' FROM user_tab_columns c WHERE column_id = (SELECT max(column_id) FROM user_tab_columns WHERE table_name = c.table_name) ORDER BY 1,2 / SPOOL OFF COLUMN sort1 CLEAR COLUMN sort2 CLEAR SET FEEDBACK ON HEAD ON ECHO ON SET PAGESIZE 24