2010-05-05 9 views
12

Potrzebuję rozwiązania dla zapytania kwerendy w Sql Server 2005.Czy istnieje sposób, aby podzielić wyniki kwerendy wyboru na dwie równe połowy?

Chciałbym mieć kwerendę zwracającą dwa ResultSet, z których każdy posiada dokładnie połowę wszystkich rekordów pasujących do określonych kryteriów. Próbowałem użyć TOP 50 PERCENT w połączeniu z Kolejnością, ale jeśli liczba rekordów w tabeli jest nieparzysta, jeden rekord pojawi się w obu zestawach wyników. Nie chcę, aby jakiekolwiek rekordy były duplikowane w zestawach rekordów. Przykład:

Mam prosty tabela z TheID (PK) i TheValue pola (varchar (10)) i 5 rekordów. Pomiń teraz klauzulę where.

SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID asc 

powoduje wybranego identyfikatora 1,2,3

SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID desc 

wyników w wybranych identyfikatora 3,4,5

3 jest DUP. W rzeczywistości oczywiście zapytania są dość skomplikowane z mnóstwem zdań i podkwerend.

+0

zakładam to SQL Server? –

+1

Kto zużywa te dwa zapytania? Jeśli obaj konsumenci są świadomi siebie nawzajem (przypuszczalnie na podstawie ich wyników), dlaczego nie pobrać całej listy i podzielić ją po stronie konsumenta, aby nie było duplikatów? –

+0

tak. przepraszam, zapomniałem o tym wspomnieć. – Mats

Odpowiedz

34

SQL Server 2005 i podobne:

select *, ntile(2) over(order by theid) as tile_nr from thetable 

ntile(n) przydziela wyjście do n segmentów, każdy o tej samej wielkości (lub dać zaokrąglania podczas liczba wierszy nie jest podzielna przez n). Więc to daje wynik:

1 | value1 | 1 
2 | value2 | 1 
3 | value3 | 1 
4 | value4 | 2 
5 | value5 | 2 

Jeśli chcesz po prostu górną lub dolną połowę, trzeba umieścić to do podzapytania, np

select theid, thevalue from (
    select theid, thevalue, ntile(2) over(order by theid) as tile_nr from thetable 
) x 
where x.tile_nr = 1 

powróci górną połowę i podobnie korzystania x.tile_nr = 2 dla dolna połowa

+1

+1, przetestowałem to na moim systemie. @Thomas, nie ma "partycji przez", po prostu 'order by' –

+2

@KM - Tak, testowany również na moim systemie. To jest dla mnie najmądrzejsze rozwiązanie przy założeniu SQL2k5 +. – Thomas

+0

+1 jedną z najczęściej pomijanych funkcji rankingowych! Świetna odpowiedź –

6

Można wykorzystać te dwa zapytania:

SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY TheID) AS rn FROM TheTable 
) T1 
WHERE rn % 2 = 0 

SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY TheID) AS rn FROM TheTable 
) T1 
WHERE rn % 2 = 1 
+0

Moja myśl dokładnie. – corsiKa

+1

Zdecydowanie realna odpowiedź. Ale czy to nie rozdziela rozkładu połówek? W PO otrzymuje "górną połowę" i "dolną połowę", w przeciwieństwie do "dwóch niewykwalifikowanych połówek". –

+0

@ Mark Canlas: Masz rację. Czytałem pytanie, że nie ma znaczenia, w której połowie jest każdy rekord, o ile liczba wierszy jest poprawna. Ale masz rację, że pytanie można interpretować w dowolny sposób. –

1

spróbować tego:

DECLARE @CountOf int,@Top int,@Bottom int 
SELECT @CountOf=COUNT(*) FROM YourTable 
SET @[email protected]/2 
SET @[email protected]@Top 
SELECT TOP (@Top) * FROM YourTable ORDER BY 1 asc --assumes column 1 is your PK 
SELECT TOP (@Bottom) * FROM YourTable ORDER BY 1 desc --assumes column 1 is your PK 
2

Jeśli jest to SQL Server 2000, a następnie Byłbym skłonny znaleźć PK wartości środkowej tak:

Declare @MiddleId int 

Set @MiddleId = (
       Select TOP 1 PK 
       From (
         Select TOP 50 PERCENT PK 
         From Table 
         Order By TheId ASC 
         ) 
       Order By TheId DESC 
       ) 

Select ... 
From Table 
Where TheId <= @MiddleId 

Select .. 
From Table 
Where TheId > @MiddleId 

SQL Server 2005, byłbym skłonny zrobić to samo, ale można użyć CTE

;With NumProjects As 
    (
    Select Id, ROW_NUMBER() OVER (ORDER BY TheId ASC) As Num 
    From Table 
    ) 
Select @MiddleId = Id 
From Table 
Where Num = CEILING((Select Count(*) From Table)/2) 
0

