web-dev-qa-db-ja.com

一番下の行を選択する方法は?

SELECT TOP(200)を実行できますが、BOTTOM(200)を実行できないのはなぜですか?

私が意味することを哲学に入らないために、どうすればTOP(200)に相当することができますか?

90
MetaGuru
SELECT
    columns
FROM
(
     SELECT TOP 200
          columns
     FROM
          My_Table
     ORDER BY
          a_column DESC
) SQ
ORDER BY
     a_column ASC
80
Tom H

不要です。 ORDER BYを使用し、ソートをDESCに変更するだけで同じ効果を得ることができます。

91
Justin Ethier

申し訳ありませんが、私の意見では正しい答えが見当たらないと思います。

TOP x関数は、未定義の順序でレコードを表示します。その定義から、BOTTOM関数は定義できません。

インデックスまたは並べ替え順序に依存しません。 ORDER BY y DESCを実行すると、最初に最高のy値を持つ行が取得されます。これが自動生成されたIDである場合、他の回答で提案されているように、テーブルに最後に追加されたレコードを表示する必要があります。しかしながら:

  • これは、自動生成されたid列がある場合にのみ機能します
  • TOP関数と比較すると、パフォーマンスに大きな影響があります。

正しい答えは、一番下の行を取得するためのTOPに相当するものは存在せず、存在しないことです。

37
Martijn Burger

従業員から下位1000を選択

DECLARE 
@bottom int,
@count int

SET @bottom = 1000 
SET @count = (select COUNT(*) from Employee)

select * from Employee emp where emp.EmployeeID not in 
(
SELECT TOP (@count-@bottom) Employee.EmployeeID FROM Employee
)
15
Shadi Namrouti

「ジャスティンエティエ」によって現在受け入れられている答えは、「プロテクター1」によって指摘されているように正しい答えではありません。

私の知る限り、今のところ、質問の著者が求めたBOTTOM(x)に相当する答えやコメントはありません。

まず、この機能が必要になるシナリオを考えてみましょう。

SELECT * FROM Split('Apple,orange,banana,Apple,Lime',',')

これは、1つの列と5つのレコードのテーブルを返します。

  • Apple
  • オレンジ
  • バナナ
  • Apple
  • ライム

ご覧のとおり、ID列はありません。返された列で並べ替えることはできません。また、標準のSQLを使用して、上位2つのレコードに対して実行できるように、下位2つのレコードを選択することはできません。

これが解決策を提供する私の試みです。

SELECT * INTO #mytemptable FROM Split('Apple,orange,banana,Apple,Lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
SELECT TOP 2 * FROM #mytemptable ORDER BY tempID DESC
DROP TABLE #mytemptable

そして、より完全なソリューションは次のとおりです。

SELECT * INTO #mytemptable FROM Split('Apple,orange,banana,Apple,Lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
DELETE FROM #mytemptable WHERE tempID <= ((SELECT COUNT(*) FROM #mytemptable) - 2)
ALTER TABLE #mytemptable DROP COLUMN tempID
SELECT * FROM #mytemptable
DROP TABLE #mytemptable

私はこれがすべての状況で使用するのが良い考えであると決して主張しませんが、それは望ましい結果を提供します。

3
tomosius

ソリューションでORDER BY句を実装する回答のいずれかがポイントを失っているか、TOPが返す内容を実際に理解していないようです。

