Oracle SQL - Joining rows that don't exist? - sql

Take these two example tables:
Table A
Name FirstOrLast
Jeremy First
Smith Last
Mark First
David First
Table B
Name
Jeremy
Smith
Mark
David
Jones
Jack
I would like the output to be this: Output only first names, but if Table A doesn't record if it's a first or last name, output it anyway. The correct output would be:
Jeremy
Mark
David
Jones
Jack
I've tried accomplishing this with an outer join, like so:
select
B.Name
from
A, B
where
A.name = B.name(+) and
A.FirstOrLast = 'First';
but no luck. How can I do this?

When you perform a left outer join and there is no record in A, a.firstOrLast will be null. While you're at it, you might as well switch to the standard syntax for joins:
select
B.Name
from
B
left outer join A on A.name = B.name
where
A.firstOrLast is null or A.firstOrLast = 'First';
However, the old syntax should also work:
select
B.Name
from
A, B
where
A.name = B.name(+) and
(A.firstOrLast is null or A.firstOrLast = 'First');

Try this:
SELECT B.Name
FROM B LEFT JOIN A ON B.Name = A.Name
WHERE A.FirstOrLast = 'First' OR A.Name IS NULL;

select b.name
from b
union
select a.namfe
from a
where a.firstOrLast = 'First'

SELECT Name
FROM B
MINUS
SELECT Name
FROM A
WHERE FirstOrLast <> 'First'

Related

SQL for 2 tables

I have these 2 tables:
Table A
Country State
-----------------
US OH
US FL
US WA
Table B
State LastVisitDate City
----------------------------------
OH 15/10/2019 Bedford
FL 10/12/2019 Bell
WA 20/09/2019 Perth
Table A can be linked with table B by field "State".
What would be the query to get the latest (last visit date) in country=US, doesn't matter which state, e.g.:
US,10-12-2019,FL,Bell
I tried inner join but couldn't make it work.
Always try to explain your question with sample data and query you tried for.
Here is query with some sample data:
CREATE TABLE A
(
COUNTRY VARCHAR(10),
State VARCHAR(10)
);
INSERT INTO A VALUES('US','OH'),
('US','FL'),
('AU','WA');
CREATE TABLE B
(
State VARCHAR(10),
LastVisitDate DATE,
City VARCHAR(20)
);
INSERT INTO B VALUES
('OH','2019-10-15','Bedford'),
('FL','2019-12-10','Bell'),
('WA','2019-09-20','Perth');
Expected Result:
US,10-12-2019,FL,Bell
Query:
SELECT a.COUNTRY,b.LastVisitDate,b.State,b.City
FROM A
INNER JOIN B ON a.State = b.State
WHERE a.COUNTRY = 'US'
ORDER BY b.LastVisitDate DESC
Limit 1;
SQL Fiddle
Before you try below code you must be reformat last visited date table structure like YYYY/MM/DD in SQL Table and you must replace actual tables name and columns name in below query.
SELECT MAX(table_b.last_visited_date) AS last_visited_date
FROM table_a
INNER JOIN table_b
ON table_a.state = table_b.state WHERE table_a.country = 'US' Limit 1;
Try this below script-
Note: As Tanmay said, you need to reformat your date values to get the correct output.
DEMO HERE
SELECT N.country,
N.mx_date LastVisitDate,
B.City,
B.State
FROM
(
SELECT Country,MAX(LastVisitDate) mx_date
FROM Table_A A
INNER JOIN Table_B B ON A.State = B.State
GROUP BY Country
)N
INNER JOIN Table_A A ON A.Country = N.Country
INNER JOIN Table_B B ON A.State = B.State
WHERE N.mx_date = B.LastVisitDate
SELECT top 1(country,
last_visit_date)
FROM A
JOIN B ON A.State = B.State
WHERE A.Country ="Country Name"
ORDER BY B.Last_visit_Date DESC

Find diff between three tables

I'm trying to find the difference between three tables, a, b, and c. I'd like to join all three, showing nulls where each table does not have records.
Each table has two columns that I would like to join on, lets say first and last name.
So far, this is what I'm doing.
Select * from a
FULL OUTER JOIN b on
a.firstName = b.firstName AND a.lastname = b.lastname
FULL OUTER JOIN c on
(c.firstName = a.firstName and c.lastName = a.LastNAME) OR
(c.firstName = b.firstName AND c.lastname = b.LastName)
I'm not confident that the logic in my output is correct. Is there a better way of doing this? In english, the first join joins A and B, including records in each table that don't exist in the other table. The second join joins A+B to C, joining C to either A or B if it matches.
You may want:
select firstname, lastname, sum(in_a), sum(in_b), sum(in_c)
from ((select firstname, lastname, 1 as in_a, 0 as in_b, 0 as in_c
from a
) union all
(select firstname, lastname, 0 as in_a, 1 as in_b, 0 as in_c
from b
) union all
(select firstname, lastname, 0 as in_a, 0 as in_b, 1 as in_c
from c
)
) abc
group by firstname, lastname;
This should each firstname/lastname pair with information about how many times the pair is in each table.
I prefer the union all/group by approach for this over left join for several reasons:
Without the using clause, the on clause gets a bit tricky as you add more tables.
Minimal use of coalesce().
Better handles duplicates within each table.
Handles NULL values for the keys.

Joining two tables and display data from first table