to the query mogę znaleźć przydatne (po modyfikacji, oczywiście):

DECLARE @numberofitemsperpage INT DEKLARUJĄ @numberofpages INT DEKLARUJĄ @currentpage int

Declare @countRecords pływak SET @countRecords = (select count (*) Od sz_hold_visitsData) - Excel może pomieścić około miliona rekordów naraz.jeśli @countRecords> = 1000000 SET @numberofitemsperpage = 500000 else if @countRecords < 1000000 I @countRecords> = 500000 SET @numberofitemsperpage = 250000 else if @countRecords < 500000 I @countRecords> = 100000 = 50000 SET @numberofitemsperpage ELSE SET @numberofitemsperpage = 10000

DECLARE @numberofpages_deci pływak SET @numberofpages_deci = @countRecords/@numberofitemsperpage

SET @numberofpages = pułap (@numberofpages_deci) Wybór @countRecords AS countRecords, @numberofitemsperpage CO numberofitemsperpage, @numberofpages_deci CO numberofpages_deci, @numberofpages CO numberofpagesFnl

SET @currentpage = 0 PODCZAS @currentpage < @numberofpages Rozpoczęcie Wybór a. * Z (SELECT row_number (NAD) (kolejność PRZEZ RZĄD person_ID) jako * Z sz_hold_visitsData) A, gdzie row> = @currentpage * @numberofitemsperpage +1 i rząd < = (@ currentPage + 1) * @numberofitemsperpage

IF @@ ROWCOUNT = 0 DOCIERANIA SET @currentpage = @currentpage +1 END

W tym wyciągu "sz_hold_visitsData" jest tabelą w mojej bazie danych, podczas gdy "person_ID" jest kolumną w niej zawartą. Można również dodatkowo zmodyfikować skrypt do wyjścia do pliku:

DECLARE @numberofitemsperpage INT DECLARE @numberofpages INT DECLARE @currentpage int

DECLARE @countRecords unosić @countRecords SET = (select count (*) Od sz_hold_visitsData) - program Excel może przechowywać około JEDNO MILIONÓW rekordów jednocześnie. jeśli @countRecords> = 1000000 SET @numberofitemsperpage = 500000 else if @countRecords < 1000000 I @countRecords> = 500000 SET @numberofitemsperpage = 250000 else if @countRecords < 500000 I @countRecords> = 100000 = 50000 SET @numberofitemsperpage ELSE SET @numberofitemsperpage = 10000

DECLARE @numberofpages_deci pływak SET @numberofpages_deci = @countRecords/@numberofitemsperpage

SET @numberofpages = pułap (@numberofpages_deci) Wybór @countRecords AS countRecords, @numberofitemsperpage CO numberofitemsperpage, @numberofpages_deci CO numberofpages_deci, @numberofpages CO numberofpagesFnl

DECLARE @sevrName nvarchar (50) Zestaw @sevrName =”. \ Sql14' stwierdzenie @outputFile nvarchar (500)

SET @currentpage = 0 PODCZAS @currentpage < @numberofpages BEGIN --wybierz a. * FROM (SELECT ROW_NUMBER() OVER (ORDER BY person_ID), jak wiersz, * FROM sz_hold_visitsData) WHERE ROW> = @currentpage * @numberofitemsperpage +1 i wierszy < = (@ currentpage + 1) * @numberofitemsperpage SET @outputFile = 'C: \ PSM \ outVisits_' + convert (nvarchar (50), @currentpage) + ".csv --Wybierz @outputFile --test

DECLARE @cmd_ VARCHAR (500) = 'Sqlcmd S' + @sevrName + '-P Q „wybierz. * Z (SELECT ROW_NUMBER(), NAD (ORDER BY person_ID) AS WIERSZ, * OD sz_hold_visitsData) a WHERE ROW> = '+ CONVERT (nvarchar (500), @ currentpage * @liczbaofitemsperpage +1) +' AND Rząd < = '+ CONVERT (nvarchar (500) , ((@ currentpage + 1) * @numberofitemsperpage)) + '"-s", "-o' + @ outputFile + '' - " C: \ PSM \ outVisits.csv "'EXEC xp_cmdshell @cmd_

IF @@ ROWCOUNT = 0 BREAK SET @currentpage = @currentpage +1 END

Nadzieja pomaga.

+0

Proszę zaszyfruj swój kod w określony sposób - zostaw pustą linię i wcięcie każdej linii kodu 4 spacji. – STLDeveloper

0

Oto inne rozwiązanie:

Trzeba by użyć tabeli temp trzymać pierwsze 50%, jak poniżej:

select top 50 percent * 
into #YourTempTable 
from TheTable 

-- The below would give the first half 
select * from #YourTempTable 

-- The below woud give rest of the half 
select * from TheTable where TheID not in (select TheID from #YourTempTable) 
Powiązane problemy