Select Name instead OF ID in table with ID-Ref Column SQL - sql

Lets say we have 2 Tables:
Table A Table B
- A_ID - B_ID
- A_Name - A_ID
I need a select statement, that selects * from Table B showing the A_NAME instead of the A_ID.
By trying it I got the following select statement which ... doesn't work to well. It is giving me a lot of nulls, but no names.
SELECT B_ID,
(select A_NAME from TableA as A where A.A_ID = B.A_ID) as Name
FROM TableB as B
Thanks for all your Answers.
The final solution:
The shown query DOES work (even though it may be slow) and the solutions in the answers also do work.
The problem why it didn't give results for me was because of my data. On another database with the same schema all the commands work.

You should try LEFT JOIN
SELECT
B_ID, A_Name
FROM
tableB B LEFT JOIN tableA A
ON B.A_ID = A.A_ID

you can do it with a join:
SELECT B.B_ID, A.A_Name
FROM B
INNER JOIN A
ON A.A_ID = B.A_ID;
Edit:
If you want only the entries from table b you can to it with a left join, like #jarlh said:
SELECT B.B_ID, A.A_Name
FROM B
LEFT JOIN A
ON A.A_ID = B.A_ID;

Related

SQL Get rows that doesn't appear in another table

I have this SQL problem: I have tables A and B. Table A has columns id and name, Table B amount and id which is a foreign key to table A.id.
I need to return all table A rows that don't have their id stored in table B. Any ideas?
So the complete opposite is:
SELECT *
FROM a
LEFT OUTER JOIN b ON a.id = b.id;
Here row what I need is left out of result
Just add a where clause:
SELECT a.*
FROM a LEFT OUTER JOIN
b
ON a.id = b.id
WHERE b.id IS NULL;
You can also use NOT EXISTS:
select a.*
from a
where not exists (select 1 from b where b.id = a.id);
In most databases, the two methods typically have similar performance.

SQL Query Duplicating records

I've got two tables.
Let's call them table_A and table_B.
Table_B contains the ForeignKey of table_A.
Table_A
ID Name
1 A
2 B
3 C
Table_B
ID table_a_fk
1 2
2 3
Now I want to get all the names out of table_a IF table_b does not contain the ID of the record in table_a.
I've tried it with this query:
SELECT a.name
FROM table_a a, table_b b
WHERE a.id != b.table_a_fk
With this Query I'm getting the right result I just get this result like 5times and I don't know why.
Hope someone can explain me that.
Your query creates a cartesian product between your two tables A and B. It is the cartesian product that generates those duplicate values. Instead, you want to use an anti-join, which is most commonly written in SQL using NOT EXISTS
SELECT a.name
FROM table_a a
WHERE NOT EXISTS (
SELECT *
FROM table_b b
WHERE a.id = b.table_a_fk
)
Another way to express an anti-join with NOT IN (only if table_b.table_a_fk is NOT NULL):
SELECT a.name
FROM table_a a
WHERE a.id NOT IN (
SELECT b.table_a_fk
FROM table_b b
)
Another, less common way to express an anti-join:
SELECT a.name
FROM table_a a
LEFT OUTER JOIN table_b b ON a.id = b.table_a_fk
WHERE b.id IS NULL
use distinct
SELECT distinct a.name
FROM table_a a, table_b b
WHERE a.id != b.table_a_fk
or better is...
Select distinct name
from tableA a
Where not exists (Select * from tableB
Where table_a_fk = a.id)

Oracle SQL WITH clause select joined column

