SQL Query involving joins - sql

For an SQL assessment I have to carry out a query where I need to list the Car Sales in the past month ordered by Salesman Code.
I have created an SQL statement. However, when I run it, it lists nothing at all except the column names that I have included within the query. The SQL code I have used is below:
SELECT CarForSale.SalesmanCode,
Salesman.SalesmanName,
Customer.CustomerCode,
Customer.CustomerName,
Customer.CustomerAddress
FROM
(
Centre
INNER JOIN Customer
ON Centre.CentreCode = Customer.CentreCode
)
INNER JOIN CarForSale
ON (Customer.CustomerCode = CarForSale.CustomerCode)
AND (Centre.CentreCode = CarForSale.CentreCode), Salesman
WHERE CarForSale.CFSSoldDate BETWEEN CVDATE('01/02/2013') AND CVDATE('01/03/2013')
ORDER BY Salesman.SalesmanCode;
If anyone has any feedback or knows where I am going wrong I would much appreciate some assistance with this problem.
Here is some sample data as requested:
CFS Table
CFSCode CFSMake CFSModel CFSSellingPrice
000001 Mercedes W168 45000
CFSSoldDate CentreCode SalesmanCode CustomerCode
01/03/2013 00000001 0000000001 00000001
Salesman Table
SalesmanCode SalesmanName SalemanCommThisYear SalesmanStatus CentreCode
0000000001 Liam Jones 2250 senior 00000001
customer table
CustomerCode CustomerName CustomerAddress CentreCode CustomerStatus
00000001 Gina Smith 1, The Lake, 00000002 good
Merthyr Tydfil

In your current query, you have some unusual syntax:
AND (Centre.CentreCode = CarForSale.CentreCode), Salesman -- what's this
I am not sure what the , Salesman is supposed to be doing. But if you are trying to JOIN on the Salesman table, then your query will be:
SELECT CarForSale.SalesmanCode,
Salesman.SalesmanName,
Customer.CustomerCode,
Customer.CustomerName,
Customer.CustomerAddress
FROM ((Centre
INNER JOIN Customer
ON Centre.CentreCode = Customer.CentreCode)
INNER JOIN CarForSale
ON (Customer.CustomerCode = CarForSale.CustomerCode)
AND (Centre.CentreCode = CarForSale.CentreCode)))
INNER JOIN Salesman
ON CarForSale.SalesmanCode = Salesman.SalesmanCode
WHERE CarForSale.CFSSoldDate BETWEEN #01/02/2013# AND #01/03/2013#
ORDER BY Salesman.SalesmanCode;
Also in MS Access, when using dates, they should be surrounded by pound sigs #. Your query should be:
SELECT CarForSale.SalesmanCode,
Salesman.SalesmanName,
Customer.CustomerCode,
Customer.CustomerName,
Customer.CustomerAddress
FROM ((Centre
INNER JOIN Customer
ON Centre.CentreCode = Customer.CentreCode)
INNER JOIN CarForSale
ON (Customer.CustomerCode = CarForSale.CustomerCode)
AND (Centre.CentreCode = CarForSale.CentreCode)))
INNER JOIN Salesman
ON CarForSale.SalesmanCode = Salesman.SalesmanCode
WHERE CarForSale.CFSSoldDate BETWEEN #01/02/2013# AND #01/03/2013#
ORDER BY Salesman.SalesmanCode;
Edit #1, I am not sure why you are joining on the Centre table since you are not using it for anything. I just ran the following query in MS Access using your sample data and got results:
SELECT CarForSale.SalesmanCode,
Salesman.SalesmanName,
Customer.CustomerCode,
Customer.CustomerName,
Customer.CustomerAddress
FROM (Customer
INNER JOIN CarForSale
ON Customer.CustomerCode = CarForSale.CustomerCode)
INNER JOIN Salesman
ON CarForSale.SalesmanCode = Salesman.SalesmanCode
WHERE CarForSale.CFSSoldDate BETWEEN #01/02/2013# AND #01/03/2013#
ORDER BY Salesman.SalesmanCode;

Related

Having trouble creating join looking for specific data

