Select from intersection / junction tables

1.1k views Asked by At

Many times just find the right article and reading it on StackOverflow helped me through a lot of stuff that I didn't know what to do with but for the first time, I think I need to write one. I've been searching for the correct answer on this prob but I've failed to find one.

So the bugger is that I've created 2 tables and one intersection table to relate them.

The idea behind is so simple(I'm almost embarrassed that I can't solve this one).

One BBS article MAY have SOME attached files. That means one article could have an attachment or not. One article can have multiple attachments.

What I've been trying to do is

get the list of articles with all the information on its attachments but without duplicate rows.

Ok... I tried to put up the DDL but I coulndn't format it correctly...

create table article(
id PK
some other stuff...
)

create table attachment(
id PK
physical_file_name 
etc...
)

and here is the intersection

create table article_attachment(
id PK(synthetic)
article_id FK
attachment_ID FK
)

I want to select all the articles whether it has or hasn't any attachments but if one article has multiple attachments I only need one of the attachments. (it doesn't matter which one of them)

Yes it sounds dumb but there is no DBA or SQL developer around here so I have to do all the things... pretty messed up I'm trying my best

any wise ideas?

Thanks in advance

-p.s. - I've tried something like...

with refined_table as(

  select file_id, row_number() over(partition by id order by id desc) as seq
  from consumer_file

)
select * 
from consumer_info ci 
left outer join consumer_file cf on cf.consumer_id = ci.id
left outer join refined_table rt on rt.file_id = cf.file_id
where rt.seq =1

this but I don't really understand how it works

UPDATE

Here is what I tried at first. It keeps giving me ORA-00979:not a GROUP BY expression I looked for the solution for a long time. A few people suggested using aggregation function or "Hint" (if that's what it is...)

  with refined_table as(

      select file_id, row_number() over(partition by id order by id desc) as seq
      from consumer_file

    )

I mean this

Hmm any ideas ?

Many thanks all of you : )

SELECT 
    CI.id as article_id, 
    DF.id as attachment_id,  
    DF.PHYSICAL_NAME as file_name 
FROM 
    CONSUMER_INFO CI
LEFT OUTER JOIN 
    CONSUMER_FILE CF ON CF.CONSUMER_ID = CI.ID
LEFT OUTER JOIN 
    DEFAULT_FILE DF ON CF.FILE_ID = DF.id
GROUP BY 
   CI.ID
3

There are 3 answers

4
Ozair Kafray On BEST ANSWER

If its only 1->N relationship from article -> attachment then you can modify the attachment as follows:

create table attachment(
   id PK
   article_id FK 
   physical_file_name 
   etc...
)

You need a separate intersection table only if there were an N->N relationship between articles and attachments.

UPDATE: However, if you still need to keep the N<->N relationship (as mentioned in your comment), then you can use the GROUP BY clause to GROUP results by article_id e.g:

SELECT 
    article.id as article_id, 
    attachment.id as attachment_id,  
    attachment.physical_file_name as file_name 
FROM 
    article 
LEFT OUTER JOIN 
    article_attachment ON article_id = article.id 
LEFT OUTER JOIN 
    attachment ON attachment_id = attachment.id
GROUP BY 
    article_id
0
Bob Jarvis - Слава Україні On

I think your table definitions are fine. The requirement to select only one of the attachments makes things a bit more complex, but since you don't care which one you get I think the following should work:

SELECT *
  FROM ARTICLE a
  LEFT OUTER JOIN (SELECT ARTICLE_ID, MIN(ATTACHMENT_ID) AS ATTACHMENT_ID
                     FROM ARTICLE_ATTACHMENT
                     GROUP BY ARTICLE_ID) aa
    ON (aa.ARTICLE_ID = a.ID)
  LEFT OUTER JOIN ATTACHMENT t
    ON (t.ID = aa.ATTACHMENT_ID)

Share and enjoy.

0
Iľja On

If you don't care, which of the attachements you load, then you may be looking for this:

select
  art.article_id, art.article_stuff,
  att.attachment_id, att.attachment_stuff
from
  article art,
  article_attachment aat,
  attachment att
where
  art.article_id = &article_id
  and aat.article_id = art.article_id
  and att.attachment_id = aat.attachment_id
  and rownum < 2;

The rownum < 2 will ensure, that you select only the first row of all article-article_attachment-attachment combinations.