SQL Server query issue - ambiguous column - sql

I have four tables :
Applicant (aid, aname)
entrance_test (Etid, etname)
etest_centre (etcid, location)
etest_details (aid, etid, etcid, etest_dt)
I want to select the number of applicants who have appeared for each test, test center wise.
This is my current query:
select
location, etname, count(Aid) as number of applicants
from
applicant as a
inner join
etest_details as d on a.aid = d.aid
inner join
Entrance_Test as t on t.Etid = d.Etid
inner join
Etest_Centre as c on c.Etcid = d.Etcid
group by
Location, Etname
This is the error I am getting :
Ambiguous column name 'Aid'

You have the column aid in multiple tables, and it doesn't know which to pick from. You should specify which table it is from using the aliases you defined.
In this case, since a.Aid is the same as d.Aid (due to the JOIN), I'm using the a alias, but do keep in mind if location and etname also appear in multiple tables, you need to specify which table it should pick from.
Select c.location, t.etname, Count(a.Aid)
From Applicant As a
Inner Join etest_details As d On a.aid = d.aid
Inner Join Entrance_Test As t On t.Etid = d.Etid
Inner Join Etest_Centre As c On c.Etcid = d.Etcid
Group By c.Location, t.Etname
As a rule of thumb, when you have multiple sources in one query, you should always be explicit about which table it should come from. Even if you're sure it only exists in one of them, it's a good habit to get into to avoid issues like this in the future.

You need to mention the alias in the COUNT clause. Since you are using aliases, it would be better if you use them in the SELECT and GROUP BY sections as well. In this case, it should be :
SELECT a.location,
a.etname,
COUNT(d.Aid)
FROM applicant AS a
INNER JOIN etest_details AS d ON a.aid = d.aid
INNER JOIN Entrance_Test AS t ON t.Etid = d.Etid
INNER JOIN Etest_Centre AS c ON c.Etcid = d.Etcid
GROUP BY a.Location,
a.Etname

Related

Best Way to join 1 to many tables

I have two tables. First one is name of all members and second is all projects and its team members of different roles.
Table 1 : [members] id, name
Table 2 : [projects] id, proj_name, sponsor (fk1_tbl_1), proj_mgr(fk2_tbl_1) , proj_co (fk3_tbl_1)
I created a query to show the project name and names of all project roles.
I am doing three joins with two sub-queries in order to achieve this.
I want to know if there is better ways to do this (in pure sql, NOT script languages like pl/sql).
select f.proj_name, f.proj_sponsor, f.proj_mgr, e.name proj_co
from
name e,
(
select
d.proj_name, d.proj_sponsor, c.name proj_mgr, d.proj_co
from
members c,
(
select
b.proj_name, a.name proj_sponsor, b.proj_mgr mgr, b.proj_co co
from
members a, projects b
where
b.sponsor = a.id
) d
where
c.id = d.mgr
) f
where
e.id = f.proj_co
Use join and join again:
select p.*, ms.name as sponsor, mm.name as manager, mc.name as co_name
from projects p left join
members ms
on p.sponsor = ms.id left join
members mm
on p.manager = mm.id left join
members mo
on p.proj_co = mo.id;
Notes:
This uses left join in case any values are missing. The project will still be returned.
Never use commas in the FROM clause.
Always use proper, explicit, standard JOIN syntax.
Use meaningful table aliases, rather than arbitrary letters.

How to perform an INNER JOIN on columns with the same name

