Re: filtering many-to-many results

From: Charles Hooper <hooperc2000_at_yahoo.com>
Date: Wed, 6 Feb 2008 04:51:04 -0800 (PST)
Message-ID: <1aa7d564-db3c-412a-afc9-9881b63be6be@m34g2000hsb.googlegroups.com>


On Feb 6, 7:01 am, markdibley <markdib..._at_gmail.com> wrote:
> Hello
>
> I have a problem filtering my results which involves a many-to-many
> join. Below is a brief layout of the problem, but briefly, I have a
> test that can have multiple results and those results may also belong
> multiple tests (i have done the same test under a different id and I
> want to inherit the previous test result). I also have an event table
> that is required to keep track of all changes.
>
> The problem I have is that I cannot filter my results so where a
> result belongs to 2 tests I don't want the details where it belongs to
> the test in the query.
>
> If anyone can suggest a way of returning 2 lines instead of 3 I would
> be very grateful.
>
> My apologises if this is not the right forum to post this in (please
> can you suggest a suitable forum if this is the case, please)
>
> Thanks
>
> mark
>
> SELECT tr.test_acc, e.event_id, re.resultevent_id, re.result_id,
> re2.resultevent_id, re2.event_id, tr2.test_acc
> FROM TestRequest tr JOIN Event e ON tr.test_acc=e.test_acc
> JOIN ResultEvent re ON e.event_id=re.event_id
> JOIN ResultEvent re2 ON re.result_id=re2.result_id
> JOIN Event e2 ON e2.event_id=re2.event_id
> JOIN TestRequest tr2 ON e2.test_acc=tr2.test_acc
> WHERE tr.test_acc=3418;
> +----------+----------+----------------+-----------+----------------
> +----------+----------+
> | test_acc | event_id | resultevent_id | result_id | resultevent_id |
> event_id | test_acc |
> +----------+----------+----------------+-----------+----------------
> +----------+----------+
> |     3418 |    42178 |           6345 |      6321 |           6345
> |    42178 |     3418 |
> |     3418 |    42179 |           6346 |      4126 |           4126
> |    28004 |     2248 |
> |     3418 |    42179 |           6346 |      4126 |           6346
> |    42179 |     3418 |
> +----------+----------+----------------+-----------+----------------
> +----------+----------+
> 3 rows in set (0.00 sec)
>
> +-------------+
> | TestRequest |
> +-------------+
> | test_acc    |
> +-------------+
>      1 |
>        |
>      * |
> +-------------+
> | Event       |
> +-------------+
> | test_acc    |
> | event_id    |
> +-------------+
>      1 |
>        |
>      * |
> +----------------+
> | ResultEvent    |
> +----------------+
> | resultevent_id |
> | event_id       |
> | result_id      |
> +----------------+

I think that I understand what you are trying to do. I changed the table names slightly (added _) in the mock up: First, the table creation:
CREATE TABLE TEST_REQUEST (
  TEST_ACC NUMBER(10)); CREATE TABLE EVENT (
  TEST_ACC NUMBER(10),
  EVENT_ID NUMBER(10)); CREATE TABLE RESULT_EVENT (
  RESULTEVENT_ID NUMBER(10),
  EVENT_ID NUMBER(10),
  RESULT_ID NUMBER(10)); As best I can tell, the data that is in the tables: INSERT INTO TEST_REQUEST VALUES (3418);
INSERT INTO TEST_REQUEST VALUES (2248);

INSERT INTO EVENT VALUES (3418,42178);
INSERT INTO EVENT VALUES (3418,42179);
INSERT INTO EVENT VALUES (2248,28004);

INSERT INTO RESULT_EVENT VALUES (6345,42178,6321);
INSERT INTO RESULT_EVENT VALUES (4126,28004,4126); INSERT INTO RESULT_EVENT VALUES (6346,42179,4126); COMMIT; I reformatted your query so that I could more easily see what is happening:
SELECT
  TR.TEST_ACC,
  E.EVENT_ID,
  RE.RESULTEVENT_ID,
  RE.RESULT_ID,
  RE2.RESULTEVENT_ID,
  RE2.EVENT_ID,
  TR2.TEST_ACC

FROM
  TEST_REQUEST TR,
  EVENT E,
  RESULT_EVENT RE,
  RESULT_EVENT RE2,
  EVENT E2,
  TEST_REQUEST TR2
