Oracle sql one-to-many Join - sql

I'm new to this sql world. After I'm a developer with limited knowledge in SQL & simple joins. I have an issue in writing sql join for one-to-many relationship. Here's my problem say -
For instance if I have a VendorsList table with:
id Name address
1 sales Japan
2 marketing US
And a VendorContacts table with:
id vendorid vendorempname
1 1 Tom
2 1 Bill
3 2 Jessy
4 1 Rachel
5 2 Rob
Now what I want after join is :
vendor_id Name address vendorempname
1 Sales Japan Tom
1 Sales Japan Bill
1 Sales Japan Rachel
2 Marketing US Jessy
2 Marketing US Rob
Can any one help in writing join for this please?

This should do the work
Select v.vendor_id, v.name, v.address, vc.vendorempname
from VendorContacts vc
join VendorList v
on v.id = vc.vendor_id
order by vc.vendor_id

SELECT b.vendor_id, a.Name, a.address, b.vendorempname
FROM VendorList a, VendorContact b
WHERE a.id = b.vendor_id
ORDER BY b.vendor_id;

Please have look this:
Select vl.vendorId,vl.name,vl.address,vc.vendorempname
from vendorlist as vl
right join VendorContacts as vc
on vl.vendorId = vc.vendorId
order by vc.vendorId asc
please try this and will get data that you want.

Try below query. It gives the exact results you are looking for except the order of the reps name..
WITH VENDORLIST AS
(SELECT '1' ID, 'sales' Name, 'Japan' address FROM DUAL
UNION
SELECT '2' ID, 'marketing' Name, 'US' address FROM DUAL),
VENDORCONTACTS AS
(
SELECT '1' ID, '1' vendorid, 'Tom' vendorempname FROM DUAL
UNION
SELECT '2' ID, '1' vendorid, 'Bill' vendorempname FROM DUAL
UNION
SELECT '3' ID, '2' vendorid, 'Jessy' vendorempname FROM DUAL
UNION
SELECT '4' ID, '1' vendorid, 'Rachel' vendorempname FROM DUAL
UNION
SELECT '5' ID, '2' vendorid, 'Rob' vendorempname FROM DUAL
)
SELECT VENDORID, NAME, ADDRESS, vendorempname FROM VENDORLIST, VENDORCONTACTS
WHERE VENDORCONTACTS.vendorid = VENDORLIST.ID
ORDER BY VENDORID, NAME, ADDRESS, vendorempname
;

Related

ORACLE SQL JOINS

I have the two tables:
TABLE1:
id name values
1 john AB
2 marry CD
3 sreya YG
TABLE2:
pid country values
45 india JKABHJ
46 usa YURRRCD
47 uk YGHJJKLJL
output
name values country
john AB india
marry CD usa
sreya YG uk
I want to join these two tables on the common columns values, but the other table columns contain extra data. How to overcome this?
table2 column "values" contains data matching to table1 "values"
values
AB
CD
YG
values
JKABHJ
YURRRCD
YGHJJKLJL
You can use like operator in query for matching values in table1 and table2.
For this query:
WITH table1 as (
select 1 as id, 'john' as name, 'AB' as value from dual union all
select 2 as id, 'marry' as name, 'CD' as value from dual union all
select 3 as id, 'sreya' as name, 'YG' as value from dual
),
table2 as (
select 45 as id, 'india' as country, 'JKABHJ' as value from dual union all
select 46 as id, 'usa' as country, 'YURRRCD' as value from dual union all
select 47 as id, 'uk' as country, 'YGHJJKLJL' as value from dual
)
select a.name, a.value, b.country
from table1 a
join table2 b on b.value like '%'||a.value||'%';
Output:
NAME VALUE COUNTRY
john AB india
marry CD usa
sreya YG uk
But I would recommend you to change a structure to make it more efficient. For example, by adding new table table2_values with column id referenced to table2.id and split values:
WITH table1 as (
select 1 as id, 'john' as name, 'AB' as value from dual union all
select 2 as id, 'marry' as name, 'CD' as value from dual union all
select 3 as id, 'sreya' as name, 'YG' as value from dual
),
table2 as (
select 45 as id, 'india' as country from dual union all
select 46 as id, 'usa' as country from dual union all
select 47 as id, 'uk' as country from dual
),
table2_values as (
select 45 as id, 'JK' as value from dual union all
select 45 as id, 'AB' as value from dual union all
select 45 as id, 'HJ' as value from dual union all
select 46 as id, 'YU' as value from dual union all
select 46 as id, 'RRR' as value from dual union all
select 46 as id, 'CD' as value from dual union all
select 47 as id, 'YG' as value from dual union all
select 47 as id, 'HJ' as value from dual
)
select a.name, a.value, c.country
from table1 a
join table2_values b on b.value = a.value
join table2 c on c.id = b.id;
You should use like operator while joining the two tables.
As below
SELECT *
FROM TABLE1
JOIN TABLE2
ON TABLE1.values like CONCAT('%',TABLE2.values,'%')

