retrieve data from multiple tables not working - sql

I have three tables
quiz: activetruck:
id id
name name
origin origin
destination destination
total_trucks total_trucks
material_type scheduled_date
scheduled_date offered_price
offered_price owner_id
owner_id subject_id
subject_id
I ran this query to extract the common data from both the tables
Select * from quiz as cq, activetruck as ca
where cq.origin=ca.origin and cq.destination=ca.destination and
cq.subject_id=ca.subject_id and cq.total_trucks<=ca.total_trucks;
there is a third table supplier and supplier is connected to active truck via owner_id
columns of suppliers are:
user_id
supplier_name
supplier_company_name
supplier_email
supplier_gst
supplier_pan
supplier_address
supplier_origin
supplier_service
I want to fetch all the details of supplier where activetruck.owner_id = suppliers.user_id
I tried running this but it didn't work
Select * from classroom_quiz as cq, classroom_activetruck as ca, classroom_supplier as cs
where cq.origin=ca.origin and cq.destination=ca.destination and
cq.subject_id=ca.subject_id and cq.total_trucks<=ca.total_trucks and
ca.owner_id=cs.user_id;

A left outer join is what you need to use. More info here.
The left outer join on activetruck and suppliers will return the suppliers details that match but in the case where there isn't a match it will still return the activetruck rows. Your query is joining where activetruck matches suppliers but if there isn't a match then it doesn't return anything.
SELECT *
FROM classroom_quiz AS cq
INNER JOIN classroom_activetruck ca ON cq.origin = ca.origin
AND cq.destination = ca.destination
AND cq.subject_id = ca.subject_id
AND cq.total_trucks <= ca.total_trucks
LEFT OUTER JOIN classroom_supplier cs ON ca.owner_id = cs.user_id;

Related

joining a table on 2 fields

I want to pull a person and their supervisor names from a table. The persons table has the supervisor_id and the person_id. The names table has name_id and a Full Name field. If I join Person ON either supervisor_id or person_id, how do I get the other to display as well?
You need to join twice, one for each relationship you have:
SELECT
-- Persons' columns
P.*,
-- Superviser name columns
SN.*,
-- Person name columns
PN.*
FROM
persons AS P
LEFT JOIN names AS SN ON P.supervisor_id = SN.name_id
LEFT JOIN names AS PN ON P.person_id = PN.name_id
Or you can join with an OR clause, but you won't be able to know which record did you join with unless you check with a CASE.
SELECT
-- Persons' columns
P.*,
-- name columns
N.*,
IsSupervisor = CASE WHEN P.supervisor_id = N.name_id THEN 'Yes' ELSE 'No' END
FROM
persons AS P
LEFT JOIN names AS N ON
P.supervisor_id = N.name_id OR
P.person_id = N.name_id
This last approach will display 2 rows as it will match either one or the other on different occasions, not both with the same persons row (as the first example).
A (self)join is what you need:
select p.*, supervisor=ps.name
from Person p join person ps on p.supervisor_id=ps.id

How to work in case in join condition

