In my query I want to get the rows from two different tables descending by their primary keys. They have two different keys so is it possible to be able to do this in one query?
Your question is a little vague. To "get rows from two different tables" you can do a JOIN, or you can do a UNION.
In the case of a JOIN:
SELECT a.id, a.something, b.id, b.something
FROM a
INNER JOIN b ON b.aId = a.id
ORDER BY a.id, b.id
In the case of a UNION:
SELECT id, something
FROM (
SELECT a.id. a.something FROM a
UNION
SELECT b.id, b.something FROM b
) t
ORDER BY t.id
These are very different, but it seems like one of them will meet your needs.
(Note that UNION by default eliminates duplicates. Use UNION ALL to keep duplicates.)
SELECT *
FROM ( select a.pk, a.foo, a.bar from a
union
select b.pk, b.foo, b.bar from b
) c
ORDER BY c.pk DESC;
Related
I have 3 tables. All of them have a column - id. I want to find if there is any value that is common across the tables. Assuming that the tables are named a.b and c, if id value 3 is present is a and b, there is a problem. The query can/should exit at the first such occurrence. There is no need to probe further. What I have now is something like
( select id from a intersect select id from b )
union
( select id from b intersect select id from c )
union
( select id from a intersect select id from c )
Obviously, this is not very efficient. Database is PostgreSQL, version 9.0
id is not unique in the individual tables. It is OK to have duplicates in the same table. But if a value is present in just 2 of the 3 tables, that also needs to be flagged and there is no need to check for existence in he third table, or check if there are more such values. One value, present in more than one table, and I can stop.
Although id is not unique within any given table, it should be unique across the tables; a union of distinct id should be unique, so:
select id from (
select distinct id from a
union all
select distinct id from b
union all
select distinct id from c) x
group by id
having count(*) > 1
Note the use of union all, which preserves duplicates (plain union removes duplicates).
I would suggest a simple join:
select a.id
from a join
b
on a.id = b.id join
c
on a.id = c.id
limit 1;
If you have a query that uses union or group by (or order by, but that is not relevant here), then you need to process all the data before returning a single row. A join can start returning rows as soon as the first values are found.
An alternative, but similar method is:
select a.id
from a
where exists (select 1 from b where a.id = b.id) and
exists (select 1 from c where a.id = c.id);
If a is the smallest table and id is indexes in b and c, then this could be quite fast.
Try this
select id from
(
select distinct id, 1 as t from a
union all
select distinct id, 2 as t from b
union all
select distinct id, 3 as t from c
) as t
group by id having count(t)=3
It is OK to have duplicates in the same table.
The query can/should exit at the first such occurrence.
SELECT 'OMG!' AS danger_bill_robinson
WHERE EXISTS (SELECT 1
FROM a,b,c -- maybe there is a place for old-style joins ...
WHERE a.id = b.id
OR a.id = c.id
OR c.id = b.id
);
Update: it appears the optimiser does not like carthesian joins with 3 OR conditions. The below query is a bit faster:
SELECT 'WTF!' AS danger_bill_robinson
WHERE exists (select 1 from a JOIN b USING (id))
OR exists (select 1 from a JOIN c USING (id))
OR exists (select 1 from c JOIN b USING (id))
;
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 *
I have a query like below:
select
a.id, a.title, a.description
from
my_table_name as a
where
a.id in (select id from another_table b where b.id = 1)
My question is, is there any way I can avoid the subquery in where clause and use it in from clause itself without compromising of performance?
Both of the answers given so far are incorrect in the general case (though the database may have unique constraints which ensure they are correct in a specific case)
If another_table might have multiple rows with the same id then the INNER JOIN will bring back duplicates that are not present in the IN version. Trying to remove them with DISTINCT can change the semantics if the columns from my_table_name themselves have duplicates.
A general rewrite would be
SELECT a.id,
a.title,
a.description
FROM my_table_name AS a
JOIN (SELECT DISTINCT id
FROM another_table
WHERE id = 1) AS b
ON b.id = a.id
The performance characteristics of this rewrite are implementation dependant.
You may use INNER JOIN as:
select
a.id, a.title, a.description
from
my_table_name as a INNER JOIN another_table as b ON (a.id = b.id and b.id = 1)
Or
select
a.id, a.title, a.description
from
my_table_name as a INNER JOIN another_table as b ON a.id = b.id
where b.id = 1
Both the queries may not return the same value for you. You may choose whatever works for you. Please use this as a starting point and not as a copy-paste code.
To express it as a join:
select distinct
a.id, a.title, a.description
from my_table_name as a
join another_table b on b.id = a.id
where b.id = 1
The use of distinct is to produce the same results in case another_table has the same id more than once so the same row doesn't get returned multiple times.
Note: if combinations of id, name and description in my_table_name are not unique, this query won't return such duplicates as the original query would.
To guarantee to produce the same results, you need to ensure that the id's in another_table is unique. To do this as a join:
select
a.id, a.title, a.description
from my_table_name as a
join (select distinct id from another_table) b on b.id = a.id
where b.id = 1
I want to union to tables and join them with a third metadata table and I would like to know which approach is the best/fastest?
The database is a PostgreSQL.
Below is my two suggestions, but other approaches are welcome.
To do the join before the union on both tables:
SELECT a.id, a.feature_type, b.datetime, b.file_path
FROM table1 a, metadata b WHERE a.metadata_id = b.id
UNION ALL
SELECT a.id, a.feature_type, b.datetime, b.file_path
FROM table2 a, metadata b WHERE a.metadata_id = b.id
Or to do the union first and then do the join:
SELECT a.id, a.feature_type, b.datetime, b.file_path
FROM
(
SELECT id, feature_type, metadata_id FROM table1
UNION ALL
SELECT id, feature_type, metadata_id FROM table2
)a, metadata b
WHERE a.metadata_id = b.id
Run an EXPLAIN ANALYZE on both statements then you will see which one is more efficient.
it can be unpredictable due to sql-engine optimizator. it's better to look at the execution plan. finally both approaches can be represented in the same way
In so far as I can remember, running Explain will reveal that PostgreSQL interprets the second as the first provided that there is no group by clause (explicit, or implicit due to union instead of union all) in any of the subqueries.
I'm trying to construct a select query where it will take all the columns of 4 tables and then order and display the results by the column 'name' (the same in all tables). I'm still learning the ropes of MySQL.
I'm finding that because the columns share the name 'name', only the results from the last table are displayed. Is there a way of performing this query which retains all the data from all the tables?
Should I use different column names? It seems easier to share one name since it is the same information in each.
SELECT * FROM table_one, table_two, table_three, table_four ORDER BY...
The four tables not joined, and the structure is different... Some column names are shared (which it looks like I should fix, I still can at this point), but each has a different amount of columns.
Thank you!
If there's no relationship between the four tables, use UNIONs instead:
SELECT a.name
FROM TABLE_ONE a
UNION
SELECT b.name
FROM TABLE_TWO b
UNION
SELECT c.name
FROM TABLE_THREE c
UNION
SELECT d.name
FROM TABLE_FOUR d
ORDER BY name
There's two options here - UNION is slower, because it will remove duplicates - the final list will be a unique list of names. UNION ALL is faster because it doesn't remove duplicates.
To get the columns from the tables as well, use:
SELECT a.*,
b.*,
c.*,
d.*
FROM (SELECT a.name
FROM TABLE_ONE a
UNION
SELECT b.name
FROM TABLE_TWO b
UNION
SELECT c.name
FROM TABLE_THREE c
UNION
SELECT d.name
FROM TABLE_FOUR d) x
LEFT JOIN TABLE_ONE a ON a.name = x.name
LEFT JOIN TABLE_TWO b ON b.name = x.name
LEFT JOIN TABLE_THREE c ON c.name = x.name
LEFT JOIN TABLE_FOUR d ON d.name = x.name
Yes you should use different column names, but to get all data also you can write quesries like this:
SELECT table_one.* t1, table_two.* t2, table_three.* t3, table_four.* t4 FROM table_one, table_two, table_three, table_four ORDER BY...
johnny_n,
You should use
SELECT name as name1, name as name2, name as name3 etc...
Obviously you need to use the correct syntax, but using the AS keyword, will allow you to use the key you want in your query.
If they all share the same name's....
SELECT *
FROM table_one
LEFT JOIN
table_two USING(name)
LEFT JOIN
table_three USING(name)
LEFT JOIN
table_four USING(name)
ORDER BY name