Stop returning multiple similar rows on joins - sql

I have the following scenario in SQLite.
TableA
ID
-----
1 |
2 |
3 |
Table B
ID | AID |Tag
----------------
1 | 1 | Hide
2 | 1 | Show
3 | 2 | Null
4 | 3 | Show
Table B has column AID which is the IDs of table A.
In the example above
Table A ID: '1' has
-> Table B ID of '1' and '2' and Tags 'Hide' and 'Show' attached to it.
I am looking for an SQL that will only return, in the example above, Table A IDs: '2' and '3'.
Basically, as TableA ID: '1' has a 'Hide' tag attached to it, don't return it (even though it also has a show tag attached to it)
The SQL I am using is (excuses the names, this is just a quick example)
select
a.ID as a_ID,
b.ID as b_ID,
b.Tag as Tag
from
Table A as a
left join Table B on a.id = b.aID
and b.tag != 'hide'
The problem with this SQL it's still returning
a_ID | b_ID | Tag
-------------------------------
1 | 2 | Show
I'm a tad stuck and any help would be really appreciated. I'm not 100% sure how I would work this on for a google search.
The closest I got was this question How to return only 1 row if multiple duplicate rows and still return rows that are not duplicates?
but I couldn't work out how the GROUP BY would help here.

You're looking for an id where no row exists with a 'hide' tag. This is a direct translation into SQL:
select *
from TableA as a
where not exists
(
select *
from TableB as B
where a.id = b.aID
and b.tag = 'hide'
)
Or, if you want the data from TableB:
select *
from TableB as t1
where not exists
(
select *
from TableB as t2
where t1.aID = t2.aID
and t2.tag = 'hide'
)

You could use an extra condition with the exists operator:
SELECT a.ID AS a_ID, b.ID AS b_ID, b.Tag AS Tag
FROM table_a a
LEFT JOIN table_b b ON a.id = b.aID
WHERE NOT EXISTS (SELECT *
FROM table_b bin
WHERE bin.aID = a.ID AND bin.Tag = 'hide')

Related

How can I get full results in SQL query using 3 tables, where 1 of them keeps relation of 2 another?

I need help writing a query to display results I want.
"Table 3 - relations" keeps all relations between table 1 and 2.Often, relation between table 1 and 2 will not exist in table 3 so I want to see missing relation in the results for all Table 1 rows - see expected Results below.
I can't modify these tables - I have only SELECT privilege.
Data and expected result below:
Table 1 - a:
a_id, a_name
e.g.:
1 A
2 B
Table 2 - b:
b_id, b_name
e.g.:
1 X
2 Y
Table 3 - relation:
asset1_id (it's always id from Table 1), asset2_id (it's always id from Table 2), relation_type
e.g.:
1 1 covers
1 2 covers
Expected result:
Table1_name, Table2_name, Table3_relation_type (including NULL for b_name and relation_type when such relation does not exist in Table 3 - relation)
e.g.
A X covers
A Y covers
B NULL NULL
I can't get the 3rd expected line with NULLs.
I think that this query will produce those results.
select a.name as a_name,b.name as b_name, r.relation_type from relation r
join a on a.id=r.asset1_id
join b on b.id=r.asset2_id
union
select a.name as a_name,b.name as b_name,r.relation_type from relation r
full outer join a on a.id=r.asset1_id
full outer join b on b.id=r.asset2_id
where a.id is null or b.id is null
With your data sample you could try this one.
It should work both hive or impala.
SELECT t1.name ,t2.name ,r.relation_type
FROM relation r
FULL OUTER JOIN table1 t1 ON(t1.id = r.id1)
FULL OUTER JOIN table2 t2 ON(t2.id = r.id2);
+------+------+---------------+
| name | name | relation_type |
+------+------+---------------+
| A | X | covers |
| A | Y | covers |
| B | NULL | NULL |
+------+------+---------------+
WITH
cte_A AS (
SELECT id as a_id, name as a_name
FROM a
),
cte_C AS (
SELECT c.asset_id1 as a_id, b.name, c.relation
FROM c
LEFT JOIN b ON c.id=b.asset_id2
)
SELECT cte_A.a_name, cte_C.name as c_name, cte_C.relation
FROM cte_A
LEFT JOIN cte_C ON cte_A.a_id=cte_C.a_id

Update select using the max of one column Postgresql

So I'm changing a db structure. I'm moving a column, 'size', from table_B to table_A.
Table_B can have multiple entries referencing table_A.a_id
I want to update the new 'size' column in table_A from table_B with the row with the highest b_id.
So I can use Max() and group by to select just the highest b_ids for each a_id.
SELECT max(b_id)
FROM table_B
GROUP BY a_id;
But I'm not sure how to fit that in with the update select
UPDATE table_A
SET table_A.size = table_B.size
FROM table_A, table_B
WHERE table_A.a_id = table_B.a_id
AND table_B.b_id =
(
max...
);
edit:
I realise now this actually isn't an update select, my first attempt was
How table_B looks and the expected result in table_A
table_A
a_id | size
-------------------------
1 | 5678
2 | 456
table_B
b_id | a_id | size
--------------------------------------
1 | 1 | 1234
2 | 1 | 5678
3 | 2 | 456
First, write a select to get the size you want:
select distinct on (b.a_id) b.a_id, b.size
from tableb b
order by b.a_id, b.b_id desc;
Next, incorporate this into the update:
update tablea a
set size = b.size
from (select distinct on (b.a_id) b.*
from tableb b
order by b.a_id, b.b_id desc
) b
where a.a_id = b.a_id;
you can try the following query
UPDATE table_A
SET table_A.size =
( SELECT table_B.size
FROM table_B B1
WHERE table_A.a_id = B1.a_id AND
B1.b_id = (SELECT max(b_id) FROM table_B B2 WHERE table_A.a_id=B2.a_id))