sql intersect with dynamic input set

I'm trying to figure out how to get the intersection of a dynamic input set. Here is a very simplified example.
company_status table:
COMPANY | STATUS
----------------
Big | 1
Notused | 0
Small | 1
company_country table:
COMPANY | COUNTRY
-----------------
Big | CA
Big | US
Notused | CA
Notused | FR
Small | US
Small | IT
What I want is the intersection of the countries for only certain companies.
If I select only companies where status = 1, here is my expected output:
US
If I select only companies where status = 0, here is my expected output:
CA
FR
Taking the company_status table out of the equation, this is what I need:
select country from company_status where company = 'Big'
intersect
-- ... (here is where the dynamic part comes in)
intersect
select country from company_status where company = 'Small';
But how do I add company_status into this?
If I understand correct so you want only these countries, which fulfil in every row of company_status the condition status = 1 or status = 0.
If so you could count, how many appearances are to be found in company_status and use this in the having- clause. But you of course have to put the same condition into the where- clause of the join.
WITH
company_status as (
select 'BIG' COMPANY, 1 STATUS from dual union all
select 'NOTUSED' COMPANY, 0 STATUS from dual union all
select 'SMALL' COMPANY, 1 STATUS from dual
),
company_country as (
select 'BIG' COMPANY, 'CA' COUNTRY from dual union all
select 'BIG' COMPANY, 'US' COUNTRY from dual union all
select 'NOTUSED' COMPANY, 'CA' COUNTRY from dual union all
select 'NOTUSED' COMPANY, 'FR' COUNTRY from dual union all
select 'SMALL' COMPANY, 'US' COUNTRY from dual union all
select 'SMALL' COMPANY, 'IT' COUNTRY from dual
)
select cc.country
from company_country cc join
company_status cs
on cc.company = cs.company
where cs.status = 0
group by cc.country
having count(*) = (SELECT COUNT(*) FROM company_status where status = 0);
(the with- clause only gives your rows, the rest of the question should work on your example)
But you can use with- clause to determine, which Status you want at only one place (third with- clause, would be your first):
WITH
company_status as (
select 'BIG' COMPANY, 1 STATUS from dual union all
select 'NOTUSED' COMPANY, 0 STATUS from dual union all
select 'SMALL' COMPANY, 1 STATUS from dual
),
company_country as (
select 'BIG' COMPANY, 'CA' COUNTRY from dual union all
select 'BIG' COMPANY, 'US' COUNTRY from dual union all
select 'NOTUSED' COMPANY, 'CA' COUNTRY from dual union all
select 'NOTUSED' COMPANY, 'FR' COUNTRY from dual union all
select 'SMALL' COMPANY, 'US' COUNTRY from dual union all
select 'SMALL' COMPANY, 'IT' COUNTRY from dual
),
wished_status as (select 0 wished_status from dual)
select cc.country
from company_country cc
join company_status cs on cc.company = cs.company
JOIN wished_status s on cs.status = s.wished_status
group by cc.country
having count(*) = (SELECT COUNT(*) FROM company_status cs join wished_status s on cs.status = s.wished_status);
so you only had to Change between 0 and 1 (or whatever you need) in wished_status
The basic query is:
select cc.country
from company_country cc join
company_status cs
on cc.company = cs.company
group by cc.country
Then use a having clause for your filtering. I think the two filters are:
having min(status) = max(status) and min(status) = 1
having sum(case when status = 0 then 1 else 0 end) > 0
These correspond to the result sets specified in your example.

Oracle SQL displaying data from multiple records

