Best Way to join 1 to many tables - sql

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.

Related

Is there any alternative way for following query in oracle

select
a.id,
a.name,
b.group,
a.accountno,
(
select ci.cardno
from taccount ac, tcardinfo ci
where ac.accountno = ci.accountno
) as card_no
from tstudent a, tgroup b
where a.id = b.id
And how to select more than one field from (select ci.cardno from taccount ac,tcardinfo ci where ac.accountno = ci.accountno) or any others way
Please note that the is not a relation in two queries (main and subquery). Sub-query value depends on the data of the main query. Main query is set of data by joining multiple table and sub-query is also a set of data by joining multiple table
In essence, you are describing a lateral join. This is available in oracle since version 12.
Your query is rather unclear about from which table each column comes from (I made assumptions, that you might need to review), and you seem to be missing a join condition in the subquery (I added question marks in that spot)... But the idea is:
select
s.id,
s.name,
g.group,
s.accountno,
x.*
from tstudent s
inner join tgroup g on g.id = s.id
outer apply (
select ci.cardno
from taccount ac
inner join tcardinfo ci on ????
where ac.accountno = s.accountno
) x
You can then return more columns to the subquery, and then will show up in the resultset.

Filtering sqlite query

Having trouble with filtering in my sqlite3 query. I am working with three tables below.
Table: models
id|data
1|car
2|truck
Table: descriptions
id|model_id|colour|make
1|1|blue|accord
2|1|green|prius
3|1|red|fusion
4|1|black|civic
5|1|white|jeep
6|1|purple|jeep
7|1|brown|jeep
8|1|brown|civic
Table: banned
model_id|colour_id|colour
1|3|black|
1|15|brown|
The below statement is counting how many of what model (cars or trucks) are what make.
SELECT models.id, make, count(make)
FROM description
JOIN models ON models.id = descriptions.model_id
GROUP BY models.id, descriptions.make;
The output would below
1|accord|1
1|prius|1
1|fusion|1
1|civic|2
1|jeep|3
However, I want to put in a qualifier that voids anything containing a banned colour/model combo, by using banned.colour.
I tried joining the table and filtering out like below, but it seems to double the count.
SELECT models.id, make, count(make)
FROM description
JOIN models ON models.id = descriptions.model_id
JOIN banned ON banned.model_id = models.id
WHERE NOT ( banned.colour = descriptions.colour)
GROUP BY models.id, descriptions.make;
My desired output is to void the two cars that fit this qualifier from the count. The final result should below
1|accord|1
1|prius|1
1|fusion|1
1|jeep|2
How can i achieve this?
You can use your approach . . . with a left join and where check:
SELECT m.id, d.make, count(*)
FROM description d JOIN
models m
ON m.id = d.model_id LEFT JOIN
banned b
ON b.model_id = m.id AND b.colour = d.colour
WHERE b.model_id IS NULL -- no match
GROUP BY m.id, d.make;
A common way to write the query would also use NOT EXISTS:
SELECT m.id, d.make, count(*)
FROM description d JOIN
models m
ON m.id = d.model_id
WHERE NOT EXISTS (SELECT 1
FROM banned b
WHERE b.model_id = m.id AND b.colour = d.colour
)
GROUP BY m.id, d.make;
Although you can also use NOT IN, I highly discourage using it with a subquery. It will not do what you want if any of the values returned by the subquery are NULL.
You may use NOT IN with a dependent subquery to avoid banned combinations.
SELECT models.id, make, count(make)
FROM description
JOIN models ON models.id = descriptions.model_id
WHERE colour NOT IN (
SELECT colour
FROM banned
WHERE banned.model_id = models.id
)
GROUP BY models.id, descriptions.make;
The only pitfall of NOT IN is a possibility to have a NULL in the subquery result. However, I believe that it is safe if the colour attribute is defined as NOT NULL (which make sense in this case).

SQL Server query issue - ambiguous column

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

Error in query: aggregate function or the GROUP BY clause

Hi all I have a problem with an SQL query: the problem is that if i add GROUP BY the database engine outputs the error:
Column 'dbo.classes.class_name' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.
My query is:
string query = "SELECT p.*
FROM dbo.classes AS p INNER JOIN teacher_classes AS a
ON a.class_id = p.class_id
and teach_id = #id
GROUP BY p.class_id";
Is there any help please for that.
Note without group by the query work fine but the result not grouped.
Your query is:
SELECT p.*
FROM dbo.classes AS p INNER JOIN
teacher_classes AS a
ON a.class_id = p.class_id and teach_id = #id
GROUP BY p.class_name;
You are trying to select all the columns from p and yet you're are grouping by class_name. This is not allowed in most databases. What happens if you have two classes, but information is different from them?
One option is to use distinct rather than group by to remove duplicates:
SELECT distinct c.*
FROM dbo.classes c INNER JOIN
teacher_classes tc
ON tc.class_id = c.class_id and tc.teach_id = #id;
Another option is to use something like in to find the matching classes for the teacher:
select c.*
from classes c
where c.class_id in (select tc.class_id from teacher_classes where teach_id = #id)
Notice I also changed your aliases so they have some relationship to the table names. This makes the query much easier to read.

Calculate Percentage Of Certified Managers

I asked a similar question a few weeks ago, but now the requirements have changed.
Considering the following tables:
http://www.maroisconsulting.com/Temp/query.png
I need to create a query that returns the percentages of employees who are managers (Titles.IsManager) and who have a date in the Certified field (Employees.Certified). The results need to be grouped by the Group each store is in.
So far I have this:
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM (SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
WHERE t.IsManager
GROUP BY d.GroupId;
And then this
SELECT q.GroupId,
(SumOfcert_complete/CountOfcert_complete)*100 AS percent_certified,
Groups.GroupName
FROM qryGroupCert_base AS q
INNER JOIN Groups ON q.GroupId = Groups.GroupId;
You can see in the first query where I added the Titles table.
1) I get prompted for the IsManager, although I don't know why
2) The results coming back are not different than before I added the IsManager
Anyone see what's wrong here?
Many thanks
Within your first query, you have this subquery which includes Titles aliased as "t":
(SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
Then, after the definition of the subquery, you have this WHERE clause:
WHERE t.IsManager
The problem is the "t" alias and IsManager column only exist within the the subquery --> they are unknown to the outer (parent) query. In cases where the Access database engine encounters something it doesn't recognize as an object name, function, literal value, or SQL keyword, it thinks that something must be a parameter ... so pops up the input box asking you to provide a value for the (IsManager) parameter.
I think you should move the WHERE clause inside the subquery definition.
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM [SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
WHERE t.IsManager = True
]. AS d
GROUP BY d.GroupId;
Perhaps you need to supply a criteria for t.IsManager, such as t.IsManager = TRUE. If the where clause doesn't have a value to set it equal to, Access probably isn't resolving it to the actual column, but thinks it's a query parameter.