How to establish many-many relationship in a oracle database? - oracle11g

I'm intended to develop a database model for my department. I found it difficult to establish the relationship between student, courses and staffs considering that any number of students can elect any number of courses and any number of staffs can handle any number of courses. How will I be able to represent this data in an oracle database?

What did you manage to do so far? What kind of difficulties did you meet?
Anyway: here's a suggestion, see whether it helps. An example is based on your STUDENT and COURSES tables. Idea is to include additional "cross" table which maps courses and students, i.e. contains columns that make primary keys of both tables, they are constrained by foreign key constraints and both of them make the primary key of the new, cross table.
Here's the code:
Create tables:
SQL> -- Students
SQL> create table t_student
2 (id_student number constraint pk_stu primary key,
3 student_name varchar2(20) not null
4 );
Table created.
SQL> -- Courses
SQL> create table t_course
2 (id_course number constraint pk_cou primary key,
3 course_name varchar2(20) not null
4 );
Table created.
SQL> -- Additional "cross" table
SQL> create table t_stu_x_cou
2 (id_student number constraint fk_sxc_stu
3 references t_student (id_student),
4 id_course number constraint fk_sxc_cou
5 references t_course (id_course),
6 constraint pk_sxc primary key (id_student, id_course)
7 );
Table created.
Insert sample data:
SQL> insert into t_student (id_student, student_name)
2 select 1, 'Little' from dual union
3 select 2, 'Foot' from dual;
2 rows created.
SQL> insert into t_course (id_course, course_name)
2 select 100, 'Mathematics' from dual union
3 select 200, 'Physics' from dual union
4 select 300, 'Chemistry' from dual;
3 rows created.
SQL> -- Mapping students and courses:
SQL> -- - student 1 takes 2 courses (100 and 300)
SQL> -- - student 2 takes 3 courses (100, 200 and 300)
SQL> insert into t_stu_x_cou (id_student, id_course)
2 select 1, 100 from dual union
3 select 1, 300 from dual union
4 --
5 select 2, 100 from dual union
6 select 2, 200 from dual union
7 select 2, 300 from dual;
5 rows created.
Select that shows courses taken by student 1:
SQL> select s.student_name, c.course_name
2 from t_stu_x_cou x
3 join t_student s on s.id_student = x.id_student
4 join t_course c on c.id_course = x.id_course
5 where s.id_student = 1;
STUDENT_NAME COURSE_NAME
-------------------- --------------------
Little Mathematics
Little Chemistry
SQL>
Now, try to add the STAFF table yourself, using the same principle (you'd add a new "cross" table between STAFF and COURSES).

Related

Joining two Tables in PL/SQL and obtain the required result

Structure of two tables in the database are as below.
1) Department table:
Dept_Id number(5) primary key,
Sept_Name varchar2(20),
Employee_strength number(4) not null.
2)Employee table:
E_Id number(5),
E_Name varchar2(20),
Designation varchar2(20),
D_ID number(5) references Department table Dept_ID.
A pl/sql program block to print the name the departments which has employees having the designation as "SE" is to be written and if no record in the department table fulfilling the given conditions found ,code should print the message "No record found" and if the record found code has to print Department name.
Please Help.
Here's one option (based on tables similar to yours; these belong to Scott).
I'll search for a SALESMAN.
SQL> break on deptno
SQL> select distinct d.deptno, e.job
2 from dept d left join emp e on e.deptno = d.deptno
3 order by d.deptno, e.job;
DEPTNO JOB
---------- ---------
10 CLERK
MANAGER
PRESIDENT
20 ANALYST
CLERK
MANAGER
30 CLERK
MANAGER
SALESMAN --> only department 30 has SALESMEN
40
10 rows selected.
SQL>
PL/SQL block:
SQL> set serveroutput on
SQL> declare
2 l_exists number(1);
3 begin
4 for cur_d in (select d.deptno, d.dname from dept d order by d.deptno) loop
5 select max(1)
6 into l_exists
7 from emp e
8 where e.deptno = cur_d.deptno
9 and e.job = 'SALESMAN';
10
11 dbms_output.put_line(cur_d.deptno || ' - ' ||
12 case when l_exists = 1 then cur_d.dname
13 else 'no record found'
14 end);
15 end loop;
16 end;
17 /
10 - no record found
20 - no record found
30 - SALES
40 - no record found
PL/SQL procedure successfully completed.
SQL>
If you want distinct department names then use the distinct() function in the SQL query.
I am using inner join to query the two table based on they have the same department id and department name is "SE".
Here are the steps to be followed:
declare the block(anonymous in this case)
write the SQL query for the cursor
begin the block
open the cursor
fetch the rows from the cursor
print the result
close the cursor
if the cursor doesn't contain any rows, so check for this condition
close the block
DECLARE
CURSOR C IS SELECT distinct(D.DEPT_NAME) FROM DEPARTMENTS D INNER JOIN EMPLOYEES E ON D.DEPT_ID = E.D_ID AND E.DESIGNATION LIKE 'SE';
RES C%ROWTYPE;
BEGIN
OPEN C;
loop
FETCH C INTO RES;
EXIT WHEN C%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(RES.DEPT_NAME);
end loop;
IF(C%ROWCOUNT=0) then
dbms_output.put_line('No record found');
end if;
END;
/

