SQL - Count after Table Joins - sql

I'm doing a class assignment and seem to be having some trouble with one question. The question requires me two join 3 tables and count the overall number of occurrences for each row.
This is the join command I have so far (need to figure out where I can put a nested count(distinct):
SELECT litwork.btitle,
bookcopy.copy_num,
request.rdate
FROM litwork,
bookcopy,
request
WHERE litwork.lit_id = bookcopy.lit_id
AND bookcopy.persidh = request.persid
ORDER BY btitle;
The join gives me this table as result:
BTITLE COPY_NUM RDATE
--------------- -------------- -------
Bankers 2 18-oct-2012
Bankers 2 30-oct-2012
Blue Ridge 1 20-oct-2012
Linux 1 18-oct-2012
Linux 1 30-oct-2012
My Life 3 31-oct-2012
O-O Design 1 30-oct-2012
O-O Design 3 25-oct-2012
O-O Design 3 18-oct-2012
So how would I make a count(distinct) for all three column within that one command? I'm using standard SQL
Edit to add question prompt (copied and paste):
Show how many requests and how many copies exist for each book that is requested. Show title, number of requests, number of copies of the book. Show in order by title. The SQL query for this question mixes a join with count. To understand such a query, be aware that the join must be processed before the count function .
Be also aware that the join may create duplicate data, so that you should use the count(distinct ..) form of count where needed. (Suggestions: if you have trouble with this question, look at the results of the join without count and group, and figure out how you would perform the required count if these results were data of an existing table. Please do not show this extra query in your report.).
Assumption: a given customer may not have more than one request of the same book.. Note that when joining the table REQUEST with the table BOOK_COPY, the number of rows where a given book appears is the product of the number of requests for that book and of the number of copies.
UPDATE: It's still not 100% correct..
Additional Tables used for the Join (First one is LITWORK table, second one is REQUEST table, and last one is BOOKCOPY table)
LIT_ID BTITLE YEAR
---------- --------------- ----------
1001 The Trojans 2000
1002 My Life 2001
1003 Nature 1998
1004 Blue Ridge 1996
1005 True Java 2012
1006 CPlus 2004
1007 Streaming 2000
1008 MyApps 1998
1009 O-O Design 2012
1010 Camping 1978
1011 Bankers 1970
1012 Linux 1962
LIT_ID PERSID BNAME RDATE RTIME
---------- ---------- -------- ----------- ----------
1001 11 College 18-oct-2012
1001 7 College 25-oct-2012
1003 8 La Jolla 20-oct-2012
1005 7 Pacific 18-oct-2012
1008 11 Atlantic 30-oct-2012
1008 1 College 30-oct-2012
1012 4 La Jolla 31-oct-2012
LIT_ID COPY_NUM PERSID_OUT DATE_OUT DATE_DUE PERSIDH HDATE BNAMEP BNAMEC
---------- ---------- ---------- ----------- ----------- ---------- ----------- -------- --------
1001 1 4 13-sep-2012 27-nov-2012 La Jolla
1002 1 Pacific Atlantic
1002 2 1 02-sep-2012 12-oct-2012 Pacific
1002 3 4 15-nov-2012 La Jolla La Jolla
1003 1 9 10-dec-2012 30-dec-2012 Pacific
1003 2 1 13-dec-2012 22-jan-2013 La Jolla
1003 3 Atlantic Atlantic
1004 1 8 19-nov-2012 Pacific College
1004 2 4 04-dec-2012 17-feb-2013 Pacific
1004 3 10 11-oct-2012 31-oct-2012 Atlantic
1005 1 4 27-oct-2012 10-jan-2013 La Jolla
1005 2 1 19-sep-2012 29-oct-2012 Pacific
1006 1 7 29-jan-2012 09-mar-2012 Pacific
1006 2 1 07-jan-2012 16-feb-2012 College
1006 3 Pacific College
1007 1 1 26-oct-2012 05-dec-2012 Pacific
1007 2 Pacific College
1007 3 6 15-oct-2012 04-nov-2012 La Jolla
1008 1 4 23-oct-2012 06-jan-2013 College
1008 2 3 15-oct-2012 24-nov-2012 Pacific
1009 1 1 20-nov-2012 Pacific Pacific
1009 2 11 28-sep-2012 12-dec-2012 Pacific
1009 3 7 22-nov-2012 La Jolla College
1010 1 1 01-sep-2012 11-oct-2012 Pacific
1011 1 4 31-jan-2012 15-apr-2012 La Jolla
1011 2 11 20-nov-2012 College La Jolla
1012 1 11 19-nov-2012 Pacific Atlantic
1012 2 3 29-oct-2012 08-dec-2012 Pacific
This is my current SQL command (not the one I got from Gordon Linoff's comment--that one gave me 2-3 extra rows)
select litwork.btitle,
count(distinct bookcopy.copy_num),
count(distinct request.rdate)
from litwork,
bookcopy,
request
where litwork.lit_id=request.lit_id and
bookcopy.persidh=request.persid
group by btitle;
And that gives me this table (which you can see I have all the correct amount of rows [when you take out the duplicates] but the count numbers are wrong)
BTITLE COUNT(DISTINCTBOOKCOPY.COPY_NUM) COUNT(DISTINCTREQUEST.RDATE)
--------------- -------------------------------- ----------------------------
Linux 1 1
MyApps 2 1
Nature 1 1
The Trojans 3 2
True Java 1 1

The following should work with Oracle's SQL *Plus:
select litwork.btitle, count(distinct bookcopy.copy_num), count(distinct request.rdate)
from litwork, bookcopy, request
where litwork.lit_id = request.lit_id and request.lit_id = bookcopy.lit_id(+)
group by litwork.btitle;
For more info on joins see Oracle SQL*Plus Pocket Reference, 2nd Edition.
Possible solutions to count issue:
Change count(distinct request.rdate) to count(distinct request.PERSID).
Change count(distinct request.rdate) to count(distinct request.*).
Change count(distinct request.rdate) to sum(case when request.rdate is null then 0 else 1 end)
Instead of joining the request table you could join (select lit_id, count(*) as requestCount from request group by lit_id) then select requestCount.
This is probably the best I can do since I do not have the detailed definition of the fields and how they relate. It would also help if I had the expected results and SQL *Plus to test it with.

Related

SQL query to select specific fields, process sum and count from two tables

i have these two tables
ORDERS
id order_id e_id e_name
1 1000 1001 Tom
2 1009 1001 Tom
3 1010 1001 Tom
4 1011 1002 Parker
5 1012 1002 Parker
6 1013 1003 Rohan
Transactions
id order_id amount status
1 1000 100 success
2 1009 80 success
3 1010 100 failed
4 1011 50 success
6 1012 50 success
7 1013 100 failed
i would like to join two tables, select fields, process sum count and filter like this
e_id e_name amount_sum total_counts total_success_amount success_count
1001 Tom 280 3 180 2
1002 Parker 100 2 100 2
1003 Rohan 100 1 0 0
this is what i tried
use card;
SELECT COUNT(orders.order_id) as `total_counts`,
COUNT(CASE WHEN transactions.status = 'success' THEN 1 END) as `success_count`,
SUM(0 + transactions.amount) as `amount_sum`, orders.e_id,
orders.e_name
FROM orders
LEFT JOIN transactions
ON transactions.order_id=orders.order_id
GROUP BY (orders.e_id), (orders.order_id),
(orders.e_name), (transactions.amount), (transactions.status);
i tried many queries also not able to achieve it. Suggest me query to get my operation.

Crosstab query to get results of three tables based on results table

This request might be asked many times but I have done a search last night to figure out but I came up with nothing.
I have three tables
Table A
ID
City
1
LA
2
NY
3
LV
Table B
ID
Job
11
Programmer
22
Engineer
33
Database Administrator
44
Cyber Security Analyst
Table C
ID
Job level
111
Junior
222
Associate
333
Senior
444
Director
Final table
ID
EmployeeName
City_ID
Job_ID
Level_ID
1000
Susie
1
11
333
1001
Nora
2
11
222
1002
Jackie
2
22
111
1003
Mackey
1
11
444
1004
Noah
1
11
111
I’d like to have a crosstab query using Microsoft Access that returns the following result ( based on city )
LA Table
Jobs
Junior
Associate
Senior
Director
Programmer
1
-
1
1
Engineer
-
-
-
-
Database Administrator
-
-
-
-
Cyber Security Analyst
-
-
-
-
How can I do it?
The best approach for this is always:
Create a "base" query that joins the base tables and returns all data columns that you will need for the crosstab query.
Run the crosstab query wizard using the "base" query as input.

Selecting from a table that contains ALL of another table

Let's say I have three tables:
Employees:
PID NAME WAGE
---------- -------------------- ----------
10234 Able 8
11567 Baker 9
3289 George 10
88331 Alice 11
Employee_made:
PID SID QUANTITY HOURS
---------- ---------- ---------- ----------
10234 11 24 3
10234 12 6 1
10234 13 24 1
10234 21 6 1
10234 23 4 1
10234 31 48 6
11567 23 4 1
11567 31 1 1
88331 11 6 1
Sandwich:
SID PRICE NAME
---------- ---------- ------------------------------
12 2 hamburger on wheat
13 2 cheese burger
21 1.75 fish burger on rye
23 1.75 fish burger on wheat
31 3 veggie burger on wheat
11 2 hamburger on rye
I need to list all the employees who have made ALL the different sandwiches, and display their names and PID. What I've gotten so far is:
Select E.name, E.pid
From employees E, employee_made EM, sandwich S
Where E.pid = EM.pid
Which tells me the matching PIDs from the employees and employee_made table. Where I'm not sure to go is how to display the employees who have made ALL the sandwiches, so matching not any SID to the employee_made table, but ALL of them.
First, never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You can approach this by counting the number of sandwiches mades by employees and then comparing to the total count of sandwiches:
select em.pid
from employee_made em
group by em.pid
having count(distinct em.sid) = (select count(*) from sandwich);
This gives the pid of the employee. I'll let you figure out how to bring in the employee name (hint: in, exists, and join could all be used).

3 Tables, JOIN query and alphabetic order

I am currently working with three tables where I am trying to figure out how to use a join to display once the title_id of any book with Dennis McCann as an editor. The tables have in common title_id and editor_id. Cant find a way to piece it all together. How to display once the title_id of any book with Dennis McCann as an editor?
SELECT * FROM title_editors;
EDITOR_ID TITLE_ EDITOR_ORDER
----------- ------ ------------
826-11-9034 Bu2075 2
826-11-9034 PS2091 2
826-11-9034 Ps2106 2
826-11-9034 PS3333 2
826-11-9034 PS7777 2
826-11-9034 pS1372 2
885-23-9140 MC2222 2
885-23-9140 MC3021 2
885-23-9140 Tc3281 2
885-23-9140 TC4203 2
885-23-9140 TC7777 2
321-55-8906 bU1032 2
321-55-8906 BU1111 2
321-55-8906 BU7832 2
321-55-8906 PC1035 2
321-55-8906 PC8888 2
321-55-8906 BU2075 3
777-02-9831 pc1035 3
777-02-9831 PC8888 3
943-88-7920 BU1032 1
943-88-7920 bu1111 1
943-88-7920 BU2075 1
943-88-7920 BU7832 1
943-88-7920 PC1035 1
943-88-7920 pc8888 1
993-86-0420 PS1372 1
993-86-0420 PS2091 1
993-86-0420 PS2106 1
993-86-0420 PS3333 1
993-86-0420 pS7777 1
993-86-0420 MC2222 1
993-86-0420 MC3021 1
993-86-0420 Tc3218 1
993-86-0420 TC4203 1
993-86-0420 TC7777 1
35 rows selected.
SQL> SELECT * FROM title_authors;
AUTHOR_ID TITLE_ AUTHOR_ORDER ROYALTY_SHARE
----------- ------ ------------ -------------
409-56-7008 Bu1032 1 .6
486-29-1786 PS7777 1 1
486-29-1786 pC9999 1 1
712-45-1867 MC2222 1 1
172-32-1176 Ps3333 1 1
213-46-8915 BU1032 2 .4
238-95-7766 PC1035 1 1
213-46-8915 Bu2075 1 1
998-72-3567 pS2091 1 .5
899-46-2035 PS2091 2 .5
998-72-3567 PS2106 1 1
722-51-5454 mc3021 1 .75
899-46-2035 MC3021 2 .25
807-91-6654 tC3218 1 1
274-80-9391 BU7832 1 1
427-17-2319 pC8888 1 .5
846-92-7186 PC8888 2 .5
756-30-7391 PS1372 1 .75
724-80-9391 PS1372 2 .25
724-80-9391 bu1111 1 .6
267-41-2394 bU1111 2 .4
672-71-3249 TC7777 1 .4
267-41-2394 TC7777 2 .3
472-27-2349 Tc7777 3 .3
648-92-1872 TC4203 1 1
25 rows selected.
SQL> SELECT * FROM editors;
EDITOR_ID EDITOR_LNAME EDITOR_FNAME EDITOR_POSITION PHONE ADDRESS CITY ST ZIP
----------- ----------------- ------------- --------------- ------------ -------------------- ------------ -- ------
321-55-8906 DeLongue Martinella Project 415 843-2222 3000 6th St. BERKELEY Ca 94710
723-48-9010 Sparks MANfred cOPY 303 721-3388 15 Sail DENVER Co 80237
777-02-9831 Samuelson Bernard proJect 415 843-6990 27 Yosemite OAKLAND Ca 94609
777-66-9902 Almond Alfred copy 312 699-4177 1010 E. DeVON CHICAGO Il 60018
826-11-9034 Himmel Eleanore pRoject 617 423-0552 97 Bleaker BOSTON Ma 02210
885-23-9140 Rutherford-Hayes Hannah PROJECT 301 468-3909 32 Rockbill Pike ROCKBILL MD 20852
993-86-0420 McCann Dennis acQuisition 301 468-3909 32 Rockbill Pike ROCKBill MD 20852
943-88-7920 Kaspchek Christof acquisitiOn 415 549-3909 18 Severe Rd. BERKELEY CA 94710
234-88-9720 Hunter Amanda acquisition 617 432-5586 18 Dowdy Ln. BOSTON MA 02210
You can try join on the table Editors and Ttile_Editors using the Editor_ID that will give you the matching records and you can filter out Only for the ' Dennis McCann ' using either multiple conditions in join or the where clause as,
WITHOUT WHERE
SELECT DISTINCT te.title_id,ed.EDITOR_ID,ed.EDITOR_LNAME,ed.EDITOR_FNAME
FROM
title_editors te JOIN editors ed
ON te.EDITOR_ID = ed.EDITOR_ID
AND ed.EDITOR_LNAME = 'McCann'
AND ed.EDITOR_FNAME = 'Dennis'
ORDER BY te.title_id
USing WHERE
SELECT DISTINCT te.title_id,ed.EDITOR_ID,ed.EDITOR_LNAME,ed.EDITOR_FNAME
FROM
title_editors te JOIN editors ed
ON te.EDITOR_ID = ed.EDITOR_ID
WHERE
ed.EDITOR_LNAME = 'McCann'
AND ed.EDITOR_FNAME = 'Dennis'
ORDER BY te.title_id
It would be easier with the in operator:
SELECT DISTINCT title_id
FROM title_editors
WHERE editor_id IN (SELECT editor_id
FROM editors
WHERE editor_fname = 'Dennis' AND
editor_lname = 'McCann')
ORDER BY title_id ASC

Joining two tables in Oracle sql

I have 2 tables. One of the tables have 7 values and the other table has 5 values. These tables have their primary keys in common. I want to join both tables this way:
If I have a Table
English French
-------------------- --------------------
one Un
two Deux
three Trois
four Quatre
four Quattro
five Cinq
five Cinco
And another one:
English French
-------------------- --------------------
one aaaaa
two bbbbb
three ccccc
four
five
I want to have a table like this:
English French
-------------------- --------------------
one Un
one aaaaa
two Deux
two bbbb
three Trois
three ccccc
four Quatre
four Quattro
four --------
five Cinq
five Cinco
five ----------
I tried using join but it does a linear combination of the values four and five. How can I go about doing this? Thanks.
Edit: SQL query:
SELECT l.date_location, l.duree, r.km_restitution, r.km_parcouru
FROM locations l, restitutions r
UNION
SELECT l.num_client, l.date_location, l.duree, r.km_restitution, r.km_parcouru
FROM locations l, restitutions r
id_agence num_immatriculation num_client km_restitution km_parcouru state date_restitution
1 406BON69 1002 30000 1000 BON 29-MAY-10
3 785CIM13 1001 56580 80 BON 09-AUG-08
5 800BBB75 1000 2020 20 BON 24-APR-11
4 307VXN78 1000 20040 40 BON 28-JAN-11
2 290UTT92 1004 30030 30 BON 01-AUG-10
5 777SET13 1005 4030 30 BON 26-APR-11
2 179CLV92 1004 15015 15 BON 03-FEB-11
5 400AAA75 1003 1020 20 BON 18-SEP-11
5 666NEF69 1004 3040 40 BON 15-APR-11
2 111AAA75 1001 20020 20 BON 21-DEC-09
1 333CCC78 1001 43250 40 BON 27-DEC-09
2 260CDE95 1003 79000 430 BON 10-SEP-09
4 307VXN78 1003 20090 90 BON 11-FEB-11
1 123ABC78 1003 10010 10 BON 04-OCT-10
1 222BBB77 1001 9050 50 BON 23-DEC-09
Locations
id_agence num_immatricul num_client duree date_location
2 406BON69 1002 20 10-MAY-10
3 785CIM13 1001 3 07-AUG-08
5 800BBB75 1000 7 18-APR-11
4 307VXN78 1000 5 24-JAN-11
1 290UTT92 1004 1 31-JUL-10
5 777SET13 1005 4 23-APR-11
1 179CLV92 1004 5 30-JAN-11
5 400AAA75 1003 2 17-SEP-11
2 123ABC78 1003 4 01-OCT-10
5 666NEF69 1004 5 11-APR-11
1 111AAA75 1001 2 20-DEC-09
1 222BBB77 1001 2 22-DEC-09
1 333CCC78 1001 3 25-DEC-09
1 260CDE95 1003 10 01-SEP-09
4 307VXN78 1003 13 30-JAN-11
2 123ABC78 1003 8 20-NOV-11
2 406BON69 1002 10 20-NOV-11
Desired Result
id_agence num_immatricul num_client duree date_location date_restitution
2 406BON69 1002 20 10-MAY-10 date_restitution
3 785CIM13 1001 3 07-AUG-08 date_restitution
5 800BBB75 1000 7 18-APR-11 date_restitution
4 307VXN78 1000 5 24-JAN-11 date_restitution
1 290UTT92 1004 1 31-JUL-10 date_restitution
5 777SET13 1005 4 23-APR-11 date_restitution
1 179CLV92 1004 5 30-JAN-11 date_restitution
5 400AAA75 1003 2 17-SEP-11 date_restitution
2 123ABC78 1003 4 01-OCT-10 date_restitution
5 666NEF69 1004 5 11-APR-11 date_restitution
1 111AAA75 1001 2 20-DEC-09 date_restitution
1 222BBB77 1001 2 22-DEC-09 date_restitution
1 333CCC78 1001 3 25-DEC-09 date_restitution
1 260CDE95 1003 10 01-SEP-09 date_restitution
4 307VXN78 1003 13 30-JAN-11 date_restitution
2 123ABC78 1003 8 20-NOV-11 ----------------
2 406BON69 1002 10 20-NOV-11 ---------------
Apart from the column name, where i put date_restitution contains real dates.
You could use a UNION:
select English, French from Table1
UNION ALL
select English, French from Table2
or a full outer join
select distinct coalesce(T1.English, T2.English), coalesce(T1.French, T2.French)
from Table1 T1
full outer join Table2 T2 on T1.English = T2.English
EDIT:
Assuming you want restitutions.date_restitution to appear in place of date_location for restitution records -
SELECT l.num_client, l.date_location, l.duree, to_number(null) km_restitution, to_number(null) km_parcouru
FROM locations l
UNION ALL
SELECT r.num_client, r.date_restitution date_location, 0 duree, r.km_restitution, r.km_parcouru
FROM restitutions r
FURTHER EDIT (based on supplied results):
select l.id_agence,
l.num_immatricul,
l.num_client,
l.duree,
l.date_location,
decode(r.date_restitution, NULL,'----------------', 'date_restitution')
as date_restitution -- or just r.date_restitution
from location l
left outer join restitution r
on l.id_agence = r.id_agence and
l.num_immatricul = r.num_immatricul and
l.num_client = r.num_client and
l.date_location <= r.date_restitution
You actually need a union:
SELECT English, French FROM T1
UNION
SELECT English, French FROM T2
If you don't care about duplicates, you can use UNION ALL
Edit after OP's comment:
SELECT l.num_client, l.id_agence, l.num_immatricul
FROM locations l
UNION
SELECT r.num_client, r.id_agence, r.num_immatriculation
FROM restitutions r
The following should do it.
SELECT tab1.English, tab1.French
UNION
SELECT tab2.English, tab2.French
For other readers who might have the same problem. From the experience I had with this problem, it would be a good idea to join tables locations and restitutions since both of them have almost the same attributes and data. I finally decided in changing my database and creating a new table that contains both the attributes of location and restitution and setting some not availabe values to NULL. This would reduce a lot of joins between tables and queries would be easier to handle.