TOPは、順序付けされていないクエリ結果セットを返します。これは、返されるレコードセットを最初のNレコードに制限します。 (Oracleの観点からは、where ROWNUM <(N + 1)を追加することに似ています。

順序を使用するソリューションmayは、TOP句によって返される行を返します(最初にデータセットが順序付けられていないため)。

TOPの有用性は、データセットが特定のサイズNに達すると、行のフェッチを停止することです。データをすべて取得しなくても、データがどのように見えるかを感じることができます。

BOTTOMを正確に実装するには、データセット全体を順不同でフェッチしてから、データセットを最後のNレコードに制限する必要があります。巨大なテーブルを扱っている場合、それは特に効果的ではありません。また、それは必ずしもあなたに何を提供するものでもありません思考あなたが求めているものです。データセットの終わりは、必ずしも「最後に挿入された行」であるとは限りません(おそらく、ほとんどのDML集中型アプリケーションには当てはまりません)。

同様に、ORDER BYを実装するソリューションは、残念ながら、大きなデータセットを処理するときに悲惨な結果を招く可能性があります。たとえば、100億のレコードがあり、最後の10個が必要な場合、100億のレコードを注文して最後の10個を選択するのは非常に愚かなことです。

ここでの問題は、BOTTOMがTOPと比較するときに思考という意味を持たないことです。

レコードが何度も挿入、削除、挿入、削除されると、ストレージにいくつかのギャップが生じ、その後、可能であれば行が挿入されます。しかし、TOPを選択したときによく見られるのは、テーブルの存在の早い段階で挿入された可能性があるため、ソートデータとしてappearsです。テーブルで多くの削除が行われない場合、appearが順序付けられます。 (例:作成日は、テーブルの作成自体と同じくらい古い場合があります)。しかし、現実には、これが削除が多いテーブルである場合、TOP N行はまったくそのように見えないかもしれません。

つまり、ここでの結論(しゃれが意図されている)は、BOTTOM Nレコードを要求している人は、実際に彼らが何を要求しているかを知らないということです。または、少なくとも、彼らが求めているものとBOTTOMが実際に意味するものは同じものではありません。

そのため、ソリューションはリクエスターの実際のビジネスニーズを満たすことができますが、BOTTOMであるための基準を満たしていません。

2
user9323238

必要なことは、ORDER BYを逆にすることだけです。 DESCを追加または削除します。

2
Justin Swartsel

上記の「Tom H」の答えは正解で、下5行を取得するのに役立ちます。

SELECT [KeyCol1], [KeyCol2], [Col3]
FROM
(SELECT TOP 5 [KeyCol1],
       [KeyCol2],
       [Col3]
  FROM [dbo].[table_name]
  ORDER BY [KeyCol1],[KeyCol2] DESC) SOME_ALAIS
  ORDER BY [KeyCol1],[KeyCol2] ASC

ありがとう。

1
user3598017
SELECT TOP 10*from TABLE1 ORDER BY ID DESC

IDはTABLE1の主キーです。

1
Er. Binod Mehta

他の方法での順序付けの問題は、インデックスをうまく利用しないことが多いということです。また、開始または終了にない行の数を選択する必要がある場合は、あまり拡張できません。別の方法は次のとおりです。

DECLARE @NumberOfRows int;
SET @NumberOfRows = (SELECT COUNT(*) FROM TheTable);

SELECT col1, col2,...
FROM (
    SELECT col1, col2,..., ROW_NUMBER() OVER (ORDER BY col1) AS intRow
    FROM TheTable
) AS T
WHERE intRow > @NumberOfRows - 20;
1
Paul

返される行の数を知る必要のないこれに対する解決策を考え出しました。

たとえば、最新の1(または2、5、または34)を除くすべての場所をテーブルに記録する場合

SELECT * 
FROM
    (SELECT ROW_NUMBER() OVER (ORDER BY CreatedDate) AS Row, * 
    FROM Locations
    WHERE UserId = 12345) AS SubQuery
WHERE Row > 1 -- or 2, or 5, or 34
0
Red

まず、次を使用して、テーブルの元の順序に従ってサブクエリにインデックスを作成します。

ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex

次に、メインクエリで作成したRowIndex列の降順にテーブルを並べ替えます。

ORDER BY RowIndex DESC

最後に、必要な行数でTOPを使用します。

    SELECT TOP 1 * --(or 2, or 5, or 34)
    FROM   (SELECT ROW_NUMBER() OVER (ORDER BY  (SELECT NULL) ) AS RowIndex, * 
            FROM MyTable) AS SubQuery
    ORDER BY RowIndex DESC
0
Thiago Marques

単純なサブクエリを降順でソートし、次に同じ列を昇順でソートするクエリは、トリックを行います。

SELECT * FROM 
    (SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
    ORDER BY t1.[column]
0
sheppe

これを試して。

declare @floor int --this is the offset from the bottom, the number of results to exclude
declare @resultLimit int --the number of results actually retrieved for use
declare @total int --just adds them up, the total number of results fetched initially

--following is for gathering top 60 results total, then getting rid of top 50. We only keep the last 10
set @floor = 50 
set @resultLimit = 10
set @total = @floor + @resultLimit

declare @tmp0 table(
    --table body
)

declare @tmp1 table(
    --table body
)

--this line will drop the wanted results from whatever table we're selecting from
insert into @tmp0
select Top @total --what to select (the where, from, etc)

--using floor, insert the part we don't want into the second tmp table
insert into @tmp1
select top @floor * from @tmp0

--using select except, exclude top x results from the query
select * from @tmp0
except 
select * from @tmp1
0
HumbleWebDev