ashcanschool
ashcanschool

Reputation: 327

Connecting Multiple Tables in SQL while Limiting Exponential Results

I have searched Google and Stack Overflow for a answer to my query, but I feel my lack of SQL vocabulary is standing in my way of finding an answer as I believe this would be a common question. Any helpful points in the direction of what I need to be reading are always welcome.

On to the question, I'm attempting to join three tables in Oracle 8i, for example, a Company Table, an Invoice Table and a Jobs Table there is no link between the Invoice Table and the Jobs Table. I am hoping that in one query I can link all three tables returning all invoices and all jobs for a company without returning all jobs for each invoice (see my example results below).

I want to see:

Company 1   Invoice 1   Job 1
Company 1   Invoice 2   Job 2
Company 1   Invoice 3   Job 3

I don't want to see:

Company 1   Invoice 1   Job 1
Company 1   Invoice 1   Job 2
Company 1   Invoice 1   Job 3
Company 1   Invoice 2   Job 1
Company 1   Invoice 2   Job 2
Company 1   Invoice 2   Job 3
Company 1   Invoice 3   Job 1
Company 1   Invoice 3   Job 2
Company 1   Invoice 3   Job 3

As always thank you for any help you can offer.

EDIT:

Essentially both the Invoice and Job Tables both have a Company Table Key field it's just that the Job and Invoice table have no link to each other directly. If the instance comes up when there are 2 Invoices and 3 Jobs I'd ideally like it to show and vice versa:

Company 1   Invoice 1   Job 1
Company 1   Invoice 2   Job 2
Company 1               Job 3

Although looking at the problem like this makes me feel that this is further away from an easier answer than I hoped.

Upvotes: 0

Views: 388

Answers (1)

Vincent Malgrat
Vincent Malgrat

Reputation: 67722

Your requirement means that you have a problem with your schema. My first advice in this case would be to modify your schema: add a job_id to invoice or an invoice_id to job (or a N-N relationship table invoice_job).

If you're not willing to update your schema, you can work a query that will make the join. The following query will basically join job and invoice one-to-one:

SELECT c.company_id, ij.job_id, ij.invoice_id
  FROM company c
  LEFT JOIN (SELECT job_id, invoice_id, 
                    NVL(j.company_id, i.company_id) company_id
               FROM (SELECT j.job_id, j.company_id,
                            row_number() OVER (PARTITION BY company_id
                                           ORDER BY job_id) job_no
                       FROM job j) j
               FULL OUTER JOIN 
                    (SELECT i.invoice_id, i.company_id,
                            row_number() OVER (PARTITION BY company_id
                                           ORDER BY invoice_id) invoice_no
                       FROM invoice i) i
                    ON j.company_id = i.company_id
                   AND j.job_no = i.invoice_no) ij
              ON c.company_id = ij.company_id

The join condition here is artificial. If you remove an invoice, the jobs and invoices relationship may change.

If the two tables are really unrelated, you may want instead to display the results differently, for example:

SQL> SELECT cj.company_id, cj.jobs,
  2         listagg(i.invoice_id, ',')
  3            WITHIN GROUP (ORDER BY i.invoice_id) invoices
  4    FROM (SELECT c.company_id,
  5                 listagg(j.job_id, ',') WITHIN GROUP (ORDER BY job_id) jobs
  6            FROM company c LEFT JOIN job j ON c.company_id = j.company_id
  7           GROUP BY c.company_id) cj
  8    LEFT JOIN invoice i ON cj.company_id = i.company_id
  9  GROUP BY cj.company_id, cj.jobs;

COMPANY_ID  JOBS   INVOICES
----------- ------ --------
1           1,2,3  1,2

Upvotes: 1

Related Questions