I am essentially swapping out the contents of column "LocationId" in the User table with the contents of column "LocationId" in table ChaplainLocation.
I tried a few INNER JOIN statements but have run into issues when it comes to differentiating between the two columns. I also tried setting aliases to no avail.
SELECT a.LocationID FROM [User] AS table1a,
a.ChaplainId,
a.FullName,
b.LocationId FROM [ChaplainLocation] AS table2b,
b.ChaplainId
FROM table1 a
INNER JOIN table2 b
ON a.LocationId = b.LocationId'''
I know the above SQL is messy, but I am new to INNER JOIN. I need the LocationId from table ChaplainLocation to replace LocationId in the User table.
Your current syntax is slightly off. Table aliases belong next to table names, and those appear in the FROM and JOIN clauses.
SELECT
a.LocationID AS LocationID_a,
a.ChaplainId AS ChaplainId_a,
a.FullName,
b.LocationId AS LocationId_b,
b.ChaplainId AS ChaplainId_b
FROM [User] AS a
INNER JOIN [ChaplainLocation] AS b
ON a.LocationId = b.LocationId;
Note that there is nothing wrong with referring to more than one column bearing the same name, so long as you qualify that column reference with a table alias (or full table name) to distinguish it.

How can i apply left outer join conditions on four tables?

i was trying to apply joins on 4 tables. but i could not find proper result for that.
i have 4 tables like 1.students,2.college,3.locations,4.departments. so i have same column sid in all tables which can be used to join conditions.
i want all matched rows from four tables as mentioned columns in select statement below and unmatched rows in left table which is left outer join work.
i have tried this syntax.
select
students.sname,
college.cname,
locations.loc,
department.dept
from students, college, locaions, departments
where student.sid=college.sid(+)
and college.sid=locations.sid(+)
and locations.sid=department.sid(+);
is this right ?
This is an old-fashioned way of outer-joining in an Oracle database. For Oracle this statement is correct; in other DBMS it is invalid.
Anyway, nowadays (as of Oracle 9i; in other DBMS much longer) you should use standard SQL joins instead.
select
s.sname,
c.cname,
l.loc,
d.dept
from students s
left outer join college c on c.sid = s.sid
left outer join locations l on l.sid = c.sid
left outer join departments d on d.sid = l.sid;
Given what you've shown it would appear that what you really want is
select s.sname,
c.cname,
l.loc,
d.dept
from students s
LEFT OUTER JOIN college c
ON c.SID = s.SID
LEFT OUTER JOIN locations l
ON l.SID = s.SID
LEFT OUTER JOIN departments d
ON d.SID = s.SID
The issue in your original query is that because an OUTER JOIN is an optional join, you can end up with NULL values being returned in one of the join fields, which then prevents any of the downstream values being joined. I agree with #ThorstenKettner who observes in a comment that SID is apparently a "student ID", but it's not reasonable or appropriate to have a "student ID" field on tables named COLLEGE, LOCATIONS, or DEPARTMENTS. Perhaps you need to update your design to allow any number of students to be associated with one of these entities, perhaps using a "join" table.
Best of luck.

Joining two tables, customers and orders to get list of all customers and the order number IF they have an order

SELECT a.org,
a.id,
a.Name,
b.ordNum
FROM customers A,
orders B
WHERE a.org = 'JJJ'
AND a.org = b.org (+)
AND b.addr_type (+) = 'ST' -- <<<<<<<<<<<<<<<<< why do i need to add (+) here
AND a.cust_id = b.cust_id (+)
ORDER BY 2
I have a table with a list of customers (A) and a table called orders (B) that have orders the customers may have placed .
The query i have above is supposed to give me the names of all customers and the order number IF there is an order linked to that customer.
My question is.. why do i need to add the (+) after b.addr_type to get all the customers even if they have not placed an order.
That is the old-style JOIN syntax, wherein (+) denotes an OUTER JOIN. This means that every row in the left table will be returned whether it has a match on the right table or not. To get only the customers with order, use an INNER JOIN. Additionally, you should use explicit JOIN and not the old-style syntax:
SELECT
c.ORG, c.ID, c.NAME, o.ordNum
FROM customers c -- Use meaningful aliases to improve readability
LEFT JOIN orders o
ON c.org = o.org
AND c.cust_id = o.cust_id
AND o.addr_type = 'ST'
WHERE
c.org = 'JJJ'
ORDER BY c.ID
The (+) is an "outer join" in old style syntax. This means EVERY row on the left side of the join is returned with a "null" in the right hand side table's colums if no match is made.
An INNER join (regular equals in old style SQL) would not return a record if there was no match on the right side.
Modern syntax is
SELECT A.ORG, A.ID, A.NAME, b.ordNum FROM
customers A
LEFT OUTER JOIN customers b on a.id = b.id
AND a.cust_id = b.cust_id
AND b.addr_type = 'ST'
WHERE a.org = 'JJJ'
ORDER BY 2
The "OUTER" part is optional, and indeed implicit if you're using the word "LEFT". Your other options are RIGHT and FULL for outer joins.
Why use this new syntax? Because it's ANSI SQL compliant, the (+) is deprecated and won't port over to some modern RDBMS implementations. Plus, as per the comment on this post, it's as ugly as sin and hard to maintain.
The (+) syntax tells Oracle to execute a left join instead of an inner join.
The result is a list of records with all valorized columns from customers and some empty columns from orders table.
If the columns from orders table are NULL, the where condition b.addr_type = 'ST' will be always FALSE for these records, so you will not obtain the desired result.
Instead if you write b.addr_type(+) = 'ST' you'll get all columns matching the condition plus the columns with NULL value because of the left join, that is what you want to get.
In order to avoid such questions,
switch to LEFT JOIN syntax which is more readable
SELECT a.org,
a.id,
a.Name,
b.ordNum
FROM customers a LEFT JOIN
orders b ON (a.org = b.org)
AND (b.addr_type = 'ST')
AND (a.cust_id = b.cust_id)
WHERE a.org = 'JJJ'
ORDER BY a.id -- better put it direct, not field's index

trying to inner join multiple tables but always returning 0 rows

I am trying to figure out why this query returns 0 rows as there is data in all 3 tables.
Here are my tables:
Table1: Applications
Columns: ID, Name
Table2: Resources
Columns: ID, Name
Table3: ApplicationResourceBridge
Columns: ID, app_id, resource_id
And Here is the query
SELECT Resources.name
, ApplicationResourceBridge.resource_id AS Expr3
FROM Resources
INNER JOIN Applications
ON Resources.id = Applications.id
INNER JOIN ApplicationsResources
ON Resources.id = ApplicationResourceBridge.resource_id
Your current query tries to match Resources.id with Applications.id, but they're different things. It should match Applications.id with ApplicationResources.app_id.
It's generally clearer to have the bridge table as the middle join, so it looks like a link. For example:
SELECT Resources.name
, ar.resource_id
FROM Resources r
INNER JOIN ApplicationsResources ar
ON r.id = ar.resource_id
INNER JOIN Applications a
ON a.id = ar.app_id
SELECT r.Name AS "Resource Name" , a.Name AS "Application Name"
FROM ApplicationResourceBridge as b
INNER JOIN Resources as r ON r.ID = b. resource_id
INNER JOIN Applications as a ON a.ID = b.app_id
UPDATE:
When constructing FROM ... JOIN ... JOIN ... follow "the path" do not "jump over".
Change this:-
Applications ON Resources.id = Applications.id INNER JOIN
to this:-
Applications ON Applications.id = ApplicationResourceBridge.app_id INNER JOIN
You were trying to join the Appliciation ID to the Resource ID but these have no relationship. What you really want is to join the Application table to the Bridge table and the Resource table to the Bridge table.
The fact that all three have data in them is immaterial. The question is whether there is data in "Resources" that has the same ID as rows in BOTH "Applications" and "ApplicationResourceBridge".
Update: don't want to post this as if I thought of it but Andomar makes a good point that you seem to be attempting to link the wrong tables fields. Thus, my answer might be right in the abstract but his might explain why you aren't getting field matches.