回答:
SELECT
columns
FROM
(
SELECT TOP 200
columns
FROM
My_Table
ORDER BY
a_column DESC
) SQ
ORDER BY
a_column ASC
不要です。を使用しORDER BY
て並べ替えを変更するだけでDESC
、同じ効果を得ることができます。
申し訳ありませんが、私の意見では正しい答えは見当たらないと思います。
TOP
X機能は、未定義の順序でレコードを示しています。その定義から、BOTTOM
関数を定義することはできません。
インデックスや並べ替え順序に依存しません。実行するORDER BY y DESC
と、最も高いy値を持つ行が最初に取得されます。これが自動生成されたIDの場合、他の回答で提案されているように、テーブルに最後に追加されたレコードが表示されます。しかしながら:
TOP
関数と比較すると、パフォーマンスに大きな影響があります。正解はTOP
、一番下の行を取得するのと同じことはあり得ません。
論理的には、
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
たとえば、従業員から下1000を選択します。
T-SQLでは、
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
)
ソリューションにORDER BY句を実装する回答のいずれかが要点を欠いている、または実際にTOPが返すものを理解していないようです。
TOPは、レコードセットを最初のN個のレコードに制限する、順序付けされていないクエリ結果セットを返します。(Oracleの観点からは、WHERE NUM <(N + 1)を追加するのと同じです。
順序を使用するソリューションは、TOP句によって返される行を返す場合があります(データセットが最初に順序付けされていないため)。
TOPの有用性は、データセットが特定のサイズNに達すると、行のフェッチを停止することです。データをすべてフェッチしなくても、データがどのように見えるかを感じることができます。
BOTTOMを正確に実装するには、データセット全体を順序付けずにフェッチしてから、データセットを最後のNレコードに制限する必要があります。巨大なテーブルを扱っている場合、これは特に効果的ではありません。それは必ずしもあなたがあなたが求めていると思うことをあなたに与えるわけでもありません。データセットの最後が必ずしも「最後に挿入された行」であるとは限りません(おそらく、ほとんどのDML集中型アプリケーションではそうではありません)。
同様に、ORDER BYを実装するソリューションは、残念ながら、大規模なデータセットを処理する場合に悲惨な結果をもたらす可能性があります。たとえば、100億件のレコードがあり、最後の10件が必要な場合、100億件のレコードを注文して、最後の10件を選択するのは非常に愚かです。
ここでの問題は、BOTTOMがTOPと比較するときに私たちが考える意味を持たないことです。
レコードが何度も挿入、削除、挿入、削除されると、一部のギャップがストレージに表示され、その後、可能であれば行が挿入されます。しかし、TOPを選択すると、テーブルの存在の早い段階で挿入された可能性があるため、よく見られるのはソートされたデータのようです。テーブルで多くの削除が行われない場合、順序付けされているように見えることがあります。(たとえば、作成日はテーブル作成自体と同じくらい前の日付になる場合があります)。しかし、実際には、これが削除の多いテーブルである場合、TOP N行はまったくそのように見えない可能性があります。
つまり、ここでの一番下の行(しゃれた意図)は、BOTTOM Nレコードを要求している誰かが実際に何を要求しているのかを知らないということです。または、少なくとも、彼らが求めていることと実際にBOTTOMが意味していることは同じではありません。
したがって、ソリューションはリクエスタの実際のビジネスニーズを満たす可能性がありますが、最下位であるための基準を満たしていません。
insert
ステートメントを実行して、行をインデックスのない大きなテーブルに入れました。(インデックスを作成する前に、最初にテーブルにデータを入力しています。)再起動などでクライアントセッションが失われました。次に、新しく追加した行がそこにあるかどうかを確認します。テーブルの「一番下」の行が最近の行の1つである場合、操作が完了したことがわかります。「下」行が何か別の場合、保証はありません。テーブル全体をスキャンして確認する必要があります...しかし、「下」をできるだけ早くチェックすることで、時間を節約できます。上'。
「ジャスティンエティエ」が現在認めている回答は、「プロテクター1」が指摘しているように正解ではありません。
私の知る限り、現時点では、他の回答やコメントは、作者が要求したBOTTOM(x)に相当するものを提供していません。
最初に、この機能が必要になるシナリオを考えてみましょう。
SELECT * FROM Split('apple,orange,banana,apple,lime',',')
これは、1つの列と5つのレコードのテーブルを返します。
ご覧のとおり、ID列はありません。返された列で並べ替えることはできません。上位2つのレコードの場合のように、標準SQLを使用して下位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
私はこれがすべての状況で使用するのが良い考えであるとは決して主張していませんが、望ましい結果を提供します。
あなたがする必要があるのはあなたのを逆にしますORDER BY
。追加または削除DESC
します。
逆の順序での問題は、インデックスをうまく利用しないことが多いことです。また、先頭または末尾にない複数の行を選択する必要がある場合も、あまり拡張可能ではありません。別の方法は次のとおりです。
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;
上記の "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
ありがとう。
これを試して。
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
まず、次を使用して、テーブルの元の順序に従ってサブクエリにインデックスを作成します。
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