0

I have a query similar to this below. As you can see, there are multiple parts which are very similar.

SELECT 
    id, 
    aaaa, 
    bbbb,
    tags
    ,(
        SELECT COUNT(*) > 0
        FROM A
        LEFT JOIN B 
            ON A.id = B.parent_id
        WHERE A.buzz=C.buzz
            AND B.tags & 1 <> 0
    ) as "has_children_tag_1"
    ,(
        SELECT COUNT(*) > 0
        FROM A
        LEFT JOIN B 
            ON A.id = B.parent_id
        WHERE A.buzz=C.buzz
            AND B.tags & 2 <> 0
    ) as "has_children_tag_2"
    ,(
        SELECT COUNT(*) > 0
        FROM A
        LEFT JOIN B 
            ON A.id = B.parent_id
        WHERE A.buzz=C.buzz
            AND B.tags & 4 <> 0
    ) as "has_children_tag_3"
    ,(
        SELECT COUNT(*) > 0
        FROM A
        LEFT JOIN B 
            ON A.id = B.parent_id
        WHERE A.buzz=C.buzz
            AND B.tags & 8 <> 0
    ) as "has_children_tag_4"
FROM A
LEFT JOIN Z
    ON A.id = Z.id

I know one thing, that I cannot split flag column into multiple bit columns, so I have to figure out how to query my existing tables in efficient way.

I am wondering is it possible (I don't know how to do that) to create some kind of temporary table for part:

    SELECT COUNT(*) > 0
    FROM A
    LEFT JOIN B 
        ON A.id = B.parent_id
    WHERE A.buzz=C.buzz

to have a possibility to run on this tmp table WHERE B.tags & 1 <> 0, WHERE B.tags & 2 <> 0, etc.

Any help/suggestion will be appreciated.

3
  • I don't see a single mention of flag in your query. Also, it would be nice to see (in English, not SQL ;) what you try to achieve. Commented Jun 22, 2016 at 16:26
  • Your example query is unclear, because of the C.buzz references: there is no C table in your query. Is the main FROM A supposed to be FROM C (and, accordingly, ON A.id = Z.id, ON C.id = Z.id)? Commented Jun 22, 2016 at 16:32
  • The usual suspects are also missing: Table definition and Postgres version. Please improve your question. Commented Jun 22, 2016 at 23:13

1 Answer 1

3

You could merge the subqueries using this model:

SELECT bool_or(B.tags&1<>0) as "has_children_tag_1",
       bool_or(B.tags&2<>0) as "has_children_tag_2",
       bool_or(B.tags&4<>0) as "has_children_tag_3",
       bool_or(B.tags&8<>0) as "has_children_tag_4"
FROM A LEFT JOIN B ON A.id = B.parent_id
WHERE [conditions]

bool_or is an aggregate function that evaluates to true if at least one value is true, so that should lead to the same results as the multiple count(*)>0 in the question, except as one single subquery.

To push these columns into an otherwise unrelated query, you may add the above subquery as a CTE in a WITH clause, and just put it in the FROM list. For instance, modifying your original query:

WITH flags AS
(SELECT bool_or(B.tags&1<>0) as "has_children_tag_1",
       bool_or(B.tags&2<>0) as "has_children_tag_2",
       bool_or(B.tags&4<>0) as "has_children_tag_3",
       bool_or(B.tags&8<>0) as "has_children_tag_4"
FROM A LEFT JOIN B ON A.id = B.parent_id
WHERE [conditions] )
SELECT 
  id, 
  aaaa, 
  bbbb,
  tags,
  has_children_tag_1,
  has_children_tag_2,
  has_children_tag_3,
  has_children_tag_4
FROM flags,A
LEFT JOIN Z
    ON A.id = Z.id

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.