join using two column in sql - sql

ProjectMaster
ProjectID ITManagerID DevelopmentManagerID
--------------------------------------------------
1 1000 1001
UserTable
UserID UserName
----------------
1000 Sam
1001 Ram
Result
Project ItManagerName DevManagerName
------------------------------------------------
1 sam ram
Help to write query
Edit:
I tried
select
projectid,projectName,projectdescription,startdate,enddate,
apsmanagerid,projectmanager,ragstatus,projectstatus,projectpriority,
categoryid,inactivedate,comments,it.userName AS ITProjectManagerName,
dev.userName as DevManagerName
from pmis_project p,pmis_user It,pmis_user dev
where p.DevprojectManager = It.userid
and p.ITmanagerid = dev.userid
and p.projectid IN (Select Projectid from SelectedProject)

You can JOIN a table as many times as needed.
In this case
one JOIN to Users to get the ITManager's name.
one JOIN to Users to get the DevManager's name.
SQL Statement
SELECT ProjectID
, ITManagerName = m.UserID
, DevManagerName = d.UserID
FROM ProjectMaster pm
INNER JOIN UserTable m ON m.UserID = pm.ITManagerID
INNER JOIN UserTable d ON d.UserID = pm.DevelopmentManagerID

You can include the same table multiple times in the FROM clause of a SELECT query. If you're doing this, you frequently want to introduce an alias for one or more of these tables, so that they can be referred to in the rest of the query. You introduce an alias by adding AS alias after the name of the table, e.g.:
SELECT
*
FROM
Table As t
WHERE
t.Column = 'x' --<-- using the alias here
(the AS is actually optional)
Joining tables in a FROM clause is performed by using the JOIN keyword, and placing the conditions for the join in the ON:
FROM
Table1 t1
inner join
Table2 t2
on
t1.ColumnA = t2.ColumnB

SELECT * FROM ProjectMaster PM
INNER JOIN UserTable UT ON UT.UserId = ITManagerId
INNER JOIN UserTable UT1 ON UT1.UserId = DevelopmentManagerId

Related

Left join vs. inner join not returning expected records

I am trying to find all of the most recent records (attempt_date) for a given "course" for each user. The query below returns the correct date for each user, unless the user doesn't have an attempt_date. In that case, the query does not return a row with the user at all.
If I change the inner joins on gradebook_grade and attempt to left join, it returns all enrolled users, but the query then returns null values if a null value exists for the any submission in the "course" rather than just the most recent attempt_date. Query here (forgive the weird naming conventions for term in the where clause, I did not choose those):
select distinct on (cu.pk1)
cu.pk1
,cm.course_id
,a.attempt_date
from course_users cu
inner join course_main cm on cm.pk1 = cu.crsmain_pk1
inner join course_term ct on ct.crsmain_pk1 = cm.pk1 /* through table */
inner join term t on t.pk1 = ct.term_pk1
inner join gradebook_grade gg on gg.course_users_pk1 = cu.pk1
inner join attempt a on a.gradebook_grade_pk1 = gg.pk1
where t.name like '%Fall 2021%'
and cu.role = 'S'
and cu.row_status = '0'
order by cu.pk1, course_id, attempt_date desc
How can I sidestep this behavior? If a student only has null values in a course for submission dates, I want the null value. If a student has anything other than a null value for submission dates in a course, I want the most recent last attempt date.
*Edited to give minimal reproducible example.
If you can, please write the structure of tables (create table DDL commands) and sample data. I will help you. But, I understood that: For example, we have 5 records in course_users table, and in the gradebook_grade may be have 7-8-10 records for only linked user3 and user4. Which users are not data in gradebook_grade table, we must select these users as null values, but which users have data in the gradebook_grade table, these users must be selected as one by one with the last attempt_date field.
For Example:
course_users.pk1
course_main.course_id
attempt_date
1
30
2
30
3
30
2021-03-10
4
20
2021-08-01
5
20
In this example, user3 and user4 have courses, but other users don't have.
Firstly we write a query that will select only users, which has courses and group these users by the last attaempt_date
select g1.course_users_pk1, max(a1.attempt_date) as attempt_date from attempt a1
inner join gradebook_grade g1 on a1.gradebook_grade_pk1 = g1.pk1
group by g1.course_users_pk1
Result:
course_users_pk1
attempt_date
3
2021-03-10
4
2021-08-01
Then completing our full query, with left joining this query to our main tables. Our final query:
select distinct on (cu.pk1)
cu.pk1,
cm.course_id,
gg.attempt_date
from course_users cu
left join course_main cm on cm.pk1 = cu.crsmain_pk1
left join course_term ct on ct.crsmain_pk1 = cm.pk1 /* through table */
left join term t on t.pk1 = ct.term_pk1 and t.name like '%2021%'
left join (
select g1.course_users_pk1, max(a1.attempt_date) as attempt_date from attempt a1
inner join gradebook_grade g1 on a1.gradebook_grade_pk1 = g1.pk1
group by g1.course_users_pk1
) gg on cu.pk1 = gg.course_users_pk1
where
cu.role = 'S'
and cu.row_status = '0'
order by cu.pk1, course_id, attempt_date desc
Maybe I misunderstood your question or your table structure, I am sorry, but if you can write create tables and some samples data I'm trying to help you.