SQL:
WITH joined AS (
SELECT *
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
returns invalid identifier.
How can you select joined column when using WITH clause? I have tried aliases, prefixing and nothing worked. I know I can use:
WITH joined AS (
SELECT a.a_id
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id
FROM joined
but I need this alias to cover all fields.
Only way I managed to meet this condition is using:
WITH joined AS (
SELECT a.a_id a_id_alias, a.*, b.*
FROM table_a a
JOIN table_b b ON (a.a_id = b.a_id)
)
SELECT a_id_alias
FROM joined
but it is not perfect solution...
You can use the effect of the USING clause when joining the tables.
When you join tables where the join columns have the same name (as it is the case with your example), the USING clause will return the join column only once, so the following works:
with joined as (
select *
from table_a a
join table_b b using (a_id)
)
select a_id
from joined;
SQLFiddle example: http://sqlfiddle.com/#!4/e7e099/2
I don't think you can do this without aliases. The result of the "joined" query has two fields, both named a_id. Unless you alias one (or both), as you did in your final query, the outer query has no idea which a_id you are referring to.
Why is your final query not a "perfect" solution?
You can probably use alias as below:
WITH JOINED AS (
SELECT A.A_ID A_A_ID, B.A_ID B_A_ID,
A.FIELD_NAME1 A_FIELDNAME1, A.FIELDNAME2 A_FIELDNAME2,A.FIELDNAME_N A_FIELDNAME_N,
B.FIELD_NAME1 B_FIELDNAME1, B.FIELDNAME2 B_FIELDNAME2,B.FIELDNAME_N B_FIELDNAME_N,
FROM TABLE_A A
JOIN TABLE_B B ON (A.A_ID = B.A_ID)
)
SELECT A_A_ID, B_A_ID
FROM JOINED
IT IS ALWAYS A GOOD PRACTICE TO AVOID USING SELECT *

Join and showing different columns from tables

I have a simple SQL question, I thought it would be quite straight forward but have got myself in a muddle. Any help would be appreciated
I have table A which contains a last updated
Table A has a one to many with Table B
Table B has a one to many with Table C
I want to show all rows of table C with the last updated time from table A. I have tried some joins but they dont seem to be quite working. Ideally I want somehting like
select a.lastUpdated c.* from TableA a, TableC c where
a.id in (select a_id from TableB where (select b_id from TableC where c_id = select
id from TableC where XXXX=YYYY))
so I can pass in an id for table C and then get one row returned with the last updated time present.
XXX=YYY would be my criteria for returning one row of table C.
Any help or pointers appreciated
Thanks
Something like
SELECT c.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.a_id = b.b_id
INNER JOIN TableC AS c
ON b.b_id = c.c_id
WHERE a.lastUpdated = c.lastUpdated;
Should work. This is a situation where a striaght INNER JOIN should suffice; unless of course I have missed something.
I hope this helps.
You should be able to do this by joining A and B together, aggregating the results at the c_id level, and then joining in C:
select tc.*, maxlastupdated
from tablec tc left outer join
(select tb.c_id, max(lastupdated) as maxlastupdated
from tablea ta join
tableb tb
on ta.b_id = tb.b_id
group by ta.id
) ta
on tc.c_id = ta.c_id
You need to drive your SQL query from Table C.
The query below displays the updated timestamp column from table A.
Since it is a one-to-many in the direction of tables A --> B --> C
You will inevitably end-up with a lot of rows in table C - all with the same timestamp.
SELECT c.*, a1.update_timestamp
FROM table_c c, table_b b, table_a a1
WHERE c.join_column = b.join_column
AND b.join_column = a1.join_column
AND a1.update_timestamp =
(SELECT max(a2.update_timestamp) FROM table_a a2
WHERE a2.<identifying columns> = a1.<identifying columns>
);

How do I find records that are not joined?

I have two tables that are joined together.
A has many B
Normally you would do:
select * from a,b where b.a_id = a.id
To get all of the records from a that has a record in b.
How do I get just the records in a that does not have anything in b?
select * from a where id not in (select a_id from b)
Or like some other people on this thread says:
select a.* from a
left outer join b on a.id = b.a_id
where b.a_id is null
select * from a
left outer join b on a.id = b.a_id
where b.a_id is null
The following image will help to understand SQL LET JOIN :
Another approach:
select * from a where not exists (select * from b where b.a_id = a.id)
The "exists" approach is useful if there is some other "where" clause you need to attach to the inner query.
SELECT id FROM a
EXCEPT
SELECT a_id FROM b;
You will probably get a lot better performance (than using 'not in') if you use an outer join:
select * from a left outer join b on a.id = b.a_id where b.a_id is null;
SELECT <columnns>
FROM a WHERE id NOT IN (SELECT a_id FROM b)
In case of one join it is pretty fast, but when we are removing records from database which has about 50 milions records and 4 and more joins due to foreign keys, it takes a few minutes to do it.
Much faster to use WHERE NOT IN condition like this:
select a.* from a
where a.id NOT IN(SELECT DISTINCT a_id FROM b where a_id IS NOT NULL)
//And for more joins
AND a.id NOT IN(SELECT DISTINCT a_id FROM c where a_id IS NOT NULL)
I can also recommended this approach for deleting in case we don't have configured cascade delete.
This query takes only a few seconds.
The first approach is
select a.* from a where a.id not in (select b.ida from b)
the second approach is
select a.*
from a left outer join b on a.id = b.ida
where b.ida is null
The first approach is very expensive. The second approach is better.
With PostgreSql 9.4, I did the "explain query" function and the first query as a cost of cost=0.00..1982043603.32.
Instead the join query as a cost of cost=45946.77..45946.78
For example, I search for all products that are not compatible with no vehicles. I've 100k products and more than 1m compatibilities.
select count(*) from product a left outer join compatible c on a.id=c.idprod where c.idprod is null
The join query spent about 5 seconds, instead the subquery version has never ended after 3 minutes.
Another way of writing it
select a.*
from a
left outer join b
on a.id = b.id
where b.id is null
Ouch, beaten by Nathan :)
This will protect you from nulls in the IN clause, which can cause unexpected behavior.
select * from a where id not in (select [a id] from b where [a id] is not null)