I am using Oracle SQL (TeraTerm),
and
I am trying to join specific information from two tables CONSULTANT, and PROJECT_CONSULTANT, and I need to retrieve only the employees who worked over 40 hours. Here are the tables
Project Consultant
PROJECT_ID CONSULTANT_ID NUMBER_HOURS
--------------- --------------- ------------
94738949 49620928 6
45699847 34879223 57
45699847 95928792 44
45699847 04875034 59
19870398 49620928 32
30495394 95928792 57
30495394 07811473 50
62388923 07811473 82
and Consultant
CONSULTA NAME ZIP START_DT
-------- -------------------------------- ----- ---------
CON_TITLE
-------------------------
49620928 Tom Jones 39875 01-SEP-98
Junior Consultant
04875034 Jack Johnson 29087 05-OCT-93
Manager
34879223 Lanny Harris 03944 30-APR-04
Principal
CONSULTA NAME ZIP START_DT
-------- -------------------------------- ----- ---------
CON_TITLE
-------------------------
95928792 Michael Johnson 02953 22-JUN-02
Senior Manager
07811473 Wendy Adams 29087 05-JUL-05
Senior Consultant
The code I came up with is
select Consultant_ID, Name, Zip, and Number_Hours
from Consultant
Inner Join project_consultant
ON Consultant.Consultant_ID=project_consultant.Consultant_ID
WHERE project_consultant.number_Hours>40;
I am getting an error
ERROR at line 1:
ORA-00936: missing expression
I just wanna know how to write the join statement correctly any help would be awesome, because I am having trouble knowing how to fix this join statement
You don't use and in the select clause:
select c.Consultant_ID, c.Name, c.Zip, pc.Number_Hours
from Consultant c Inner Join
project_consultant pc
on c.Consultant_ID = pc.Consultant_ID
where pc.number_Hours > 40;
You also need a table alias in the select clause to be clear what table Consultant_Id refers to.
EDIT:
You might actually want to sum the hours for employees. If so, you need an aggregation:
select c.Consultant_ID, c.Name, c.Zip, sum(pc.Number_Hours)
from Consultant c Inner Join
project_consultant pc
on c.Consultant_ID = pc.Consultant_ID
group by c.Consultant_ID, c.Name, c.Zip
having sum(pc.number_Hours) > 40;
You can't use and in Select Clause
Try this
SELECT C.Consultant_ID, C.Name, C.ip, PC.Number_Hours
FROM Consultant C
INNER Join project_consultant PC
ON C.Consultant_ID=PC.Consultant_ID
WHERE PC.number_Hours > 40;
select c.Consultant_ID, c.Name, c.Zip, p.Number_Hours
from Consultant c
Inner Join project_consultant p
ON c.Consultant_ID=p.Consultant_ID
WHERE p.number_Hours>40;

Sql query with multiple condition but some of item is not available in certain table

I am facing problem with sql query when I try to join this tree table and get the data. I am using Oracle database.
Personal
id_no name
-------------
0001 John
0002 Peter
0003 Mike
position
id_no name
-------------
0001 programmer
0002 Engineer
0003 Clerk
extra_skill
employee_id skill
--------------------------
0001 Visual Studio 2008
0003 Crystal Report
Requirement:
Display details of employees:
Example:
Employee No : 0001
Employee Name : John
Employee Position : Programmer
Employee Skill : Visual Studio 2008
My sql statement is
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "USER INPUT";
The problem is when
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "0002";
This query give me NULL because in the table extra_skill does not have 0002.
I want it possible to get data even in the third table no value.
Expected result:
Employee No : 0002
Employee Name : Peter
Employee Position : Engineer
Employee Skill :
How can I implement such a query?
Your attentions and helps are much appreciated.
Thank you, Siti..:)
The way to do this is with outer joins. I have used the ANSI joining syntax (introduced in Oracle 9i) for this example, because it is clearer and also Oracle now recommend using it.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id )
WHERE a.id_no = '0002';
Note that I have changed the filter condition to select on PERSONAL.ID. If you attempt to use c.employee_id = '0002' (as you do in your question) you will get no rows returned.
You could include EXTRA_SKILLS.EMPLOYEE_ID in the join condition rather than the WHERE clause.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id
and c.employee_id = '0002');
Generally including filters in the join section is not considered good practice, because it can effect the result set in ways we're not expecting. In your case it will return every row in PERSONAL and POSITION and no values from EXTRA_SKILL. This is probably not what you want to happen. Here is a SQL Fiddle to prove it.
You will have to use an outer join.
The purpose of an outer join is to include non-matching rows, and the outer join returns these missing columns as NULL values.
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id(+) = "USER INPUT";