Sorry if I am not explaining this properly, I am relatively new to SQL.
In oracle have a table describing properties (city, property type, cost of rent per month, other information)
My question is: assuming 3 unique property types (hotel, house, empty lot), how can I show which cities do not have all 3 types of properties?
GROUP BY solution, make sure there are less than 3 different property types for each city returned:
select city
from tablename
where property_type in ('hotel', 'house', 'empty lot')
group by city
having count(distinct property_type) < 3
Your SQL query should be
SELECT City
FROM YourTable
WHERE hotel <> 'hotelname' and house <> 'housename' and emptylot <> 'name'
assuming
Hotel, House, Emptylot is column name in your database.
There are two ways,
GROUP BY
Analytic COUNT() OVER()
For example, Let's say I have sample data of 3 cities, where city 1 has all the property types satisfied, rest other cities are not having all the required property types.
Using GROUP BY
SQL> -- sample table data
SQL> WITH DATA AS(
2 SELECT 1 city, 'hotel' property FROM dual UNION ALL
3 SELECT 1 city, 'house' property FROM dual UNION ALL
4 SELECT 1 city, 'empty' property FROM dual UNION ALL
5 SELECT 2 city, 'hotel' property FROM dual UNION ALL
6 SELECT 2 city, 'house' property FROM dual UNION ALL
7 SELECT 2 city, 'scrap' property FROM dual UNION ALL
8 SELECT 3 city, 'empty' property FROM dual UNION ALL
9 select 3 city, 'house' property from dual
10 )
11 -- query
12 SELECT city
13 FROM data
14 WHERE property IN ('hotel', 'house', 'empty')
15 GROUP BY city
16 HAVING COUNT(property) < 3
17 /
CITY
----------
2
3
SQL>
Using Analytic COUNT() OVER()
SQL> -- sample table data
SQL> WITH DATA AS(
2 SELECT 1 city, 'hotel' property FROM dual UNION ALL
3 SELECT 1 city, 'house' property FROM dual UNION ALL
4 SELECT 1 city, 'empty' property FROM dual UNION ALL
5 SELECT 2 city, 'hotel' property FROM dual UNION ALL
6 SELECT 2 city, 'house' property FROM dual UNION ALL
7 SELECT 2 city, 'scrap' property FROM dual UNION ALL
8 SELECT 3 city, 'empty' property FROM dual UNION ALL
9 select 3 city, 'house' property from dual
10 )
11 -- query
12 SELECT DISTINCT city
13 FROM
14 (SELECT t.* ,
15 COUNT(property) OVER(PARTITION BY city ORDER BY city) rn
16 FROM DATA t
17 WHERE property IN ('hotel', 'house', 'empty')
18 )
19 WHERE rn < 3
20 /
CITY
----------
2
3
SQL>
Could be something like this:
SELECT City
FROM YourTable
WHERE [property type] != 'hotel' OR
[property type] != 'empty lot' OR
[property type] != 'house'
(Edited)Try this query :
select t.city from table_name t
where t.city NOT IN
(select city from table_name
where ( property_type ='hotel' or
property_type ='house' or
property_type ='Empty lot')
);
(Query returning cities where all three types of property are not present):
select t.city from table t inner join
(select city from table
where property_type not in ('House','Hotel','Empty lot')) x
on t.city=x.city
group by t.city
having count(*)<3 ;

Summarizing redundant SQL information

