0

Test という名前の 2 つのテーブルがあり、TestHistory の testHistory には Test との FK 関係があります。

テスト テーブル データ

testHistory テーブル データ

ここで、テスト テーブル レコードを含むテーブル TestHistory から挿入された上位 1 データを選択します。

私の望ましい出力は次のようになります。

ここに画像の説明を入力

または、 TestHistory テーブルに TestId に関連するレコードが含まれている必要がない場合、出力は次のようになります。

ここに画像の説明を入力

次のようなサブクエリでこれを達成しました:

Select Id,(select top(1) price from TestHistory HT Where T.Id=HT.TestId order by HT.Id desc) As Price 

From Test T

しかし、そのためにサブクエリを使用したくありません。サブクエリなしでデータを選択したい。

サブクエリなしでそれを行う方法を教えてください。これを解決するための最良の代替方法は何ですか。

4

2 に答える 2

1

これを行う最も簡単な方法は、 を使用row_number()して結果を取得することだと思いますが、それでもサブクエリがあります。ただし、これは相関サブクエリにはなりません。

select id, price, testhistoryid
from
(
  select t.id,
    h.price,
    h.id testhistoryid,
    row_number() over(partition by t.id order by h.id desc) rn
  from test t
  inner join testhistory h
    on t.id = h.testid
) src
where rn = 1;

SQL Fiddle with Demoを参照してください。

test行が履歴テーブルに存在しない場合に行を返したい場合は、 のLEFT JOIN代わりにを使用しINNER JOINます。

select id, price, testhistoryid
from
(
  select t.id,
    h.price,
    h.id testhistoryid,
    row_number() over(partition by t.id order by h.id desc) rn
  from test t
  left join testhistory h
    on t.id = h.testid
) src
where rn = 1;

デモを見る

于 2013-04-24T19:05:55.317 に答える
0

申し訳ありませんが、ある種のサブクエリなしでこれを行う実際の方法はありません。あなたが書いたクエリは問題ありません。私の意見では、探しているものを達成するための最良の構文は次のとおりです。

SELECT
   T.ID,
   HT.*
FROM
   dbo.Test T
   OUTER APPLY (
      SELECT TOP 1 *
      FROM dbo.TestHistory HT
      WHERE T.ID = HT.TestID
      ORDER BY HT.ID DESC
   ) HT
;

SQL Fiddle でこれを試してみてください

Test一致する行を持つ行のみが表示されるように制限する場合は、代わりに をTestHistory使用します。CROSS APPLYOUTER APPLY

また、このようなクエリは可能であり、理解しやすいかもしれませんが、パフォーマンスが低下する可能性が高く、さらにTestHistory各行に少なくとも 1 つの行が必要Testです。

SELECT
   T.ID,
   HT.*
FROM
   dbo.Test T
   INNER JOIN dbo.TestHistory HT
      ON T.ID = HT.TestID
WHERE
   HT.ID = (
      SELECT Max(HT2.ID)
      FROM dbo.TestHistory HT2
      WHERE T.ID = HT2.TestID
   )
;

ソリューションを使用することもできますが、それが利用可能な場合、それはとRow_Number()同じように機能しないことが多いため、私はそれから遠ざかる傾向があります.CROSS APPLYTOP

SELECT
   T.ID,
   HT.TestID,
   HT.Price
FROM
   dbo.Test T
   LEFT JOIN (
      SELECT
         Selector = Row_Number() OVER (
            PARTITION BY HT.TestID ORDER BY HT.ID DESC
         ),
         *
      FROM dbo.TestHistory HT
   ) HT
      ON T.ID = HT.TestID
      AND HT.Selector = 1
;

SQL Fiddle でこれを試してみてください

TOP 1そのソリューションまたはソリューションのパフォーマンスが優れているかどうかを確認する唯一の方法Row_Number()は、適切に代表的な多数のデータを使用して、データベース内の各ソリューションを試すことです。履歴エントリがほとんどなく、メイン エントリが非常に多い場合は、 を使用するとより良い結果が得られる可能性Row_Number()があります。ただし、メイン エントリごとに多数の履歴エントリがある場合は、このTOP方法が最適なパフォーマンスを発揮する可能性があります。

テーブルのインデックスも大きな違いを生む可能性があります。適切なテーブル アクセスを許可する適切なインデックスがあることを確認します (たとえば、PK が on であっても、テーブルのクラスター化インデックスは on にTestHistoryする必要があります)。毎回テーブル全体をクエリする場合、インデックスはそれほど重要ではないかもしれませんが、行のセットを制限する条件が発生した瞬間に、インデックスは非常に重要になります。TestID, IDIDTest

于 2013-04-24T19:19:41.197 に答える