SQL query - select row basing on the joined table's criteria

I'm stuck within this simple scenario:
tableA
| ID | TableB_ID | Name |
tableA 1 ---> * tableB
tableB
| ID | Status_ID |
and I need to retrieve the Name column values from the tableA, whose contains rows in the tableB with Status_ID = 1 and Status_ID = 2 (two separate rows, it can be more with other values but it doesn't matter here)
Try this:
SELECT A.NAME
FROM TABLE_A AS A INNER JOIN TABLE_B AS B ON A.TABLEB_ID = B.ID
WHERE B.STATUS_ID IN (1, 2) -- OR OTHER VALUES

SQL query - select uncommon values from 2 tables

Today I was asked following question in my interview for a QA and because of incorrect query, I did not get selected. From then on, my mind is itching to get the correct answer for the following scenario:
I was given following 2 tables:
Tabel A | |Table B
--------- ----------
**ID** **ID**
-------- -----------
0 | | 5 |
1 | | 6 |
2 | | 7 |
3 | | 8 |
4 | | 9 |
5 | | 10|
6 | -----
----
And following output was expected using an SQL query:
**ID**
--------
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 7 |
| 8 |
| 9 |
| 10 |
--------
Thanks everyone, I really like this forum and from now on will be active here to learn more and more about SQL. I would like to make it my strong point rather a weak so as not to get kicked out of other interviews. I know there is a long way to go. However beside all of your responses, I came to draft the following query and would like to know from the experts here of their opinion about my query (and the reason why they think of what they think):
BTW the query has worked on MSSQLSRV-2008 (using Union or Union All, didn't matter to the result I got):
select ID from A where ID not in (5,6)
union
select ID from B where ID not in (5,6)
Is this really an efficient query?
If you want values in only one of two tables, I would use a full outer join and condition:
select coalesce(a.id, b.id)
from tableA a full outer join
tableB b
on a.id = b.id
where a.id is null or b.id is null;
Of course, if the job at a company that uses MS Access or MySQL, then this isn't the right answer, because these systems don't support full outer join. You can also do this in more complicated ways using union all and aggregation or even with other methods.
EDIT:
Here is another method:
select id
from (select a.id, 1 as isa, 0 as isb from tablea union all
select b.id, 0, 1 from tableb
) ab
group by id
having sum(isa) = 0 or sum(isb) = 0;
And another:
select id
from tablea
where a.id not in (select id from tableb)
union all
select id
from tableb
where b.id not in (select id from tablea);
As I think about this, it is a pretty good interview question (even though I've just given three reasonable answers).
Edit: See Gordon answer above for a better request, this is very inneficient way of doing what you want.
I think this should do the trick :
(SELECT * FROM A WHERE NOT id IN (SELECT A.id FROM A, B WHERE A.id = B.id))
UNION
(SELECT * FROM B WHERE NOT id IN (SELECT A.id FROM A, B WHERE A.id = B.id))
You could avoid the duplication of SELECT A.id ...by using a temporary table.
without full outer joins...
Select id
from (Select id from tableA
Union all
Select id from tableB) Z
group by id
Having count(*) = 1
or using Except and Intersect .....
(Select id from tableA Except Select id from tableB)
Union
(Select id from tableB Except Select id from tableA)
or ....
(Select id from tableA union Select id from tableB)
Except
(Select id from tableA intersect Select id from tableB)

Join 2 Tables and display everything

I have 2 simple tables:
table a:
id | txt
---+----
0 | aaa
1 | bbb
2 | ccc
table b:
id | tel
---+----
0 | 000
2 | 111
I am trying to join 2 tables like this:
SELECT a.*,b.*
FROM a,b
WHERE a.id=b.id
It works, but, if there is no entry in the "b" table it wont show anything.
what the sql shows is something like this:
id | txt | tel
---+-----+----
0 | aaa | 000
2 | ccc | 111
I also want to list the "empty" row a.id=1:
id | txt | tel
---+-----+-----
1 | bbb | NULL
Any ideas? Thanks!
(SQL is for MS Access / oledb)
You want a left outer join (or a full outer join, if you want rows in which there is no entry in the a table also).
SELECT a.*,b.* FROM a LEFT OUTER JOIN b ON a.id=b.id
Depending the system, the syntax LEFT JOIN may work as well.
In MSAccess query designer, right click on the relationship connection between the two tables, and edit its properties. Modify it to 'show all records from table a'.
This:
SELECT a.*,b.*
FROM a, b
WHERE a.id = b.id
...is ANSI-89 inner join syntax, and I highly recommend using ANSI-92 syntax instead:
SELECT a.*,
b.*
FROM TABLE_A a
JOIN TABLE_B b ON b.id = a.id
...mostly because ANSI-88 syntax for left joining to tables wasn't consistently implemented on various databases. This will return the results you expect:
SELECT a.id,
a.txt,
b.tel
FROM TABLE_A a
LEFT JOIN TABLE_B b ON b.id = a.id
A LEFT JOIN means you'll get all the records from TABLE_A in this example, and when there is a matching record (based on the ON criteria) in TABLE_B, the value will be displayed. Otherwise, the TABLE_B column references will return NULL values.
For more information on JOINs, see this page for a great pictorial demonstration of what each one represents and how they compare.