Mogę zrobić SELECT TOP (200) ... ale dlaczego nie BOTTOM (200)?
Cóż, nie wchodząc w filozofię, mam na myśli to, jak mogę zrobić odpowiednik TOP (200), ale odwrotnie (od dołu, tak jak można by się spodziewać, że zrobi to BOTTOM ...)?
Odpowiedzi:
SELECT
columns
FROM
(
SELECT TOP 200
columns
FROM
My_Table
ORDER BY
a_column DESC
) SQ
ORDER BY
a_column ASC
To jest niepotrzebne. Możesz użyć ORDER BY
i po prostu zmienić sortowanie na, DESC
aby uzyskać ten sam efekt.
Przepraszam, ale moim zdaniem nie widzę żadnych poprawnych odpowiedzi.
Funkcja TOP
x wyświetla rekordy w nieokreślonej kolejności. Z tej definicji wynika, że aBOTTOM
funkcji nie można zdefiniować.
Niezależnie od jakiegokolwiek indeksu lub porządku sortowania. Kiedy to zrobisz, ORDER BY y DESC
najpierw otrzymasz wiersze z najwyższą wartością y. Jeśli jest to identyfikator wygenerowany automatycznie, powinien pokazywać rekordy ostatnio dodane do tabeli, jak sugerowano w innych odpowiedziach. Jednak:
TOP
funkcją, ma to znaczący wpływ na wydajnośćPrawidłowa odpowiedź powinna być taka, że nie ma i nie może być odpowiednika TOP
dla uzyskania najniższych wierszy.
Logicznie
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
Np. Wybierz dolne 1000 od pracownika:
W 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
)
Wydawałoby się, że którakolwiek z odpowiedzi, które implementują klauzulę ORDER BY w rozwiązaniu, nie ma sensu lub w rzeczywistości nie rozumie, co TOP Ci zwraca.
TOP zwraca nieuporządkowany zestaw wyników zapytania, który ogranicza zestaw rekordów do pierwszych N zwróconych rekordów. (Z punktu widzenia Oracle jest to podobne do dodania gdzie ROWNUM <(N + 1).
Każde rozwiązanie korzystające z zamówienia może zwrócić wiersze, które również są zwracane przez klauzulę TOP (ponieważ ten zbiór danych był w pierwszej kolejności nieuporządkowany), w zależności od kryteriów zastosowanych w zamówieniu przez
Użyteczność TOP polega na tym, że gdy zbiór danych osiągnie pewien rozmiar N, przestaje pobierać wiersze. Możesz zobaczyć, jak wyglądają dane, bez konieczności pobierania ich wszystkich.
Aby dokładnie zaimplementować BOTTOM, należałoby pobrać cały zestaw danych w nieuporządkowany sposób, a następnie ograniczyć go do ostatecznych N rekordów. Nie będzie to szczególnie skuteczne, jeśli masz do czynienia z dużymi stołami. Niekoniecznie też da ci to, co myślisz że prosisz. Koniec zbioru danych niekoniecznie musi oznaczać „ostatnie wstawione wiersze” (i prawdopodobnie nie będzie to miało miejsce w przypadku większości aplikacji intensywnie korzystających z DML).
Podobnie rozwiązania, które implementują ORDER BY są niestety potencjalnie katastrofalne w przypadku dużych zbiorów danych. Jeśli mam, powiedzmy, 10 miliardów rekordów i chcę ostatnich 10, to głupotą jest zamówienie 10 miliardów rekordów i wybranie ostatnich 10.
Problem polega na tym, że BOTTOM nie ma takiego znaczenia, o jakim myślimy , porównując go z TOP.
Kiedy rekordy są wstawiane, usuwane, wstawiane i usuwane w kółko, w pamięci pojawią się luki, a później wiersze zostaną wstawione, jeśli to możliwe. Ale to, co często widzimy, kiedy wybieramy TOP, wydaje się być posortowanymi danymi, ponieważ mogły zostać wstawione na początku istnienia tabeli. Jeśli w tabeli nie występuje wiele usunięć, może wydawać się, że jest uporządkowana. (np. daty utworzenia mogą być tak odległe w czasie, jak samo utworzenie tabeli). Ale rzeczywistość jest taka, że jeśli jest to tabela z dużą ilością usuwania, to TOP N wierszy może wcale tak nie wyglądać.
Tak więc - najważniejsze tutaj (gra słów zamierzona) jest to, że ktoś, kto prosi o nagrania BOTTOM N, tak naprawdę nie wie, o co proszą. A przynajmniej to, o co proszą i co właściwie oznacza DOLNY, nie jest tym samym.
A więc - rozwiązanie może spełniać rzeczywiste potrzeby biznesowe żądającego… ale nie spełnia kryteriów bycia DOLNYM.
insert
polecenie, aby umieścić wiersze w dużej, niezindeksowanej tabeli. (Najpierw zapełniam tabelę, zanim zacznę ją indeksować). Straciłem sesję klienta z powodu ponownego uruchomienia komputera lub czegoś innego, a teraz chcę sprawdzić, czy są tam moje nowo dodane wiersze. Jeśli „dolny” wiersz tabeli jest jednym z ostatnich, to wiem, że operacja została zakończona. Jeśli „dolny” wiersz jest czymś innym, cóż, nie ma żadnych gwarancji i muszę przeskanować całą tabelę, aby się upewnić ... ale najprawdopodobniej mógłbym zaoszczędzić trochę czasu, szybko sprawdzając „dół”, tak jak możesz. Top'.
Aktualnie przyjęta odpowiedź przez „Justina Ethiera” nie jest poprawną odpowiedzią, jak wskazał „Protektor jeden”.
O ile widzę, na razie żadna inna odpowiedź ani komentarz nie jest odpowiednikiem BOTTOM (x), o które zadał autor pytania.
Najpierw rozważmy scenariusz, w którym ta funkcjonalność byłaby potrzebna:
SELECT * FROM Split('apple,orange,banana,apple,lime',',')
Zwraca tabelę składającą się z jednej kolumny i pięciu rekordów:
Jak widać: nie mamy kolumny ID; nie możemy złożyć zamówienia według zwróconej kolumny; i nie możemy wybrać dwóch ostatnich rekordów za pomocą standardowego SQL, tak jak możemy to zrobić dla dwóch górnych rekordów.
Oto moja próba rozwiązania:
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
A oto bardziej kompletne rozwiązanie:
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
W żadnym wypadku nie twierdzę, że jest to dobry pomysł w każdych okolicznościach, ale zapewnia pożądane rezultaty.
Wszystko, co musisz zrobić, to odwrócić ORDER BY
. Dodaj lub usuń DESC
do niego.
Problem z kolejnością w drugą stronę polega na tym, że często nie wykorzystuje ona dobrze indeksów. Nie można go również zbytnio rozszerzać, jeśli kiedykolwiek zajdzie potrzeba wybrania liczby wierszy, które nie znajdują się na początku ani na końcu. Alternatywny sposób jest następujący.
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;
Powyższa odpowiedź „Tom H” jest prawidłowa i działa w moim przypadku przy uzyskiwaniu 5 ostatnich wierszy.
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
Dzięki.
Spróbuj tego.
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
Wymyśliłem rozwiązanie tego problemu, które nie wymaga znajomości liczby zwróconych wierszy.
Na przykład, jeśli chcesz, aby wszystkie lokalizacje zostały zarejestrowane w tabeli, z wyjątkiem ostatniej 1 (lub 2 lub 5 lub 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
SELECT TOP 10*from TABLE1 ORDER BY ID DESC
Gdzie ID jest kluczem podstawowym tabeli TABLE1.
Najpierw utwórz indeks w podzapytaniu zgodnie z pierwotną kolejnością tabeli, używając:
ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex
Następnie uporządkuj tabelę malejąco według RowIndex
kolumny utworzonej w głównym zapytaniu:
ORDER BY RowIndex DESC
I na koniec użyj TOP
z żądaną liczbą rzędów:
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