0

Not sure if the question is phrased correctly but here's an example of the schema:

CREATE TABLE TabA (Id INT NOT NULL, PRIMARY KEY (Id));

CREATE TABLE TabB (
    Id INT NOT NULL, 
    TabAId INT, 
    PRIMARY KEY (Id),
    FOREIGN KEY (TabAId) REFERENCES TabA(Id)
)

CREATE TABLE TabC (
    Id INT NOT NULL, 
    TabAId INT, 
    PRIMARY KEY (Id),
    FOREIGN KEY (TabAId) REFERENCES TabA(Id)
)

What I need to do is to select TabA.Id where TabA.Id is either referenced by records in TabB or TabC (or both). If I were to translate this programmatically:

type B = { Id : int }

type C = { Id : int }

type A = { ItemsB : B list ; ItemsC : C list }

let itemsA = [ ... ] // a list of items A
let filtered = itemsA |> List.filter (fun a -> a.ItemsB.Length > 0 || a.ItemsC.Length > 0)

So far I tried this query, but I'm not sure if it's good:

SELECT a.Id 
FROM TabA a
INNER JOIN
    (
        SELECT b.TabAId AS tabAId
        FROM TabB b
        FULL OUTER JOIN TabC c ON b.TabAId = c.TabAId
    ) sub
ON a.Id = sub.tabAId

Any thoughts? Thank you.

3
  • What exactly do you want as ouput? Do you JUST want rows from A where the ID exists in either of the other two tables? That implies EXISTS. Why do you join? That means your resultset can include rows with duplicate values of a.ID. Is that your goal?
    – SMor
    Nov 8, 2021 at 17:18
  • > Do you JUST want rows from A where the ID exists in either of the other two tables? Yes, I want the IDs from A where the IDs exist in either of the two tables > Why do you join? That means your resultset can include rows with duplicate values of a.ID. Is that your goal? I don't want duplicates. I just don't know better
    – vladek
    Nov 8, 2021 at 17:21
  • 1
    @vladek, check the updated answer. I didn't notice before you were querying only SELECT a.Id instead of all the columns.
    – Ronaldo
    Nov 8, 2021 at 17:34

2 Answers 2

5

Why so complicated?

SELECT a.Id 
FROM TabA a
WHERE exists (select * from TabB b where b.tabAId = a.Id)
   OR exists (select * from TabC c where c.tabAId = a.Id)
ORDER BY ...;

You don't need DISTINCT here - a.Id is the primary key. In your original query, you could have used UNION instead of FULL OUTER JOIN. The FULL OUTER JOIN is nonsense - something you can see if you test just that part of the query and examine the resultset. In this case, UNION rather than UNION ALL is desired to remove duplicates. Generally speaking, most uses of UNION should be UNION ALL.

When you run into problems with a query that does not work, stop trying to fix it all at once. Break out the pieces and examine what they do. Often you will see problems that can be solved and might lead you to the desired logic.

To follow on with UNION comments, you could use:

SELECT b.TabAId AS Id FROM TabB as b
UNION 
SELECT c.TabAId FROM TabC as c
;

No need to reference TabA at all.

3
  • Thank you, will give those a try. I'm not really all that familiar with SQL, that's why I'm overcomplicating things. Which of these methods is the best in terms of performance?
    – vladek
    Nov 8, 2021 at 19:42
  • Examine the execution plans. There are no absolute truths with respect to "performance". I suspect the UNION approach but much also depends on your goal. If an application is to access the resultset and interrogate the meta-data for some purpose, you might NEED the EXISTS form.
    – SMor
    Nov 8, 2021 at 20:12
  • Both answers seemed to work in my tests, but the solutions you provided seem more elegant so I'll mark this one as accepted answer.
    – vladek
    Nov 9, 2021 at 7:52
2

Here's one way to achieve it:

SELECT DISTINCT A.Id
FROM TabA A 
    LEFT JOIN TabB B ON A.Id = B.TabAId
    LEFT JOIN TabC C ON A.Id = C.TabAId
WHERE B.TabAId IS NOT NULL
    OR C.TabAId IS NOT NULL;

You can check the db<>fiddle.

5
  • @Charlieface, that's a fair question and my answer to that is not related to the query performance itself:
    – Ronaldo
    Nov 9, 2021 at 11:57
  • My 1st point is that the OP didn't mention a performance issue, it was a how can I do it? question and at the top of my answer I say Here's one way to achieve it meaning there are other methods, some better, some worse, but none should be discarded - See What contributes most: a long answer with more than one way of doing a task or a short answer with the method known to be more professional?.
    – Ronaldo
    Nov 9, 2021 at 11:57
  • My 2nd point is that the OP didn't give any background info related to the reason that query was needed. Imagine his boss asked "I need a report on my desk ASAP containing the IDs": do you still think the answer that was given 2 hours later would be the fastest to achieve the OP goal? Regarding the use of DISTINCT I added it on my edit when I noticed the OP wouldn't need the other columns. I'm glad Smor added 2 other methods I didn't think of by the time I answered the OP. Now I know about 3 ways of doing it =)
    – Ronaldo
    Nov 9, 2021 at 11:58
  • @Charlieface, if I remove the DISTINCT, the resultset brings repeated values. See the db<>fiddle without the DISTINCT. Even though we have the uniqueness constraint on TabA, the values can repeat on TabB and TabC. Am I missing something?
    – Ronaldo
    Nov 9, 2021 at 13:31
  • 1
    Hand on my heart, you're quite right. I misread the schema and assumed that TabB and TabC were also distinct Nov 9, 2021 at 13:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.