Given (Oracle 11g):
MANUFACTURER
------------
ID
NAME
CARS
---------
CAR_ID
MANUFACTURER_ID
NAME
PARTS
---------
PART_ID
CAR_ID
PART_NAME
Is it possible from SQL to get a listing of parts by car and manufacturer in a single query without repeating the redundant data on each row?
Something like:
FORD ESCORT Windshield Wiper
Horn
Steering Wheel
F-150 Windshield Wiper
Horn
Bed Liner
TOYOTA CAMRY Floor Mat
Door Handle
CIVIC Headlight
Horn
Or does something like this require application-level logic and/or use of reporting features. I've tried numerous queries, but gotten nothing close thus far.
Try the lag function like this:
WITH manufacturer AS (
SELECT 1 manufacturer_id, 'FORD' NAME FROM dual
UNION ALL SELECT 2, 'TOYOTA' FROM dual)
, CAR AS (
SELECT 1 car_id, 1 manufacturer_id, 'ESCORT' AS name FROM dual
UNION ALL SELECT 2, 1, 'F-150' FROM dual
UNION ALL SELECT 3, 2, 'CAMRY' FROM dual
UNION ALL SELECT 4, 2, 'CIVIC' FROM dual)
, part AS (
SELECT 1 AS part_id, 1 AS car_id, 'Windshield Wiper' AS part_name FROM dual
UNION ALL SELECT 2, 1, 'Horn' FROM dual
UNION ALL SELECT 3, 1, 'Steering Wheel' FROM dual
UNION ALL SELECT 4, 2, 'Windshield Wiper' FROM dual
UNION ALL SELECT 5, 2, 'Horn' FROM dual
UNION ALL SELECT 6, 2, 'Bed Liner' FROM dual
UNION ALL SELECT 7, 3, 'Floor Mat' FROM dual
UNION ALL SELECT 8, 3, 'Door Handle' FROM dual
UNION ALL SELECT 9, 4, 'Headlight' FROM dual
UNION ALL SELECT 10, 4, 'Horn' FROM dual)
SELECT case lag (m.name) over (order by p.part_id)
when m.name then null
else m.name
end as manufcturer,
case lag (c.name) over (order by p.part_id)
when c.name then null
else c.name
end as carname,
p.part_name
FROM manufacturer m INNER JOIN car c ON m.manufacturer_id = c.manufacturer_id
INNER JOIN part p ON p.car_id = c.car_ID
;
OUTPUT:
MANUFACTURER CARNAME PART_NAME
------------- --------- -----------------
FORD ESCORT Windshield Wiper
Horn
Steering Wheel
F-150 Windshield Wiper
Horn
Bed Liner
TOYOTA CAMRY Floor Mat
Door Handle
CIVIC Headlight
Horn
The natural way to get the result is:
select m.name as manufacturer_name, c.name as car_name, p.name as part_name
from manufacturer m join
cars c
on c.manufacturer_id = m.id join
parts p
on p.car_id = c.car_id;
This will be in a format where all the cells are filled in the table (so 'Ford' will be in the first few rows of the table).
If you only want the first appearance of each name, you can use row_number() (and be sure to sort the results in the end):
select (case when m_seqnum = 1 then manufacturer_name else '' end) as manufacturer_name,
(case when c_seqnum = 1 then car_name else '' end) as car_name,
part_name
from (select m.name as manufacturer_name, c.name as car_name, p.name as part_name,
row_number() over (partition by m.name order by c.name, p.name) as m_seqnum,
row_number() over (partition by m.name, c.name order by p.name) as c_seqnum
from manufacturer m join
cars c
on c.manufacturer_id = m.id join
parts p
on p.car_id = c.car_id
) mcp
order by manufacturer_name, car_name, part_name;

select multiple columns from mutiple tables

Example.
I have two tables
CAR
id name
1 bmw
2 fiat
Car_info
car_id field_name country
1 year 2000
1 country germany
2 year 1988
2 country italy
How in one select query I can get this?
id name year country
1 bmw 2000 germany
2 fiat 1988 italy
Ideally, you should have a column in the car_info table specifying what type of information is being displayed on that line. i.e. Type 1 is the year, type 2 is the country.
You can get round this by joining on to the car_info table twice specifying an 'AND' condition on the join, like so:
SELECT car.ID, car.Name, ci1.country as [YEAR], ci2.country as COUNTRY
FROM car
INNER JOIN car_info AS ci1 ON Car.ID = ci1.car_id AND ci1.field_name = 'year'
INNER JOIN car_info AS ci2 ON Car.ID = ci2.car_id AND ci2.field_name = 'country'
Try this :
You can use PIVOT and then join with the Car table
with cte as
(
Select car_id,[year],[country]
from
(Select car_id,field_name,countryName
from car_info
)pv
pivot
(
max(countryName)
FOR field_name IN ([year],[country])
)pvt
)
Select c.name,ct.year,ct.country
from car c inner join cte ct
on ct.car_id=c.id
Demo in SQL Fiddle
WITH car AS (
SELECT 1 AS id, 'BMW' AS name FROM dual
UNION ALL
SELECT 2, 'Fiat' FROM dual
)
, car_info AS (
SELECT 1 AS car_id, 'Year' AS field_name, '2000' AS field_val FROM dual
UNION ALL
SELECT 1, 'Country', 'Germany' FROM dual
UNION ALL
SELECT 2, 'Year', '1988' FROM dual
UNION ALL
SELECT 2, 'Country', 'Italy' FROM dual
)
SELECT c.*, car_year.field_val AS yr, car_country.field_val AS country
FROM car c
JOIN car_info car_year ON c.id = car_year.car_id AND car_year.field_name = 'Year'
JOIN car_info car_country ON c.id = car_country.car_id AND car_country.field_name = 'Country'
;