4

非常に複雑な動的SQLを作成しています。ユーザーごとに1行を返す必要がありますが、1対多のテーブルに対して結合する必要があります。少なくとも1つの行が返されることを確認するために外部結合を実行します(そして、そのテーブルにデータがあるかどうかを確認するためにnullをチェックできます)が、複数ある場合は、この外部結合部分から1行だけ戻るようにする必要がありますこのユーザーのこの2番目のテーブルの行。これまでのところ、私はこれを思いついた:( sybase)

SELECT a.user_id
FROM table1 a
    ,table2 b
WHERE a.user_id = b.user_id
AND a.sub_id = (
    SELECT min(c.sub_id)
    FROM table2 c
    WHERE b.sub_id = c.sub_id
    )

サブクエリは、その特定のユーザーの1対多のテーブルで最小値を検索します。

これは機能しますが、表1と表2が非常に大きくなると、相関サブクエリを実行することによる不快感を恐れます。もっと良い方法はありますか?私はそれを行うために参加する方法を夢見ようとしていますが、私はそれを見ていません。また、「where rowcount = 1」または「top1」と言っても役に立ちません。上記のクエリを修正しようとしているのではないため、すでに複雑なクエリに上記を追加しています。

4

6 に答える 6

1

MySql では、クエリが最大 X 行を返すことを保証できます。

select *
from foo
where bar = 1
limit X;

残念ながら、これは SQL に対する MySQL 固有の拡張機能であると確信しています。ただし、「mysql sybase limit」などを Google で検索すると、Sybase に相当するものが見つかる場合があります。

于 2008-10-27T14:37:29.103 に答える
1

いくつかの簡単なポイント:

  1. 明確なビジネス ルールが必要です。クエリが複数の行を返す場合は、その理由を考える必要があります (単に「1 対多の関係である - なぜ 1 対多の関係なのか?)」だけではなく、「 min" というのは、1 行が得られるからです。ビジネス上の解決策は単純に "最初の行を取得する" かもしれません。この場合、min が答えかもしれませんが、それが意識的な決定であることを確認する必要があります。
  2. 結合には ANSI 構文を使用するようにしてください。それが標準的であるという理由だけでなく、あなたが持っている構文があなたが思っていることを実際には行っていないため (外部結合ではありません)、あなたが持っている構文ではいくつかのことが単純に不可能だからです。

最終的に MIN ソリューションを使用すると仮定すると、サブクエリを使用しない場合に考えられるソリューションの 1 つを次に示します。他のさまざまなソリューションでテストして、結果が同等であることを確認し、どれが最高のパフォーマンスを発揮するかを確認する必要があります。

SELECT
     a.user_id, b.*
FROM
     dbo.Table_1 a
LEFT OUTER JOIN dbo.Table_2 b ON b.user_id = a.user_id AND b.sub_id = a.sub_id
LEFT OUTER JOIN dbo.Table_2 c ON c.user_id = a.user_id AND c.sub_id < b.sub_id
WHERE
     c.user_id IS NULL

これをテストして、本当に必要なものを提供しているかどうかを確認する必要がありますが、微調整が必​​要になる場合がありますが、基本的な考え方は、2 番目の LEFT OUTER JOIN を使用して、sub_id がそれよりも低い行が存在しないようにすることです。最初の LEFT OUTER JOIN で見つかったもの (見つかった場合)。最終的なビジネス ルールに応じて、2 番目の LEFT OUTER JOIN の基準を調整できます。

于 2008-10-27T15:11:37.677 に答える
0

あなたの例は単純すぎるかもしれませんが、私は次のグループを使用します:

選択する
  a.user_id
から
  表1a
    LEFT OUTER JOIN table2 b ON(a.user_id = b.user_id)
GROUP BY
  a.user_id

他の唯一の方法は、ネストされたクエリを使用することだと思います。

このクエリと例の違いは、「サブテーブル」は1回だけ生成されることですが、この例では、table1の各行に対して「サブテーブル」を生成します(ただし、コンパイラによって異なる場合があるため、クエリを使用することをお勧めします。パフォーマンスをチェックするアナライザー)。

選択する
  a.user_id、
  b.sub_id
から
  表1a
    LEFT OUTER JOIN(
      選択する
        ユーザーID、
        min(sub_id)as sub_id、
      から
        表2
      GROUP BY
        ユーザーID
    )b ON(a.user_id = b.user_id)

また、クエリが非常に複雑になっている場合は、一時テーブルを使用してコードを簡略化すると、処理時間が少し長くなる可能性がありますが、クエリの保守がはるかに簡単になります。

一時テーブルの例は次のようになります。

選択する
  ユーザーID
の中へ
  #表1
から
  表1
どこ
  ....。

選択する
  a.user_id、
  min(b.sub_id)as sub_id、
の中へ
  #table2
から
  #table1 a
    INNER JOIN table2 b ON(a.user_id = b.user_id)
GROUP BY
  a.user_id

選択する
  a。*、
  b.sub_id
から
  #table1 a
    LEFT OUTER JOIN#table2 b ON(a.user_id = b.user_id)
于 2008-10-27T13:55:53.930 に答える
0

どうですか:

select a.user_id 
from table1 a
where exists (select null from table2 b 
              where a.user_id = b.user_id 
             )
于 2008-10-27T14:21:11.147 に答える
0

まず第一に、あなたの例としてあなたが書こうとしているクエリは次のとおりだと思います:

select a.user_id 
from table1 a, table2 b 
where a.user_id = b.user_id 
and b.sub_id = (select min(c.sub_id) 
                from table2 c 
                where b.user_id = c.user_id)

あなたが外部結合を望んでいたことを除いて(誰かがOracle構文を編集したと思います)。

select a.user_id 
from table1 a
left outer join table2 b on a.user_id = b.user_id 
where b.sub_id = (select min(c.sub_id) 
                from table2 c 
                where b.user_id = c.user_id)
于 2008-10-27T14:51:34.813 に答える
-1

さて、あなたはすでに機能するクエリを持っています。速度が気になる場合は

  • どの sub_id が「最初のもの」であるかを識別するフィールドを table2 に追加します。

  • table1 または別のテーブルで table2 の主キーを追跡する

于 2008-10-27T15:16:10.053 に答える