Query Returning SUM of Quantity or 0 if no Quantity for a Product at a given date

I have the following 4 tables:
----------
tblDates:
DateID
30/04/2012
01/05/2012
02/05/2012
03/05/2012
----------
tblGroups:
GroupID
Home
Table
----------
tblProducts:
ProductID GroupID
Chair Home
Fork Table
Knife Table
Sofa Home
----------
tblInventory:
DateID ProductID Quantity
01/05/2012 Chair 2
01/05/2012 Sofa 1
01/05/2012 Fork 10
01/05/2012 Knife 10
02/05/2012 Sofa 1
02/05/2012 Chair 3
03/05/2012 Sofa 2
03/05/2012 Chair 3
I am trying to write a query that returns all Dates in tblDates, all GroupIDs in tblGroups and the total Quantity of items in each GroupID.
I manage to do this but only get Sum(Quantity) for GroupID and DateID that are not null. I would like to get 0 instead. For exemple for the data above, I would like to get a line "02/05/2012 Table 0" as there is no data for any product in "Table" group on 01/05/12.
The SQL query I have so far is:
SELECT tblDates.DateID,
tblProducts.GroupID,
Sum(tblInventory.Quantity) AS SumOfQuantity
FROM (tblGroup
INNER JOIN tblProducts ON tblGroup.GroupID = tblProducts.GroupID)
INNER JOIN (tblDates INNER JOIN tblInventory ON tblDates.DateID = tblInventory.DateID) ON tblProducts.ProductID = tblInventory.ProductID
GROUP BY tblDates.DateID, tblProducts.GroupID;
I reckon I should basically have the same Query on a table different from tblInventory that would list all Products instead of listed products with 0 instead of no line but I am hesitant to do so as given the number of Dates and Products in my database, the query might be too slow.
There is probably a better way to achieve this.
Thanks
To get all possible Groups and Dates combinations, you'll have to CROSS JOIN those tables. Then you can LEFT JOIN to the other 2 tables:
SELECT
g.GroupID
, d.DateID
, COALESCE(SUM(i.Quantity), 0) AS Quantity
FROM
tblDates AS d
CROSS JOIN
tblGroups AS g
LEFT JOIN
tblProducts AS p
JOIN
tblInventory AS i
ON i.ProductID = p.ProductID
ON p.GroupID = g.GroupID
AND i.DateID = d.DateID
GROUP BY
g.GroupID
, d.DateID
use the isnull() function. change your query to:
SELECT tblDates.DateID, tblProducts.GroupID,
**ISNULL( Sum(tblInventory.Quantity),0)** AS SumOfQuantity
FROM (tblGroup INNER JOIN tblProducts ON tblGroup.GroupID = tblProducts.GroupID)
INNER JOIN (tblDates INNER JOIN tblInventory ON tblDates.DateID = tblInventory.DateID)
ON tblProducts.ProductID = tblInventory.ProductID
GROUP BY tblDates.DateID, tblProducts.GroupID;
You don't say which database you're using but what I'm familiar with is Oracle.
Obviously, if you inner join all tbales, you will not get the rows containing nulls. If you use an outer join to the inventory table you also have a problem because the groupid column is not listed in tblinventory and you can only outer join to one table.
I'd say you have two choices. Use a function or have a duplicate of the groupid column in the inventory table.
So, a nicer but slower solution:
create or replace
function totalquantity( d date, g varchar2 ) return number as
result number;
begin
select nvl(sum(quantity), 0 )
into result
from tblinventory i, tblproducts p
where i.productid = p.productid
and i.dateid = d
and p.groupid = g;
return result;
end;
select dateid, groupid, totalquantity( dateid, groupid )
from tbldates, tblgroups
Or, if you include the groupid column in the inventory table. (You can still quarantee integrity using constraints)
select d.dateid, i.groupid, nvl(i.quantity, 0)
from tbldates d, tblinventory i
where i.dateid(+) = d.dateid
group by d.dateid, g.groupid
Hope this helps,
GĂ­sli

SQL Syntax Issue with getting sum