I have two tables tblPatient, tblDropDowns
tblpatient:
firstname gender patienttype
anil 1 3
Satheesh 1 4
Vinod 1 4
Shashikanth 1 3
Srimani 2 3
Thanuja 2 4
Nandini 2 4
Vishu 2 3
and
tblDropdowns:
id Name
1 Male
2 Female
3 Inpatient
4 Outpatient
Now i want to display the patient table with gender and patient type as their significant names are connected to dropdown table.
result table:
firstname gender patienttype
anil male inpatient
satheesh male outpatient
vinod male outpatient
please help me out..
thanks
anil
In general it would be better avoid storing different things in the same table. However, you could join with subqueries that only contain the relevant records.
SELECT firstname, gender.Name AS gender, patienttype.Name As patienttype
FROM tblPatient p
INNER JOIN (SELECT id, Name
FROM tblDropdowns
WHERE id IN (1, 2)) gender
ON p.gender = gender.id
INNER JOIN (SELECT id, Name
FROM tblDropdowns
WHERE id > 2) patienttype
ON p.patienttype = patienttype.id
Please try out this.
select [column1], [column2] from tblpatient a, tbldropdowns b
where a.gender = b.id order by a.gender;
You could also use joins: Please refer this W3Schools SQL Link.
Hope this helps. Thanks.
Edit
Maybe this query could be your solution:
select a.firstname, b.name as 'gender', b.name as 'PatientType'
from tblpatient a, tbldropdowns b
where a.gender = b.id and a.patienttype = b.id
order by a.gender;
Thanks again. :-)
Try as follows:
SELECT firstname, name, CASE WHEN (patienttype=3) THEN 'inpatient' ELSE 'outpatient' END as patienttype_text from tblpatient INNER JOIN tbldropdowns ON gender = id
join your "tblDropdowns" table twice in your select query.
Please refer this link to understand join,
http://www.w3schools.com/sql/sql_join_left.asp
select tP.firstname,tG.Name gender,tPT.Name patienttype
from tblPatient tP
left join tblDropDowns tG
on tG.id = tP.gender
left join tblDropDowns tPT
on tPT.id = tP.patienttype

In a left join, select row with value A, if not select row with value B

This must be simple, but I think I'm lost. I have a table A:
name id
Tom 1
Barbara 2
Gregory 3
...and table B:
id nickname preferred
1 Spiderman 0
1 Batman 1
2 Powerpuff 0
3 Donald Duck 0
3 Hulk 1
How do I query the table to get a nickname when it is preferred (1), or any other nickname if preferred is not available.
So the result for Tom would be "Batman", while the result for Barbara would be "Powerpuff".
Just an immediate solution:
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 1
union all
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 0
where a.id not in(
select a.id
from a
join b on a.id = b.id and b.prefered = 1
)
Fiddle http://sqlfiddle.com/#!7/0b7db/1
Try below Query:
Which 1. selects row with value A, otherwise, 2. select row with value B
using LEFT JOIN,
SELECT A.name, B.nickname
FROM A
LEFT JOIN
(
SELECT MAX(preferred) AS preferred, id
FROM B
GROUP BY id
)AS B1
ON A.id = B1.id
LEFT JOIN B ON B.preferred = B1.preferred AND B.id = B1.id
If SQLite supported analytic functions then that would provide a fairly clean and convenient solution. No such luck, though. It does simplify the problem that you want either all the preferred nicknames for a given person (of which there will be at most one) or all the non-preferred ones. It is then fairly straightforward to use an inline view to distinguish between those cases and apply a suitable filter:
SELECT p.name, pn.nickname
FROM
person p
JOIN (
SELECT id, MAX(preferred) AS preferred
FROM person_nickname
GROUP BY id
) flag
ON p.id = flag.id
JOIN person_nickname pn
ON pn.id = flag.id AND pn.preferred = flag.preferred

Sql query with multiple condition but some of item is not available in certain table

I am facing problem with sql query when I try to join this tree table and get the data. I am using Oracle database.
Personal
id_no name
-------------
0001 John
0002 Peter
0003 Mike
position
id_no name
-------------
0001 programmer
0002 Engineer
0003 Clerk
extra_skill
employee_id skill
--------------------------
0001 Visual Studio 2008
0003 Crystal Report
Requirement:
Display details of employees:
Example:
Employee No : 0001
Employee Name : John
Employee Position : Programmer
Employee Skill : Visual Studio 2008
My sql statement is
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "USER INPUT";
The problem is when
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id = "0002";
This query give me NULL because in the table extra_skill does not have 0002.
I want it possible to get data even in the third table no value.
Expected result:
Employee No : 0002
Employee Name : Peter
Employee Position : Engineer
Employee Skill :
How can I implement such a query?
Your attentions and helps are much appreciated.
Thank you, Siti..:)
The way to do this is with outer joins. I have used the ANSI joining syntax (introduced in Oracle 9i) for this example, because it is clearer and also Oracle now recommend using it.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id )
WHERE a.id_no = '0002';
Note that I have changed the filter condition to select on PERSONAL.ID. If you attempt to use c.employee_id = '0002' (as you do in your question) you will get no rows returned.
You could include EXTRA_SKILLS.EMPLOYEE_ID in the join condition rather than the WHERE clause.
SELECT a.id_no, a.name, b.name as position, c.skill
FROM personal a INNER JOIN position b
on (a.id_no = b.id_no )
LEFT OUTER JOIN extra_skill c
on ( a.id_no = c.employee_id
and c.employee_id = '0002');
Generally including filters in the join section is not considered good practice, because it can effect the result set in ways we're not expecting. In your case it will return every row in PERSONAL and POSITION and no values from EXTRA_SKILL. This is probably not what you want to happen. Here is a SQL Fiddle to prove it.
You will have to use an outer join.
The purpose of an outer join is to include non-matching rows, and the outer join returns these missing columns as NULL values.
SELECT a.id_no, a.name, b.name, c.skill
FROM personal a, POSITION b, extra_skill c
WHERE a.id_no = b.id_no
AND b.id_no = c.employee_id
AND c.employee_id(+) = "USER INPUT";