How to find city when ContactID is provided and condition is if ContactID is coming as 123 then it will look whether it is P or C, If P then it will go to Person table and returns City(USA) as output and If C then it will go to Company table and gives City(AUS) as output.
NB: all tables contain thousands of record and City value comes from run time.
Unless you're dynamically generating the query (i.e. using some language other than SQL to execute it) then you need to join on both tables anyway. If you're joining on both tables then there's no need for a CASE statement:
select *
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
You'll start noting an issue here, for every column from PERSON and COMPANY you're going to have to add some business logic to work out which table you want the information from. This can get very tiresome
select co.contactid
, case when p.id is not null then p.name else c.name end as name
from contacts co
left outer join person p
on co.contactid = p.contactid
and co.person_company = 'P'
left outer join company c
on co.contactid = c.contactid
and co.person_company = 'C'
Your PERSON and COMPANY tables seem to have exactly the same information in them. If this is true in your actual data model then there's no need to split them up. You make the determination as to whether each entity is a person or a company in your CONTACTS table.
Creating additional tables to store data in this manner is only really helpful if you need to store additional data. Even then, I'd still put the data that means the same thing for a person or a companny (i.e. name or address) in a single table.
If there's a 1-2-1 relationship between CONTACTID and PID and CONTACTID and CID, which is what your sample data implies, then you have a number of additional IDs, which have no value.
Lastly, if you're not restricting that only companies can go in the COMPANY table and individuals in the PERSON table. You need the PERSON_COMPANY column to exist in both PERSON and COMPANY, though as a fixed string. It would be more normal to set up this data model as something like the following:
create table contacts (
id integer not null
, contact_type char(1) not null
, name varchar2(4000) not null
, city varchar2(3)
, constraint pk_contacts primary key (id)
, constraints uk_contacts unique (id, contact_type)
);
create table people (
id integer not null
, contact_type char(1) not null
, some_extra_info varchar2(4000)
, constraint pk_people primary key (id)
, constraint fk_people_contacts
foreign key (id, contact_type)
references contacts (id, contact_type)
, constraint chk_people_type check (contact_type = 'P')
);
etc.
you can LEFT JOIN all 3 tables and the using a CASE statement select the one that you need based on the P or C value
SELECT
CASE c.[Person/Company]
WHEN 'P' THEN p.NAME
WHEN 'C' THEN a.Name
END AS Name
FROM Contact c
LEFT JOIN Person p on p.ContactId = c.ContactId
LEFT JOIN Company a on a.ContachId = c.ContactId
Ben's answer is almost right. You might want to check that the first join has no match before doing the second one:
select c.*, coalesce(p.name, c.name) as p.name
from contacts c left outer join
person p
on c.contactid = p.contactid and
c.person_company = 'P' left join
company co
on c.contactid = co.contactid and
c.person_company = 'C' and
p.contactid is null;
This may not be important in your case. But in the event that the second join matches multiple rows and the first matches a single row, you might not want the additional rows in the output.

Listing Pairs on same table with different criteria on Oracle Sql

I need to list pairs of customer names as follows;
> CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
such that each pair of customers has the same zip code (which is also in the customers table).
On the task there is a hint which says
HINT: Your output should have four columns: CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
This is what I have written so far:
SELECT DISTINCT CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME, CUSTOMER_FIRST_NAME, CUSTOMER_LAST_NAME
FROM CUSTOMERS
WHERE CUSTOMER_ZIP = CUSTOMER_ZIP
But I am not sure how to continue since I've only started learning SQL yesterday. I have also tried to Join the same table which resulted in ambiguity errors.
Update#1:
I've written this code using aliases as suggested by #kpater87
SELECT DISTINCT C1.CUSTOMER_FIRST_NAME, C1.CUSTOMER_LAST_NAME , C2.CUSTOMER_FIRST_NAME, C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
But even though I have a distinct statement it will show duplicate data. Is this to be expected or am I missing something?
Your updated query looks fine. The only problem in your query is it will be joining also the same records.
If you have a primary key in the table you can improve your query by adding WHERE condition:
SELECT DISTINCT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
WHERE C1.PK <> C2.PK;
PK - is a column being a primary key in the table.
If you don't have primary key you can try this one:
SELECT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME
FROM CUSTOMERS C1
INNER JOIN CUSTOMERS C2
ON C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
WHERE C1.CUSTOMER_FIRST_NAME <> C2.CUSTOMER_FIRST_NAME
AND C2.CUSTOMER_LAST_NAME <> C2.CUSTOMER_LAST_NAME
But there still be a problem that in your output you will get e.g.
Mary Smith James Bond
James Bond Mary Smith
To remove permutations:
SELECT C1.CUSTOMER_FIRST_NAME,
C1.CUSTOMER_LAST_NAME ,
C2.CUSTOMER_FIRST_NAME,
C2.CUSTOMER_LAST_NAME,
C1.CUSTOMER_ZIP
FROM T_CUSTOMERS C1
LEFT JOIN T_CUSTOMERS C2
ON (C1.CUSTOMER_ZIP = C2.CUSTOMER_ZIP
AND
C1.CUSTOMER_NUMBER > C2.CUSTOMER_NUMBER );
See also: SQL: self join using each rows only once