Get all the values from the first left table but when two left joins used its restricting the values from first table

I am trying to get all the values from the first left table but when I use two left joins its restricting the values from first table.
I used the below query
SELECT P.person_id, TS.Task_Id, TS.skill
FROM Person P
LEFT JOIN Person_Skill PS ON P.person_id = PS.person_id
LEFT JOIN Task_Skill TS ON PS.Skill = TS.Skill
WHERE ts.task_id = 245
I need all the person id from person table.
Just move the condition on the left joined table from the where clause to the on clause of the join:
select p.person_id, ts.task_id, ts.skill
from person p
left join person_skill ps
on p.person_id = ps.person_id
left join task_skill ts
on ps.skill = ts.skill
and ts.task_id = 245 --> here
Rationale: conditions in the where clause are mandatory. If there is no match in ts, then condition ts.task_id = 245 cannot be satisfied, since ts.task_id is null.
Use the filter condition in a sub query instead of using it as a global filter outside. This should give you the output that you desire.
SELECT P.person_id,TS.Task_Id,TS.skill FROM Person P
LEFT JOIN Person_Skill PS
ON P.person_id=PS.person_id
LEFT JOIN
(Select * from Task_Skill where task_id = 245) TS
ON PS.Skill=TS.Skill;

SQL include entries with no data

Here is my sql statement in Oracle that I am working with:
SELECT FACILITY.fac_name
, SUM(FEE_LOG.fee_amount) AS TOTAL_FEES
FROM FACILITY
, BOOK_DETAIL
, TRANS_LOG
, FEE_LOG
, TRANS_TYPE
WHERE
FACILITY.fac_id = BOOK_DETAIL.fac_id
AND BOOK_DETAIL.bkdt_id = TRANS_LOG.bkdt_id
AND TRANS_LOG.trans_id = FEE_LOG.trans_id
AND TRANS_LOG.trans_type_id = TRANS_TYPE.trans_type_id
AND
(
TRANS_TYPE.trans_type_desc = 'LOST'
OR TRANS_TYPE.trans_type_desc = 'CHECKIN'
)
GROUP BY FACILITY.fac_name;
It outputs something similar to this:
FACILITY TOTAL_FEES
Facility 1 8.45
Facility 2 4.23
Facility 3 5.23
I have 2 other facilities but they do not have any fees associated with them. I want to show them as 0
So the output would be like:
FACILITY TOTAL_FEES
Facility 1 8.45
Facility 2 4.23
Facility 3 5.23
Facility 4 0
Facility 5 0
ER Diagram
Use LEFT JOIN instead of implicit INNER JOIN for the FEE_LOG table
SELECT FACILITY.fac_name
, SUM(FEE_LOG.fee_amount) AS TOTAL_FEES
FROM FACILITY
JOIN BOOK_DETAIL ON FACILITY.fac_id = BOOK_DETAIL.fac_id
JOIN TRANS_LOG ON BOOK_DETAIL.bkdt_id = TRANS_LOG.bkdt_id
LEFT JOIN FEE_LOG ON TRANS_LOG.trans_id = FEE_LOG.trans_id
JOIN TRANS_TYPE TRANS_LOG.trans_type_id = TRANS_TYPE.trans_type_id
WHERE TRANS_TYPE.trans_type_desc IN ('LOST', 'CHECKIN')
GROUP BY FACILITY.fac_name;
Use outer joins and the on clause:
SELECT FACILITY.fac_name, SUM(nvl(FEE_LOG.fee_amount,0)) AS TOTAL_FEES
FROM FACILITY
left join BOOK_DETAIL
on FACILITY.fac_id = BOOK_DETAIL.fac_id
left join TRANS_LOG
on BOOK_DETAIL.bkdt_id = TRANS_LOG.bkdt_id
left join FEE_LOG
on TRANS_LOG.trans_id = FEE_LOG.trans_id
left join TRANS_TYPE
on TRANS_LOG.trans_type_id = TRANS_TYPE.trans_type_id
and TRANS_TYPE.trans_type_desc in ('LOST', 'CHECKIN')
GROUP BY FACILITY.fac_name;
Note: If these facilities you are referring to, that do not have any fees, have rows on BOOK_DETAIL or TRANS_LOG you can replace the outer join with an inner join (for just those tables). Any table at which point there may or may not be a related record you have to use an outer join.
Try this:
SELECT f.fac_name
, coalesce(SUM(fl.fee_amount),0) AS TOTAL_FEES
FROM FACILITY AS f
INNER JOIN BOOK_DETAIL AS bd
ON bd.fac_id = f.fac_id
INNER JOIN TRANS_LOG AS tl
ON tl.bkdt_id = bd.bkdt_id
LEFT OUTER JOIN FEE_LOG AS fl
ON fl.trans_id = tl.trans_id
INNER JOIN TRANS_TYPE AS tt
ON tt.trans_type_id = tl.trans_type_id
WHERE tt.trans_type_desc in ('LOST' , 'CHECKIN')
GROUP BY f.fac_name;
NB: when you list tables after from with commas between them you're effectively using a cross join.
When you add a condition to your where statement matching a field from one table to a field from another, the join becomes an inner join.
To select all records from one table along with any matches which may or may not exist from another you need an outer join.
There are 3 types:
left outer join where you want all records from the first table listed and any matching records from the second.
right outer join for all records from the second with only matches from the first.
full outer join is all records from both tables, alongside one another where there's a match.
You should always specify the type of join rather than implying it through where clauses / commas, as this makes your intentions clearer and thus your code more readable.

