Search code examples
sqloracle-databaseoracle11goracle10g

Join a table that depends on another table


I have a POST table, a CATEGORY table, a TAG table and a MIGTATION_TAG table, I explain the MIGTATION_TAG table contains the movement of the tags between the categories, for example the tag whose ID = 1 belongs to the category whose l 'ID = 10 if I change its category to 12 a line will be added to the MIGTATION_TAG table as follows: ID 1 TAG_ID 1 CATEGOTY_ID 12

the POST table

 id         title       content     tag_id
----------  ----------  ----------  ----------
 1          title1      Text...     1
 2          title2      Text...     3
 3          title3      Text...     1
 4          title4      Text...     2
 5          title5      Text...     5
 6          title6      Text...     4

the CATEGORY table

 id         name      
----------  ----------  
 1          category_1      
 2          category_2
 3          category_3        

the TAG table

 id         name        fist_category_id
----------  ----------  ----------------
 1          tag_1       1
 2          tag_2       1
 3          tag_3       3
 4          tag_4       1
 5          tag_5       2

the MIGTATION_TAG table

 id         tag_id      category_id
----------  ----------  ----------------
 9          1           3
 8          5           1
 7          1           2
 5          3           1
 4          2           2
 3          5           3
 2          3           3
 1          1           3

so i would like to know how many posts are registered for each category.

in some cases if there has been no change of category for a tag then it keeps its first category, I manage to join the TAG table to the POST table via LEFT JOIN but the problem is that the join must depend on the MIGTATION_TAG table which must check if there has been a migration, if so then it must bring me back the last MAX (tag_id ) for each tag ,

here is my query

select category, COUNT(*) AS numer_of_posts
                  
        from(
            select CATEGORY.name,               
                case
                when POST.tag_id is not null then CATEGORY.name
                end as category              

                from POST
                left join TAG ON POST.tag_id = TAG.id
                
                left join  (
                    select id, MAX(tag_id) tag_id 
                    from MIGTATION_TAG 
                    group by id, tag_id
                ) MIGTATION_TAG 
                ON TAG.id = MIGTATION_TAG.tag_id

                left join CATEGORY on MIGTATION_TAG.category_id = CATEGORY.id         
            )
            GROUP BY category
;

here is the result i want to display with my query

Important ! for the post with id = 6 the tag_id = 4 whish was not changed so it will be using the fist_category_id in TAG table

 category   numer_of_posts     
----------  --------------  
category_1  3    
category_2  1
category_3  2      

Best regards


Solution

  • You can use:

    SELECT MAX(c.name) AS category,
           COUNT(*)
    FROM   post p
           INNER JOIN tag t
           ON (p.tag_id = t.id)
           LEFT OUTER JOIN (
             SELECT tag_id,
                    MAX(category_id) KEEP (DENSE_RANK LAST ORDER BY id) AS category_id
             FROM   migration_tag
             GROUP BY tag_id
           ) m
           ON (t.id = m.tag_id)
           INNER JOIN category c
           ON ( COALESCE(m.category_id, t.first_category_id) = c.id )
    GROUP BY c.id
    ORDER BY category
    

    Which, for the sample data:

    CREATE TABLE POST ( id, title, content, tag_id ) AS
      SELECT 1, 'title1', 'Text...', 1 FROM DUAL UNION ALL
      SELECT 2, 'title2', 'Text...', 3 FROM DUAL UNION ALL
      SELECT 3, 'title3', 'Text...', 1 FROM DUAL UNION ALL
      SELECT 4, 'title4', 'Text...', 2 FROM DUAL UNION ALL
      SELECT 5, 'title5', 'Text...', 5 FROM DUAL UNION ALL
      SELECT 6, 'title6', 'Text...', 4 FROM DUAL;
    
    CREATE TABLE CATEGORY  ( id, name ) AS
      SELECT 1, 'category_1' FROM DUAL UNION ALL
      SELECT 2, 'category_2' FROM DUAL UNION ALL
      SELECT 3, 'category_3' FROM DUAL;
    
    CREATE TABLE TAG (id, name, first_category_id) AS
      SELECT 1, 'tag_1', 1 FROM DUAL UNION ALL
      SELECT 2, 'tag_2', 1 FROM DUAL UNION ALL
      SELECT 3, 'tag_3', 3 FROM DUAL UNION ALL
      SELECT 4, 'tag_4', 1 FROM DUAL UNION ALL
      SELECT 5, 'tag_5', 2 FROM DUAL;
    
    CREATE TABLE  MIGRATION_TAG ( id, tag_id, category_id ) AS
      SELECT 9, 1, 3 FROM DUAL UNION ALL
      SELECT 8, 5, 1 FROM DUAL UNION ALL
      SELECT 7, 1, 2 FROM DUAL UNION ALL
      SELECT 5, 3, 1 FROM DUAL UNION ALL
      SELECT 4, 2, 2 FROM DUAL UNION ALL
      SELECT 3, 5, 3 FROM DUAL UNION ALL
      SELECT 2, 3, 3 FROM DUAL UNION ALL
      SELECT 1, 1, 3 FROM DUAL;
    

    Outputs:

    CATEGORY COUNT(*)
    category_1 3
    category_2 1
    category_3 2

    fiddle