Need help on PL/SQL database trigger

I have a DB trigger before insert on emp table. I would like to add sal, comm from emp_test table and want to use those value as a default in the emp table, by trigger. Any idea how to do it?
Until you provide answers to questions I posted in a comment, here's how you might do it. See if you can adjust it.
EMP_TEST table contains only one row (which is kind of stupid; you'd rather use DEFAULT value for those columns in the EMP table).
SQL> create table emp_test (sal number, comm number);
Table created.
SQL> insert into emp_test (sal, comm) values (3000, 100);
1 row created.
Trigger takes SAL and COMM values if they are provided; otherwise, it takes values from the EMP_TEST table.
SQL> create or replace trigger trg_bi_emp
2 before insert on emp
3 for each row
4 begin
5 select nvl(:new.sal, t.sal),
6 nvl(:new.comm, t.comm)
7 into :new.sal,
8 :new.comm
9 from emp_test t;
10 end;
11 /
Trigger created.
Testing: I didn't provide SAL value (so trigger will insert EMP_TEST one), but I did provide COMM:
SQL> insert into emp (empno, ename, deptno, sal, comm)
2 values (1, 'Littlefoot', 40, null, 50);
1 row created.
SQL> select * from emp where empno = 1;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
1 Littlefoot 3000 50 40
SQL>

SQLite Query Duplicate record

I created two tables having following records.
CREATE TABLE ForgeRock
(`id` int,`sta` int, `productName` varchar(7), `description` varchar(55));
INSERT INTO ForgeRock
(`id`,`sta`, `productName`, `description`)
VALUES
(1, 0,'OpenIDM', 'Platform for building enterprise provisioning solutions'),
(2,0, 'OpenAM', 'Full-featured access management'),
(3,0, 'OpenDJ', 'Robust LDAP server for Java');
CREATE TABLE ForgeRock1
(`id` int,`sta` int, `productName` varchar(7), `description` varchar(55));
INSERT INTO ForgeRock1
(`id`,`sta`, `productName`, `description`)
VALUES
(1, 2,'hii', 'Platform for building enterprise provisioning solutions'),
(2,0, 'OpenAM', 'Full-featured access management'),
(3,0, 'OpenDJ', 'Robust LDAP server for Java');
I want to Union both tables but want records of duplicate id having sta=2
SELECT id,sta
FROM ForgeRock
GROUP BY id
UNION
SELECT id, sta
FROM ForgeRock1
GROUP BY id
Result:
id sta
1 0
2 0
3 0
1 2
Expected Result:
id sta
1 2
2 0
3 0
Do the grouping after the UNION, and use MAX() to select the row to output for each group:
SELECT id, MAX(sta) AS sta
FROM (SELECT id, sta
FROM ForgeRock
UNION
SELECT id, sta
FROM ForgeRock1)
GROUP BY id
ORDER BY id

Common Table Expression in sqlite using rowid

I found a good article on converting adjacency to nested sets at http://dataeducation.com/the-hidden-costs-of-insert-exec/
The SQL language used is Microsoft SQL Server (I think) and I am trying to convert the examples given in the article to sqlite (as this is what I have easy access to on my Macbook).
The problem I appear to be having is converting the part of the overall CTE query to do with the Employee Rows
EmployeeRows AS
(
SELECT
EmployeeLevels.*,
ROW_NUMBER() OVER (ORDER BY thePath) AS Row
FROM EmployeeLevels
)
I converted this to
EmployeeRows AS
(
SELECT
EmployeeLevels.*,
rowid AS Row
FROM EmployeeLevels
ORDER BY thePath
)
and the CTE query runs (no syntax errors) but the output I get is a table without the Row and Lft and Rgt columns populated
ProductName ProductID ParentProductID TreePath HLevel Row Lft Rgt
----------- ---------- --------------- ---------- ---------- ---------- ---------- ----------
Baby Goods 0 0 1
Baby Food 10 0 0.10 2
All Ages Ba 100 10 0.10.100 3
Strawberry 200 100 0.10.100.2 4
Baby Cereal 250 100 0.10.100.2 4
Beginners 150 10 0.10.150 3
Formula Mil 300 150 0.10.150.3 4
Heinz Formu 310 300 0.10.150.3 5
Nappies 20 0 0.20 2
Small Pack 400 20 0.20.400 3
Bulk Pack N 450 20 0.20.450 3
I think the start of the problem is the Row is not getting populated and therefore the Lft and Rgt columns do not get populated by the following parts of the query.
Are there any sqlite experts out there to tell me:
am I translating the rowid part of the query correctly
does sqlite support a rowid in a part of a CTE query
is there a better way? :)
Any help appreciated :)
am I translating the rowid part of the query correctly
No.
The SQL:
SELECT
EmployeeLevels.*,
rowid AS Row
FROM EmployeeLevels
ORDER BY thePath
has the Row defined as the rowid of table EmployeeLevels in SQLite, ignoring the order clause. Which is different from the intention of ROW_NUMBER() OVER (ORDER BY thePath) AS Row
does sqlite support a rowid in a part of a CTE query
Unfortunately no. I assume you mean this:
WITH foo AS (
SELECT * FROM bar ORDER BY col_a
)
SELECT rowid, *
FROM foo
but SQLite will report no such column of rowid in foo.
is there a better way?
Not sure it is better but at least it works. In SQLite, you have a mechanism of temp table which exists as long as your connection opens and you didn't delete it deliberately. Rewrite the above SQL in my example:
CREATE TEMP TABLE foo AS
SELECT * FROM bar ORDER BY col_a
;
SELECT rowid, *
FROM foo
;
DROP TABLE foo
;
This one will run without SQLite complaining.
update:
As of SQLite version 3.25.0, window function is supported. Hence you can use row_number() over (order by x) expression in your CTE if you happen to use a newer SQLite

