1

Appleのインスタンスに「関連する」すべてのインスタンスを選択するGrailsアプリケーションのクエリを作成しようとしていますOrange。ここで、「関連する」という言葉は、のインスタンスに関連付けられているすべてのインスタンスが、関係Bananaするインスタンスに関連付けられているインスタンスのAppleいくつかの組み合わせに関連付けられていることを意味しCherryますOrange私はここで質問を見てきましたが、私の質問はもう少し複雑で、与えられた答えを私の問題に適用する方法がわかりません。

これが私が扱っているクラスです:

class Apple {
    static hasMany = [ bananas: Banana ]
}

class Banana {
}

class Cherry {
    static hasMany = [ bananas: Bannna ]
}

class Orange {
    static hasMany = [ cherries: Cherry ]
}

次のような画像形式で:

ここに画像の説明を入力してください

以下に示すシナリオ1では、Banana「Apple 2」に関連するすべてのインスタンスが「Cherry」のインスタンスのいくつかの組み合わせを通じて「Orange1」に関連していないため、目的のクエリは「Apple1」のみを返します。

ここに画像の説明を入力してください

Banana以下に示すシナリオ2では、「Apple2 」に関連するすべてのインスタンスが「Cherry」のインスタンスのいくつかの組み合わせを通じて「Orange1」に関連しているため、目的のクエリは「Apple1」と「Apple2」を返します。 。

ここに画像の説明を入力してください

これが私が扱ってきたクエリです:

Apple.executeQuery(
    "SELECT DISTINCT apples
    FROM Apple apples
    INNER JOIN apples.banannas banannas
    WHERE banannas IN(
        SELECT DISTINCT banannas
        FROM Cherry cherries
        INNER JOIN cherries.banannas banannas
        WHERE cherries IN(
            SELECT DISTINCT cherries
            FROM Orange orange
            INNER JOIN orange.cherries cherries
            WHERE orange =:myOrange
        )
    )
    ORDER BY apples.id ASC",
    myOrange: myOrange
)

問題は、私のクエリがシナリオ1と2の両方で「Apple1」と「Apple2」を返すことです。

更新#1:

要求に応じて、HQLクエリによって生成されたSQLは次のとおりです。フルーティーな難読化でごめんなさい<<<しゃれ

SELECT DISTINCT apple0_.id                     AS id10_,
                apple0_.version                AS version10_,
                apple0_.description            AS descript3_10_,
                apple0_.apple_priority_type_id AS apple4_10_,
                apple0_.apple_status_type_id   AS apple5_10_,
                apple0_.internal_need_date     AS internal6_10_,
                apple0_.name                   AS name10_
FROM   apple apple0_
       INNER JOIN apple_priority_type applepri1_
               ON apple0_.apple_priority_type_id = applepri1_.id
       INNER JOIN apple_status_type applesta2_
               ON apple0_.apple_status_type_id = applesta2_.id
       INNER JOIN apple_banana banana3_
               ON apple0_.id = banana3_.apple_bananas_id
       INNER JOIN banana banana4_
               ON banana3_.banana_id = banana4_.id
WHERE  banana4_.id IN (SELECT DISTINCT banana7_.id
                       FROM   cherry plum5_
                              INNER JOIN cherry_banana banana6_
                                      ON plum5_.id = banana6_.cherry_bananas_id
                              INNER JOIN banana banana7_
                                      ON banana6_.banana_id = banana7_.id
                       WHERE  plum5_.id IN (SELECT DISTINCT plum10_.id
                                            FROM   orange orange8_
                                                   INNER JOIN orange_cherry
                                                              plum9_
                                                           ON
orange8_.id = plum9_.orange_cherrys_id
INNER JOIN cherry plum10_
        ON
plum9_.cherry_id = plum10_.id
WHERE  orange8_.id = 248))
ORDER  BY apple0_.id ASC
LIMIT  100 

更新#2:

私は実際にこれをHQLで機能させる方法を持っていますが、他のタイプのインスタンスに関連するすべてのタイプを見つけている他の場所にあるようなワンライナーではありません。これが私の回避策です:

    def bananas= myOrange.cherries.bananas.flatten().unique()
    def apples = Apple.getAll().collectMany{ !it.bananas.isEmpty() && bananas.containsAll( it.bananas ) ? [ it ] : [] }.flatten().unique()
    namedParams.put( "apples", apples )
    if( !apples.isEmpty() ) {
        apples = Apple.executeQuery( "SELECT DISTINCT apples FROM Apple apples WHERE apples IN(:apples) ${additionalQuery} ORDER BY ${sortname} ${sortorder}", namedParams )
    }
    return apples
4

1 に答える 1

1

これは、Apple がバナナと少なくとも 1 つの関係を持っている場合、常に返されるためです。

select
    distinct apple0_.id as id0_,
    apple0_.version as version0_ 
from
    apple apple0_ 
inner join
    apple_banana bananas1_ 
where bananas1_.banana_id in (1,2,3)

あなたがしなければならないことは、チェリーに関連するバナナが存在しないリンゴを結果から除外することです。データベースに oracleマイナスのような機能があるかどうかを確認する必要があります。

EDIT : このクエリは、チェリー バナナに含まれていないバナナを持つリンゴをリストから削除します。

注:これのパフォーマンスは確認していません。

  SELECT DISTINCT apples
    FROM Apple apples
    INNER JOIN apples.bananas bananas
    WHERE bananas IN(
        SELECT DISTINCT bananas
        FROM Cherry cherries
        INNER JOIN cherries.bananas bananas
        WHERE cherries IN(
            SELECT DISTINCT cherries
            FROM Orange orange
            INNER JOIN orange.cherries cherries
            WHERE orange =:myOrange
        )
    )
  and apples not in (
    SELECT DISTINCT apples
      FROM Apple apples
     INNER JOIN apples.bananas bananas
      WHERE bananas NOT IN(
        SELECT DISTINCT bananas
          FROM Cherry cherries
          INNER JOIN cherries.bananas bananas
          WHERE cherries IN(
            SELECT DISTINCT cherries
            FROM Orange orange
            INNER JOIN orange.cherries cherries
            WHERE orange = :myOrange
          )
      )
    )
于 2012-12-04T21:05:04.483 に答える