CS 460 : Assignment # 2 Due: Tue Feb 20th, 6pm in CS460 Drop-off Box (30% penalty/day for late submissions upto Wenesday Feb 21, 5pm) Problem 1: [20 pts] Consider the following schema: WORKS ( person-name, company-name, salary) LIVES ( person-name, street, city) LOCATED-IN ( company-name, city) MANAGES ( person-name, manager-name) The WORKS relation contains information about where an employee works and with what salary, the LIVES relation tells us where an employee lives, the LOCATED-IN relation gives the location of each company, while the MANAGES relation provides the employees and their managers. Give an expression in Relational Calculus for each of the queries below: 1.1. Find the names of all employees who work for First Bank Corporation. 1.2. Find the names and city of all employees who work for First Bank Corporation. 1.3. Find the names of all employees who live in the same city as the company they work for. 1.4. Find the names of all employees who live in the same city and on the same street as their manager. Programming Exercises: 1. Login to csa3.bu.edu 2. At command prompt type: oraenv When prompted for ORACLE_SID=? type “orcl” 3. In your .cshrc add the following: setenv ORACLE_HOME /fs/local/oracle/app/oracle/product/10.2.0/db_1 setenv ORACLE_SID orcl set path = ( $path /fs/local/oracle/app/oracle/product/10.2.0/db_1/bin) 4. source .cshrc SQL*PLUS SQL*Plus is a text editor available in all Oracle Except inside quotation marks of strings, Oracle commands are case-insensitive The semicolon (;) terminates a SQL statement The right-leaning slash (/) executes SQL statement stored in Oracle buffer SQL*Plus can be used to – Enter SQL statements e.g., SQL> select * from emp; – Submit SQL files created by text editors, e.g., notepad, to Oracle e.g., SQL > @myhw.sql – Spool output to an output file in the OS filesystem. e.g., SQL > spool myhw.log 5. Login to oracle and run your SQL commands using SQL*PLUS: sqlplus <username_in_your_email>/< username_in_your_email> @orcl (i.e., if the email is lodrina@cs.bu.edu, then the username is lodrina and password is lodrina too). (e.g. sqlplus lodrina/lodrina@orcl or sqlplus sumeet/sumeet@orcl etc.)… -- Change your password Sqlplus will then ask you to set a new password which you will use to login from Next time. If you set the password to ‘myname’ and your username is lodrina, next Time you will login as “sqlplus lodrina/myname”. -- You can explicitly change your password using the following command: alter user <username> identified by <mynewpassword>; 6. Running sql commands at SQL prompt: SQL> select tname from tab; SQL> select owner, table_name from all_tables; 7. To quit from a sqlplus session: - just type “quit” and it will put you in shell prompt. Now at “SQL>” prompt you can run your SQL statements. Basic commands to look at tables and their descriptions: - Select tname from tab ; - Or select table_name from user_tables; -- Or select owner, table_name from all_tables; - Describe scott.emp; Write SQL and show the sql, output for following. Use order by to sort the results Problem 2: [80 pts] [5pts each] 2.1 Identify all the tables in scott; along with their primary keys. Answer: SELECT table_name FROM all_tables WHERE owner = ‘SCOTT’; Possible primary keys: DESC emp; EMP EMPNO DESC dept; DEPT DEPTNO DESC BONUS; BONUS ENAME; DESC SALGRADE: SALGRADE (LOSAL, HISAL); Finding views for your queries: SELECT view_name FROM ALL_VIEWS WHERE view_name LIKE ‘%KEYS%’; SELECT view_name FROM ALL_VIEWS WHERE view_name LIKE ‘%CONS%’; Finding primary keys: SELECT b.table_name, b.column_name FROM all_constraints a, all_cons_columns b WHERE a.owner = 'SCOTT' AND a.constraint_type = 'P' AND a.constraint_name = b.constraint_name; 2.2 Identify the different job categories for employees. SELECT DISTINCT job FROM scott.emp; 2.3 For each job category, how many employees exist. SELECT job, count(*) FROM scott.emp GROUP BY job; [7pts each] 2.4 For each dept (name), determine how many employees exist. SELECT deptno, count(*) from scott.emp GROUP BY deptno; But no dept name; So Join to dept table SELECT d.dname, count(*) num_employees FROM scott.emp e, scott.dept d WHERE e.deptno = d.deptno GROUP BY d.dname ; 2.5 For each dept, determine the mean and stddev in salaries of employees SELECT d.dname, sum(sal)/count(*) mean, stddev(sal) dev FROM scott.emp e, scott.dept d WHERE e.deptno = d.deptno GROUP BY d.dname ; 2.6 For each job category find out the min, max, avg of the commission as a percentage of the salaries. SELECT job, min(comm*100/sal), max(comm*100/sal), avg(comm*100/sal) FROM scott.emp GROUP BY job; SELECT job, nvl(min(comm*100/sal), 0), nvl(max(comm*100/sal), 0), nvl(avg(comm*100/sal), 0) FROM scott.emp GROUP BY job; 2.7 Identify how many days each employee is working. Assume current date is ‘7-Feb-2007’. SELECT ename, to_date(‘7-FEB-2007’) – hiredate “num_work days” FROM scott.emp; 2.8 Find all employees whose names have the pattern ‘AM’. SELECT ename FROM scott.emp WHERE ename LIKE ‘%AM%’; [10pts each] 2.9 Identify all employees in each dept that earn more than the avg in their dept. SELECT ename FROM scott.emp e WHERE sal > (SELECT avg(sal) FROM scott.emp e2 WHERE e2.deptno = e.deptno); 2.10 Identify names of depts. that have an avg salary > 2500. SELECT dname, avg(sal) asal FROM scott.dept a, scott.emp b WHERE a.deptno = b.deptno GROUP BY dname HAVING avg(sal) > 2500; 2.11 Identify all employees in depts. that have an avg salary > 2000 and the employees have salary greater than the avg for the dept. 2.9 + 2.10 SELECT ename FROM scott.emp e WHERE sal > (SELECT avg(sal) FROM scott.emp e2 WHERE e2.deptno = e.deptno And e2.deptno in (SELECT deptno FROM scott.emp GROUP BY deptno HAVING avg(sal)>2000)); but simpler: SELECT ename FROM scott.emp e WHERE sal > (SELECT avg(sal) FROM scott.emp e2 WHERE e2.deptno = e.deptno GROUP BY deptno HAVING avg(sal) > 2000); Problem 3: [21 pts] 3.1 Identify all employees reporting to ‘CLARK’; SELECT ename FROM scott.emp START WITH MGR = (SELECT empno FROM scott.emp WHERE ename=’CLARK’) CONNECT BY NEXT mgr = empno; 3.2 Identify the manager of manager of ‘ALLEN’ SELECT ename, LEVEL FROM scott.emp START WITH ename=’ALLEN’ CONNECT BY empno = PRIOR mgr; Refine that to select only the manager’s manager which is level=3. SELECT ename FROM ( SELECT ename, LEVEL lvl FROM scott.emp START WITH ename=’ALLEN’ CONNECT BY empno = PRIOR mgr ) WHERE lvl = 3 ; 3.3 Identify all bosses (managers and higherups) of ‘ADAMS’; SELECT ename FROM ( SELECT ename, LEVEL lvl FROM scott.emp START WITH ename=’ADAMS’ CONNECT BY empno = PRIOR mgr ) WHERE lvl > 1 ; OR SELECT mgr FROM scott.emp START WITH ename=’ADAMS’ CONNECT BY empno = PRIOR mgr; And join it with emp to get the name of the mgr OR SELECT ename FROM scott.emp START WITH empno = (SELECT mgr FROM scott.emp WHERE ename = ‘ADAMS’) CONNECT BY empno = PRIOR mgr; Problem 4: [ 24pts] 4.1 Copy the tables from scott to your schema. Specify primary keys and non-null constraints. CREATE TABLE emp AS SELECT * FROM SCOTT.EMP; CREATE TABLE dept AS SELECT * FROM SCOTT.DEPT; 4.2 In your schema, create views one per dept that shows the salaries, commissions for all employees in that dept. CREATE VIEW sal_view_accounting AS SELECT e.ename, e.empno, comm, sal, d.deptno, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno and d.dname = ‘ACCOUNTING’; In PL/SQL: Set serverout on DECLARE CURSOR dcur IS SELECT * FROM dept; Dname varchar2(32); Vname varchar2(32); Stmt varchar2(256); BEGIN FOR d IN dcur LOOP vname := ‘salary_view_’ || d.dname; stmt := ‘ CREATE VIEW ‘ || vname || ‘ AS SELECT e.ename, e.empno, comm, sal, d.deptno, d.dname ‘ || ‘ FROM emp e, dept d ‘ || ‘ WHERE e.deptno = d.deptno and d.dname = ‘’’ || DBMS_ASSERT.SIMPLE_SQL_NAME(d.dname) || ‘’’’ ; dbms_output.put_line(stmt); EXECUTE IMMEDIATE stmt; END LOOP; EXCEPTION WHEN OTHERS THEN RAISE; END; / 4.3. In your schema (i.e., the schema you logged in as: halo/halo, sumeet/sumeet, etc...), create a table of all managers with an additional column to store their ‘direct’ reportees. CREATE TYPE employees_type AS TABLE of VARCHAR2(32); / CREATE TABLE mgr_emp_tab (mgrname VARCHAR2(32), employees EMPLOYEES_TYPE) NESTED TABLE employees STORE AS emptab; 1) -- First populate the managers names INSERT INTO mgr_emp_tab SELECT ename, EMPLOYEES_TYPE( ) FROM emp WHERE empno IN (SELECT mgr FROM emp); -- Insert the employees for each employee manually -- Insert into the ‘table’ of each specific employee insert into mgr_emp_tab values ('KING', EMPLOYEES_TYPE(‘JONES’, ‘BLAKE’, ‘CLARK’)); … -- Do the same for each manager OR 2) -- First populate the managers names INSERT INTO mgr_emp_tab SELECT ename, EMPLOYEES_TYPE( ) FROM emp WHERE empno IN (SELECT mgr FROM emp); -- Populate the employees for each manager automatically using a query -- Insert into the ‘table’ of each specific employee INSERT INTO TABLE(SELECT employees FROM mgr_emp_tab WHERE mgrname = ‘BLAKE’) p (SELECT ename FROM emp where mgr = (SELECT empno FROM emp WHERE ename = ‘BLAKE’)); -- Do the same for each manager -- You can put the insertion for each manager in a PL/SQL loop. 3) OR the most simplest way: USE CAST of subquery results to EMPLOYEES_TYPE and insert. Truncate table mgr_emp_tab; INSERT INTO mgr_emp_tab ( SELECT ename, CAST(MULTISET ( SELECT e1.ename FROM emp e1 WHERE e1.mgr = e2.empno ) AS EMPLOYEES_TYPE) FROM emp e2 WHERE empno in (SELECT mgr FROM emp)); 4.4. In the table created in 4.3, show the direct reportees of ‘BLAKE’. SELECT * FROM TABLE( SELECT employees FROM mgr_emp_tab WHERE mgrname=’BLAKE’);