1

テーブルBuildingAddressがあり、それぞれBuildingが 0..n に関連付けられていAddressesます。

Buildings関連付けて出品したいと思いAddressます。aBuildingに複数の入り口があり、したがって複数の がある場合、Addressesどれが表示されるかは気にしません。に既知のアドレスがない場合Building、アドレス フィールドは になりますnull

これは、各行を最大 1 回結合する左結合のようなものが欲しいということです。

これをOracle SQLでどのように表現できますか?

PS: 私のクエリには、両方のテーブルにかなり複雑な制限が含まれます。したがって、クエリ テキストでこれらの制限を繰り返すことは避けたいと思います。

4

5 に答える 5

4

SELECT 句でアドレスを照会することを検討します。たとえば、次のようになります。

SELECT b.*
      ,(SELECT a.text
        FROM   addresses a
        WHERE  a.buildingid = b.id
        AND    ROWNUM=1) as atext
FROM   building b;

これROWNUM=1は、「ある場合は 1 つだけ取得し、どちらでも構いません」という意味です。

このアプローチの利点は、addresses.buildingid に適切なインデックスが存在する限り、おそらくほとんどの代替方法よりもパフォーマンスが向上することです。照会された各建物の住所が見つかるとすぐに、それ以上の住所の検索を停止します。

このアプローチの欠点は、住所テーブルから複数の列が必要な場合、それができないことです。ただし、それらを 1 つの文字列に連結することはできます。

于 2010-02-25T00:11:44.997 に答える
2

多くのアドレスのどれが表示されるかは気にしないためです。

オラクル 9i+:

WITH summary AS (
      SELECT b.*,
             a.*,
             ROW_NUMBER() OVER (PARTITION BY b.building_id) rn
        FROM BUILDINGS b
   LEFT JOIN ADDRESSES a ON a.building_id = b.building_id)
SELECT s.*
  FROM summary s
 WHERE s.rn = 1

サブクエリ以外の因数分解に相当するもの:

SELECT s.*
  FROM (SELECT b.*,
               a.*,
               ROW_NUMBER() OVER (PARTITION BY b.building_id) rn
           FROM BUILDINGS b
      LEFT JOIN ADDRESSES a ON a.building_id = b.building_id) s
 WHERE s.rn = 1
于 2010-02-24T22:56:24.107 に答える
0
select b.*, max(a.id) as aid 
from building b 
left outer join addresses a on (a.buildingid = b.id) 
group by a.buildingid 

また

select b.*, maxid
from building b 
left outer join 
(
 select buildingid, max(id) as maxid
 from addresses
 group by buildingid 
) a on (a.buildingid = b.id) 
于 2010-02-24T21:32:58.323 に答える
0

メリトン、

このアプローチでは、ネストされたインラインビューを使用します。私はこのアプローチを大規模なデータセットで証明しましたが、非常にうまく機能します。

クエリを理解する最良の方法は、最も内側の「M」インラインビューから開始することです。デバッグと明確さのためにカウントを追加しました。これにより、各建物の最大(つまり最新の???)アドレスIDが識別されます。

   select maxa.b_id, max(maxa.a_id) a_id, count(*) c
   from address maxa
   group by maxa.b_id;

次の「A」インラインビューは、上記の「M」インラインビューを使用して取得するアドレスを決定し、そのアドレスIDに結合して、一連のアドレスフィールドを返します。

  select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c
  from address ma, 
     ( select maxa.b_id, max(maxa.a_id) a_id, count(*) c
       from address maxa
       group by maxa.b_id ) m
  where ma.a_id = m.a_id;

上記の「A」インラインビューは、変換されたアドレスのセットを最終的なクエリに配信します。BUILDINGとADDRESSの関係は1から0..nですが、BUILDINGと「A」の関係は1から0..1で、基本的な外部結合です。

select b.b_id, b.b_code, b.b_name, a.*
 from building b, 
    ( select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c
      from address ma, 
         ( select maxa.b_id, max(maxa.a_id) a_id, count(*) c
           from address maxa
           group by maxa.b_id ) m
      where ma.a_id = m.a_id ) a
 where b.b_id = a.b_id (+);

このアプローチの主な利点は次のとおりです。

  1. 任意の数のアドレス列を配信します。
  2. 決定論的で、実行するたびにまったく同じ結果を返します。
  3. 最終的なクエリに過度の複雑さを課すことはありません。これは確かにこれよりも複雑になります。
  4. 「A」インラインビューは、データベースビュー内に簡単にカプセル化できます。おそらく、LATEST_ADDRESSビューと呼びます。
create view latest_address (b_id, a_id, addr1, addr2, addr3, c) as
select ma.b_id, ma.a_id, ma.addr1, ma.addr2, ma.addr3, m.c
 from address ma, 
    ( select maxa.b_id, max(maxa.a_id) a_id, count(*) c
      from address maxa
      group by maxa.b_id ) m
 where ma.a_id = m.a_id;

select b.b_id, b.b_code, b.b_name, a.*
 from building b, latest_address a
 where b.b_id = a.b_id (+);

楽しみ!
マシュー

于 2010-02-25T13:47:09.437 に答える
0

あなたができることは、参加するアドレスの制限です。たとえば、より低い ID を持つアドレスがないことを要求することによって:

select *
from building b
left join addresses a on (a.buildingid = b.id)
where not exists (select 1 from addresses a2
                  where a2.buildingid = b.id and a2.id < a.id)

この場合、建物ごとに最大 1 つのアドレスを取得します。

于 2010-02-24T21:25:40.680 に答える