How to transform a row to a column and add it to the result set

I have 5 different tables as shown in the pictures.
I can combine them using that query but i want to add book read log with using book names as column name into that table.
I show my tables in picture with different colors.
select dbo.Users.name+' '+dbo.Users.surname AS name_surname,
dbo.Student_Facebook_Data.likes,
dbo.Student_Facebook_Data.posts,
dbo.Student_Facebook_Data.comments,
dbo.Attendance.absence,dbo.Attendance.physical_presence,
dbo.Attendance.virtual_presence
from dbo.Users inner join dbo.Student_Facebook_Data on dbo.Users.id=dbo.Student_Facebook_Data.student_id
inner join dbo.Attendance on dbo.Users.id=dbo.Attendance.student_id
I tried that queries but these are doesn't solve my problem:
select dbo.Users.name+' '+dbo.Users.surname AS name_surname ,dbo.Student_Log.content_id
from dbo.Student_Log inner join
dbo.Users on dbo.Student_Log.student_id=dbo.Users.id
select distinct(material_name)
from dbo.Material_Detail inner join
dbo.Student_Log on dbo.Student_Log.content_id=convert(varchar,dbo.Material_Detail.id)
select distinct(material_name)
from dbo.Material_Detail inner join
dbo.Student_Log on dbo.Student_Log.content_id=convert(varchar,dbo.Material_Detail.id)
If your database is SQL Server 2005 or higher, you can definitely do it using the PIVOT operator. For clarity, I'm only showing how to display the count for books and using simplified table names:
select * from (
select u.name as 'user_name',
b.name as 'book_name',
l.id as 'reading'
from dbo.Users u
left join dbo.RealLog l on u.id = l.user_id
left join dbo.Books b on l.bid = b.id
) x
pivot (count(reading) for book_name in ([one],[two],[three],[four],[five])) as count
PIVOT Reference: http://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

SQL: Matching multiple columns value

I have a database set up so that the username (username) and id (id) are stored in the members table.
I have another table that records reports and I record each column in the table (fid), who reported it (rid) and who they were reporting (id) which both match to the user's id in the members table.
How could I get a query to pull the username for both the rid and id?
My current query is
SELECT selfreport.fid, selfreport.rid,
selfreport.id, members.username as username
FROM members, selfreport
WHERE members.id = selfreport.id
ORDER BY fid
but this only gets the username for who they were reporting. How can I get it to pull the username for both?
You need to join to your members table twice. Try something like this:
SELECT selfreport.fid,
selfreport.rid,
selfreport.id,
COALESCE(WhoReported.username, 'Not Specified') AS WhoReportedUN,
COALESCE(ReportedTo.username, 'Not Specified') AS ReportedToUN
FROM selfreport
LEFT JOIN members WhoReported ON WhoReported.id = selfreport.id
LEFT JOIN members ReportedTo ON ReportedTo.id = selfreport.rid
ORDER BY fid
Do not use implicit SQL '89 joins they are an antipattern.
Use explicit join syntax instead.
SELECT s.fid, s.rid, s.id, m1.username as username, m2.username as rusername
FROM selfreport S
INNER JOIN members m1 ON (m1.id = s.id)
INNER JOIN members m2 ON (m2.id = s.rid)
ORDER BY s.fid
If id or rid is optional, use a left join.
SELECT
s.fid, s.rid, s.id
, COALESCE(m1.username, 'nobody') as username
, COALESCE(m2.username, 'nobody') as rusername
FROM selfreport S
LEFT JOIN members m1 ON (m1.id = s.id)
LEFT JOIN members m2 ON (m2.id = s.rid)
ORDER BY s.fid
You need to join members twice:
SELECT selfreport.fid,
selfreport.rid,
selfreport.id,
m1.username AS ReportToUsername,
m2.username AS ReporteeUsername
FROM selfreport
INNER JOIN members m1
ON m1.id = selfreport.id
INNER JOIN members m2
ON m2.id = selfreport.rid
ORDER BY fid
Since you were doing an implicit join in your original query, I believe INNER JOIN will suit you well. However, if it's possible to have null values in selfreport.id or selfreport.rid, you should use LEFT JOIN instead.