Ok I have two tables.
Table IDAssoc has the columnsbill_id, year, area_id.
Table Bill has the columns bill_id, year, main_id, and amount_due.
I'm trying to get the sum of the amount_due column from the bill table for each of the associated area_ids in the IDAssoc table.
I'm doing a select statement to select the sum and joining on the bill_ids. How can I set this up so it will have a single row for each of the associated bills in each area_id from the assoc table. There may be three or four bill_ids associated with each area_id and I need those summed for each and returned so I can use this select in another statement. I have a group by set up for the area_id but it still is returning each row and not summing them up for each area_id. I have the year and main_id specified already in the where clause to return the data that I want, but I can't get the sum to work properly. Sorry I'm still learning and I'm not sure how to do this. Thanks!
Edit- Basically the query I'm trying so far is basically just like the one posted below:
select a.area_id, sum(b.amount_due)
from IDAssoc a
inner join Bill b
on a.bill_id = b.bill_id
where Bill.year = 2006 and bill.bill_id = 11111
These are just arbitrary numbers.
The data this is returning is like this:
amount_due - area_id
.05 1003
.15 1003
.11 1003
65 1004
55 1004
I need one row returned for each area_id with the amount_due summed. The area_id is only in the assoc table and not in the bill table.
select a.area_id, sum(b.amount_due)
from IDAssoc a
inner join Bill b
on a.bill_id = b.bill_id
where b.year = 2006 and b.bill_id = 11111
group by a.area_id
You might want to change inner join to left join if one IDAssoc can have many or no Bill:
select a.area_id, coalesce(sum(b.amount_due),0)
from IDAssoc a
left join Bill b
on a.bill_id = b.bill_id
where b.year = 2006 and b.bill_id = 11111
group by a.area_id
You are missing the GROUP BY clause:
SELECT a.area_id, SUM(b.amount_due) TotalAmount
FROM IDAssoc a
LEFT JOIN Bill b
ON a.bill_id = b.bill_id
GROUP BY a.area_id

Suggest optimized query using 4 tables ( RIGHT JOIN v/s INNER JOIN & HAVING )

I have following table structure
table_country ==> country_id (PK) | country | status
table_department ==> department_id (PK) | department | country_id (FK)
table_province ==> province_id (PK) | province | department_id (FK)
table_district ==> district_id (PK) | district | province_id (FK)
NOTE: all tables engine are innoDB
One country can have multiple department, one department can have multiple province and one province can have multiple district. Now I need to search only those country which have at least one district
I have written the below 2 SQL queries, in my case, both queries return the same results.... please describe the difference between those queries
Using a RIGHT JOIN:
SELECT c.country_id as id, c.country as name
FROM table_country c
RIGHT JOIN table_department d ON d.country_id=c.country_id
RIGHT JOIN table_province p ON p.department_id=d.department_id
RIGHT JOIN table_district ds ON ds.province_id=p.province_id
WHERE c.status='Active' GROUP BY (c.country_id)
Using INNER JOIN and HAVING clause:
SELECT COUNT(ds.district), c.country_id as id, c.country as name
FROM table_country c
INNER JOIN table_department d ON d.country_id = c.country_id
INNER JOIN table_province p ON p.department_id = d.department_id
INNER JOIN table_district ds ON ds.province_id = p.province_id
WHERE c.status='Active'
GROUP BY (c.country_id)
HAVING COUNT(ds.district)>0
Please tell me where these both query make the difference in results and which one I have to use or do I have to use a different query?
Thanks in advance
I would suggest using the second of your 2 queries (with inner joins), but without the HAVING clause as it isn't required because the inner joins require that any row in the final result MUST have a row in the district table.
The first of your queries, using a more exotic series of RIGHT OUTER JOINS, ultimately produces the same outcome - but because they are outer joins it is potentially less efficient. Another way of representing your first query would be to reverse the table sequence like this:
SELECT
c.country_id AS id
, c.country AS name
, COUNT(ds.district)
FROM table_district ds
INNER JOIN table_province p ON ds.province_id = p.province_id
INNER JOIN table_department d ON p.department_id = d.department_id
INNER JOIN table_country c ON d.country_id = c.country_id
WHERE c.status='Active'
GROUP BY
c.country_id
, c.country
and hopefully when inverted like that it is clear that no result row can exist unless there is a row from the district table.