How do I write a query which based on hierarchies? - sql

Suppose I have a table t1 with:
ID CODE
1 A
1 B
1 C
2 C
2 D
And another table t2 that provides me the hierarchies. (so what inferior really means is that if code A, B and C all exist for a specific ID, we should really only use code A. and if code C and D both exist, we should really only use code C)
CODE INFERIOR
A B
A C
C D
How do I write the query in plsql that give me the following results?
ID CODE
1 A
2 C

Current query is for SQL-Server 2008, if there's any issue just tell me where your problem is and what your DBMS is and I'll try to adapt the code.
SELECT a.id, a.code
FROM t1 a
LEFT OUTER JOIN t2 b ON b.inferior = a.code
LEFT OUTER JOIN t1 c ON c.code = b.code and c.id=a.id
where c.code is null;
The idea is basically to try and match each entry of t1 with another entry that has the same id and shares a child-parent relationship. Once that's done, you simply need to find those who don't have a parent.

Related

MS-Access SQL : Join expression not supported

I have 2 tables A and B. I want to create a third one, C. C must contain each record that is in A but not in B, and each record that is in A and B.
I've tried the following :
SELECT A.* INTO C FROM (A INNER JOIN B ON A.Id = B.Id) LEFT JOIN B ON A.Id = B.Id WHERE B.Id IS NULL;
But it gives me the error message : JOIN expression not supported.
When there's only the INNER JOIN or the LEFT JOIN, it works perfectly. But for some reason when I combine both with the brackets, it doesn't work.
I believe I am using MS-Access 2013, if that helps.
By the way, I'm an Access and an SQL newbie.
The correct logic is:
SELECT A.* INTO C
FROM A LEFT JOIN
B
ON A.Id = B.Id
WHERE B.Id IS NULL;
You do not need two joins. My guess is that the problem with your query is that B appears twice in the FROM clause, without a table alias. MS Access doesn't know what the second B refers to.

How do I select group wise from a second table

This one is hard to explain and I'm sure I will facepalm when I see the solution, but I just can't get it right...
I have three tables:
Table A contains new records that I want to do something with.
Table B contains all activities from Table C of a specific type (done beforehand).
Table C is sort of a "master" table that contains all activities as well as a customer id and a lot of other stuff.
I need to select all activities that is in Table A from Table B. So far so good.
The part I can't get together is that I also need all the activities from Table B that has the same customer id as an activity contained in Table A.
This is what I'm after:
activity
2
3
4
5
6
The trick here is to get activity 2, because activity 2 is also done by customer 2, even though it is not in Table A.
Here are the tables:
Table A (new records)
activity
3
4
5
6
Table B (all records of a specific type from Table C)
activity
1
2 <-- How do I get this record as well?
3
4
5
6
Table C (all records)
activity customer
1 1
2 2
3 2
4 3
5 3
6 4
7 5
I tried something like this...
SELECT *
FROM table_b b
INNER JOIN table_c c
ON c.activity = b.activity
INNER JOIN table_a a
ON a.activity = b.activity
... but of course it only yields:
activity
3
4
5
6
How can I get activity 2 as well here?
To do this returning one column I would recommend staging the customer_ids of activities in Table_b that are in Table_a into a CTE (common table expression MSDN CTE) then select activities in table_c and join to the CTE to get only activities with a valid customer_id.
example of CTE: (Note the semi-colon ; before the WITH keyword is workaround for an issue in SQL 2005 with multiple statements. It it not necessary if you are in a newer version, or not running batch statements.)
;WITH cte_1 AS (
SELECT distinct c.customer --(only need a distinct result of customer ids)
from table_b b
join table_a a on b.activity = a.activity --(gets only activities in b that are in a)
join table_c c on b.activity = c.activity --(gets customer id of activies in table b)
)
SELECT a.activity
FROM table_c a
JOIN cte_1 b ON a.customer = b.customer
Alternatively you could do this in three joins with a select distinct. However I find the CTE to be an easier way to develop and think about this problem regardless of the way you decide to implement your solution. Although the three join solution will most likely scale and perform better over time with a growing data-set.
Example:
SELECT distinct d.activity
from table_b b
join table_a a on b.activity = a.activity --(gets only activities in b that are in a)
join table_c c on b.activity = c.activity --(gets customer id of activies in table b)
join table_c d ON c.customer = d.customer
Both would output:
2
3
4
5
6
Here is one way to do it
SELECT *
FROM TableB b1
WHERE EXISTS (SELECT 1
FROM Tablec c1
WHERE EXISTS (SELECT 1
FROM TableA a
INNER JOIN Tablec c
ON a.activity = c.activity
WHERE c.customer = c1.customer)
AND c1.activity = b1.activity)
Can you try doing a left join?
SELECT *
FROM table_b b
INNER JOIN table_c c
ON c.activity = b.activity
LEFT JOIN table_a a
ON b.activity = a.activity