Two group by tables stich another table

I have 3 tables I need to put together.
The first table is my main transaction table where I need to get distinct transaction id numbers and company id. It has all the important keys. The transaction ids are not unique.
The second table has item info which is linked to transaction id numbers which are not unique and I need to pull items.
The third table has company info which has company id.
Now I've sold some of these with the first one through a group by id. The second through a subquery which creates unique ids and joins onto the first one.
The issue I'm having is the third one by company. I cannot seem to create a query that works in the above combinations. Any ideas?
As suggested here is my code. It works but that's because for the company I used count which doesn't give the correct number. How else can I get the company number to come out correct?
SELECT
dep.ItemIDAPK,
dep.TotalOne,
dep.company,
company.vendname,
appd.ItemIDAPK,
appd.ItemName
FROM (
SELECT
csi.ItemIDAPK,
sum(f.TotalOne) as TotalOne,
count(f.DimCurrentcompanyID) company
FROM dbo.ReportOne F with (nolock)
INNER JOIN dbo.DSaleItem csi with (nolock)
on f.DSaleItemID = csi.DSaleItemID
INNER JOIN dbo.DimCurrentcompany cv
ON f.DimCurrentcompanyID = cv.DimCurrentcompanyID
INNER JOIN dbo.DimDate dat
on f.DimDateID = dat.DimDateID
where (
dat.date >='2013-01-29 00:00:00.000'
and dat.date <= '2013-01-30 00:00:00.000'
)
GROUP BY csi.ItemIDAPK
) as dep
INNER JOIN (
SELECT
vend.DimCurrentcompanyID,
vend.Name vendname
FROM dbo.DimCurrentcompany vend
) As company
on dep.company = company.DimCurrentcompanyID
INNER JOIN (
SELECT
c2.ItemIDAPK,
ItemName
FROM (
SELECT DISTINCT ItemIDAPK
FROM dbo.dimitem AS C
) AS c1
JOIN dbo.dimitem AS c2 ON c1.ItemIDAPK = c2.ItemIDAPK
) as appd
ON dep.ItemIDAPK = appd.ItemIDAPK
For further information my output is the following example, I know the code executes and the companyid is incorrect as I just put it with a (count) in their to make the above code execute:
Current Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 303 Johnson Corp 29323 Soap
Proposed Results:
Item Number TLS CompanyID Company Name Item Number Item Name
111111 300 29 Johnson Corp 29323 Soap

Selecting from table with categories of people

I created a database in ms sql , in the database I have three category of persons namely staff, customers, suppliers whom I stored in different tables create serial unique id for each.
Now these persons id are stored under person_id and a column names person type which stores whether its a staff, custimer or supplier in the transaction table, The problem lies in selecting the records from the transaction table like this pseudo code
Select t.*,s.na as staff,sp.name as supplier, c.name as customer
From Trans t
left join Staff s on s.id = t.pid
left join Suppliers sp on sp.id = t.pid
left join Customers c on c.id = t.pid
This returns one row, instead of at least 3 or more, How do I solve this problem
My trans table
person_id Person_type Trans_id
1 staff 1
1 customer 2
2 customer 3
3 suppler 4
1 staff 5
Expected output
person_name Trans_id
james 1
mark 2
dan 3
jude 4
james 5
Staff, Customers, and suppliers are stored in their different tables
That's what the Join does, combine data from multiple tables into one result row. If you want to "keep the rows", not combine them, you can use UNION
(
Select t.* From Trans t
left join Staff s on s.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Suppliers sp on sp.id = t.pid
)
UNION
(
Select t.* From Trans t
left join Customers c on c.id = t.pid
)
This will get you the multiple rows you want BUT still not sure you have defined it right. I see you are only taking columns from Trans, so you're not getting any data from the other tables. And you're doing left outer joins so the other tables won't affect the selection. So I think it's just that same as selecting from just Trans.
If what you want is data from Trans where there is corresponding entry in the other tables, then do the UNION, but also change the outer joins to inner.