WHERE
  TR.TEST_ACC=3418
  AND TR.TEST_ACC=E.TEST_ACC
  AND E.EVENT_ID=RE.EVENT_ID
  AND RE.RESULT_ID=RE2.RESULT_ID
  AND E2.EVENT_ID=RE2.EVENT_ID
  AND E2.TEST_ACC=TR2.TEST_ACC;

  TEST_ACC EVENT_ID RESULTEVENT_ID RESULT_ID RESULTEVENT_ID EVENT_ID TEST_ACC
---------- ---------- -------------- ---------- -------------- ---------- ----------

      3418      42179           6346       4126           4126
28004      2248
      3418      42179           6346       4126           6346
42179      3418
      3418      42178           6345       6321           6345
42178      3418

It appears that if you have 2 rows with the same RESULT_ID, you only want the first EVENT_ID, so you need to have some way of numbering the rows. The ROW_NUMBER analytical function might be able to help: SELECT
  TR.TEST_ACC,
  E.EVENT_ID,
  RE.RESULTEVENT_ID,
  RE.RESULT_ID,

  RE2.RESULTEVENT_ID,
  RE2.EVENT_ID,
  TR2.TEST_ACC,

  ROW_NUMBER() OVER (PARTITION BY RE.RESULT_ID ORDER BY RE2.EVENT_ID) RN
FROM
  TEST_REQUEST TR,
  EVENT E,
  RESULT_EVENT RE,
  RESULT_EVENT RE2,
  EVENT E2,
  TEST_REQUEST TR2
WHERE
  TR.TEST_ACC=3418
  AND TR.TEST_ACC=E.TEST_ACC
  AND E.EVENT_ID=RE.EVENT_ID
  AND RE.RESULT_ID=RE2.RESULT_ID
  AND E2.EVENT_ID=RE2.EVENT_ID
  AND E2.TEST_ACC=TR2.TEST_ACC;

  TEST_ACC EVENT_ID RESULTEVENT_ID RESULT_ID RESULTEVENT_ID EVENT_ID TEST_ACC RN
---------- ---------- -------------- ---------- -------------- ---------- ---------- --

      3418      42179           6346       4126           4126
28004      2248   1
      3418      42179           6346       4126           6346
42179      3418   2
      3418      42178           6345       6321           6345
42178      3418   1

Now, if we can filter out any of the rows that do not have RN=1, we may have a usable solution. By sliding the above into an inline view (and adding column aliases as necessary in the inline view), we can add a WHERE clause to return only those rows with RN=1: SELECT
  TEST_ACC,
  EVENT_ID,
  RESULTEVENT_ID,
  RESULT_ID,
  RESULTEVENT_ID2,
  EVENT_ID2,
  TEST_ACC2
FROM
  (SELECT
    TR.TEST_ACC,
    E.EVENT_ID,
    RE.RESULTEVENT_ID,
    RE.RESULT_ID,

    RE2.RESULTEVENT_ID RESULTEVENT_ID2,
    RE2.EVENT_ID EVENT_ID2,
    TR2.TEST_ACC TEST_ACC2,

    ROW_NUMBER() OVER (PARTITION BY RE.RESULT_ID ORDER BY RE2.EVENT_ID) RN
  FROM
    TEST_REQUEST TR,
    EVENT E,
    RESULT_EVENT RE,
    RESULT_EVENT RE2,
    EVENT E2,
    TEST_REQUEST TR2
  WHERE
    TR.TEST_ACC=3418
    AND TR.TEST_ACC=E.TEST_ACC
    AND E.EVENT_ID=RE.EVENT_ID
    AND RE.RESULT_ID=RE2.RESULT_ID
    AND E2.EVENT_ID=RE2.EVENT_ID
    AND E2.TEST_ACC=TR2.TEST_ACC)

WHERE
  RN=1;

  TEST_ACC EVENT_ID RESULTEVENT_ID RESULT_ID RESULTEVENT_ID2 EVENT_ID2 TEST_ACC2
---------- ---------- -------------- ---------- --------------- ---------- ----------

      3418      42179           6346       4126            4126
28004      2248
      3418      42178           6345       6321            6345
42178      3418

Hopefully, the above helps, even if it is not exactly what you wanted.

Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc. Received on Wed Feb 06 2008 - 06:51:04 CST

Original text of this message