Postgresql: inner join on 3 tables if data in 2. table is of no interest

Assuming I have the following three tables:
a
------
id
p1
b_id
b
------
id
c_id
other_value
c
------
id
p2
To get all the p1 and p2 values, I would write the following query:
SELECT
a.p1, c.p2
FROM
a
INNER JOIN
b ON (a.b_id = b.id)
INNER JOIN
c ON (b.c_id = c.id)
Now, since I'm not really interested in the other_value inside of b, I wondered if there is a simpler way to find the corresponding p2 value for each a entry.
(The reason for this question is that I'm running into performance problems on a database with a similar, but more complex, structure)
If you really insist on avoiding the b table in the outer scope, here is a nice ugly solution:
SELECT *
-- a.p1, c.p2
FROM a,c
WHERE EXISTS (
SELECT 42
FROM b
WHERE b.id = a.b_id
AND b.c_id = c.id
);
The same, using JOIN syntax (yields exactly the same query plan)
SELECT *
FROM a
JOIN c ON EXISTS (
SELECT 42
FROM b
WHERE b.id = a.b_id
AND b.c_id = c.id
);

Inner joining one table against many others

I have a table A with columns (Id,Value)
and a table B with Columns (BId,Id,..)
and a table C with columns (CId,Id,...)
I need to perform an inner join on these tables as follows
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
inner join C c on c.Id=a.Id
where <many conditions on table B and C>
How can i achieve the same. Now when i just run the query
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
inner join C c on c.Id=a.Id
it doesnt return anything.. please help.
FYI when i run the joins separately it gives me the rows. I just want a union of them...
Sample data:
A
1
2
3
B
2
C
3
then i want to select
A
2
3
Thanks in advance.
So, following your comments, it appears that you want something like this:
select a.Id,a.Value from A a
inner join B b on b.Id=a.Id
where <many conditions on table B>
UNION ALL
SELECT a.Id, a.Value from A
inner join C c on c.Id=a.Id
where <many conditions on table C>
As long as the fields match on ID from A -> B and A -> C and you dont have any other join condition, you should be able to see the matching rows.
I could not understand your point about how the B and C Id do not match. if a.id=b.id and a.id=c.id, Doesn't it automatically imply b.id = c.id?
Anyways, in situations like these, I try to do outer join of A on B and C and see if the rows that I think are matching in fact do exist.
select a.Id,a.Value from A a
left outer join B b on b.Id=a.Id
left outer join C c on c.Id=a.Id
where (b.id is not null or c.id is not null)
/* Matching record found in b or c */
EDIT: Based on your requirement, you can use the approach that Lamak suggested above (Using UNION Alls) or if you are certain that for each record in A, you will only have one record in B and one in C at most and only one column, you can use the scalar sub query approach.

Is there alternative way to write this query?

I have tables A, B, C, where A represents items which can have zero or more sub-items stored in C. B table only has 2 foreign keys to connect A and C.
I have this sql query:
select * from A
where not exists (select * from B natural join C where B.id = A.id and C.value > 10);
Which says: "Give me every item from table A where all sub-items have value less than 10.
Is there a way to optimize this? And is there a way to write this not using exists operator?
There are three commonly used ways to test if a value is in one table but not another:
NOT EXISTS
NOT IN
LEFT JOIN ... WHERE ... IS NULL
You have already shown code for the first. Here is the second:
SELECT *
FROM A
WHERE id NOT IN (
SELECT b.id
FROM B
NATURAL JOIN C
WHERE C.value > 10
)
And with a left join:
SELECT *
FROM A
LEFT JOIN (
SELECT b.id
FROM B
NATURAL JOIN C
WHERE C.value > 10
) BC
ON A.id = BC.id
WHERE BC.id IS NULL
Depending on the database type and version, the three different methods can result in different query plans with different performance characteristics.