How to count records from multiple columns using sql and asp.net?

I have a table with 5 columns: ID, Session1, Session2, Session3, Session4. What I want to do is to display the number of same items from each column. Same item can't appear in more than one column.
ID Session1 Session2 Session3 Session4
-- -------- -------- -------- --------
1 Music Web Tech Future
2 Art Articles Search Introduction
3 Music Books Camera Phone
4 Music Glass Cup Future
5 Art Books Tech Future
6 Music Glass Cup Phone
I want to display it like this on an asp.net page.
Music: 4
Art: 2
Web: 1
Articles: 1
Books: 2
Glass: 2
Tech: 2
Search: 1
Camera: 1
Cup: 2
Future: 3
introduction: 1
Phone: 2
how would I construct a sql query and display them on asp.net?
You could simply use:
SELECT
session1,
COUNT(*)
FROM
My_Table
GROUP BY
session1
UNION ALL
SELECT
session2,
COUNT(*)
FROM
My_Table
GROUP BY
session2
...
With SQL Server you could do something like this:
SELECT Session, COUNT(*) FROM (
SELECT Session1 AS Session FROM TableName
UNION ALL
SELECT Session2 AS Session FROM TableName
UNION ALL
SELECT Session3 AS Session FROM TableName
UNION ALL
SELECT Session4 AS Session FROM TableName) T1
GROUP BY Session
It's not pretty, but it should work.
try:
Select z.Val, Count(*) ValueCount
From (Select Distinct session1 val From Table Union
Select Distinct session2 val From Table Union
Select Distinct session3 val From Table Union
Select Distinct session4 val From Table) Z
Join Table t on Z.Val In (t.Session1, t.Session2, t.Session3, t.Session4)
Group By z.Val

Resources