0

一般的なモデル: lordshave peons、および bothlordspeonshave thingsは、1 つまたは複数のおよびthingsによって所有できます。領主が直接的または間接的に所有しているすべてを表示するには:peons lordsthings

SELECT lords.id AS lord_id,
       peons.id AS peon_id,
       things.id AS thing_id
  FROM lords
  LEFT JOIN lords_things ON
       lords.id = lords_things.lord_id
  LEFT JOIN peons ON
       lords.id = peons.lord_id
  LEFT JOIN peons_things ON
       peons.id = peons_things.peon_id
  JOIN things ON
       lords_things.thing_id = things.id OR
       peons_things.thing_id = things.id
 WHERE lords.id = 123

現在、2 つの問題があります。

  1. コードは、モノがどのレベルに接続されているかを判断するためにlord_id、どちらpeon_idが非であるかを調べる必要があります。NULLこれを解決する方法はたくさんあります。たとえば、Oracle では次のように言えます。

    SELECT NVL2(things_lords.id, 'lord', 'peon') as level
    

    SQL Serverでは、次のように言うことができるはずです

    SELECT CASE WHEN things_lords.id IS NULL THEN 'peon' ELSE 'lord' END AS level
    

    しかし、私はこれらのどちらも (少なくとも PostgreSQL には) 移植可能ではないと思います。別のアプローチでは、次を使用しUNIONます。

    SELECT lords.id AS owner_id,
           'lord' AS level,
           things.id AS thing_id
      FROM lords
      JOIN lords_things ON
           lords.id = lords_things.lord_id
      JOIN things ON
           lords_things.thing_id = things.id
     WHERE lords.id = 123
    UNION
    SELECT peons.id AS owner_id,
           'peon' AS type,
           things.id AS thing_id
      FROM lords
      JOIN peons ON
           lords.id = peons.lord_id
      JOIN peons_things ON
           peons.id = peons_things.peon_id
      JOIN things ON
           peons_things.thing_id = things.id
     WHERE lords.id = 123
    

    ほとんどすべてのコードを複製するので、これは非常に醜いです。これのためのよりエレガントなポータブルソリューションはありますか?

  2. things複数回表示される場合もあります。これは私のアプリケーションの問題ではありませんが、完全を期すために言及されています。
4

1 に答える 1

1

このcaseステートメント、すべてのデータベース エンジン (少なくとも、MS Access を除く比較的最近のすべてのエンジン) に移植できます。Web を見ると、Postgres は少なくともバージョン 7 以降で case ステートメントをサポートしています。

そのため、ケースバージョンを使用してください。

完成度は。次のようなものが必要です。

select things.id,
       (case when max(lords.id) is not null and max(peons.id) is not null then 'BOTH'
             when max(lords.id) is not null then 'LORDS'
             when max(peons.id) is not null then 'PEONS'
             else 'Ooops!'
        end) as wherefrom
. . . 
group by things.id

つまり、集計を行い、集計関数を使用して必要なものを要約します。

于 2012-12-17T16:37:28.883 に答える