Есть ли способ разбить результаты запроса на две равные половины?

Мне нужно решение для запроса на выборку в Sql Server 2005.

Я хотел бы получить запрос, возвращающий два ResultSet, каждый из которых содержит ровно половину всех записей, соответствующих определенным критериям. Я попытался использовать TOP 50 PERCENT в сочетании с Order By, но если число записей в таблице нечетное, одна запись будет отображаться в обоих наборах результатов. Я не хочу дублировать записи на наборах записей. Пример:

У меня есть простая таблица с полями TheID (PK) и TheValue (varchar(10)) и 5 ​​записей. Пропустите предложение where на данный момент.

SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID asc

результаты в выбранном идентификаторе 1,2,3

SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID desc

Результаты в выбранном идентификаторе 3,4,5

3 является дуплом. Конечно, в реальной жизни запросы довольно сложны с кучей предложений и подзапросов.

6 ответов

Решение

SQL Server 2005 и аналогичные:

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

ntile(n) распределяет выходные данные по n сегментам, каждый из которых имеет одинаковый размер (округлять или отдавать, когда число строк не делится на n). Так что это производит вывод:

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

Если вам нужна только верхняя или нижняя половина, вам нужно поместить это в подзапрос, например:

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

вернет верхнюю половину, а так же использует x.tile_nr = 2 для нижней половины

Вы можете использовать эти два запроса:

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

Если это SQL Server 2000, я был бы склонен найти ПК среднего значения следующим образом:

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 я был бы склонен сделать то же самое, но вы можете использовать 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 )

Попробуй это:

DECLARE @CountOf int,@Top int,@Bottom int
SELECT @CountOf=COUNT(*) FROM YourTable
SET @Top=@CountOf/2
SET @Bottom=@CountOf-@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

Вот еще одно решение:

Вам нужно будет использовать временную таблицу для хранения первых 50%, как показано ниже:

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)

Этот запрос я нашел полезным (после изменений, конечно):

Объявить @numberofitemsperpage INT объявить @numberofpages INT объявить @currentpage int

DECLARE @countRecords float SET @countRecords = (Выберите COUNT(*) из sz_hold_visitsData) - Excel может одновременно содержать приблизительно ОДИН МИЛЛИОН записей. if @countRecords >= 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords < 1000000 AND @countRecords >= 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords < 500000 AND @countRecords >= 100000 SET @numberofitemsperpage = 50000 ELSE 10000

ОБЪЯВИТЬ @numberofpages_deci float SET @numberofpages_deci = @countRecords / @numberofitemsperpage

SET @numberofpages = CEILING (@numberofpages_deci) Выберите @countRecords AS countRecords, @numberofitemsperpage AS numberofitemsperpage, @numberofpages_deci AS numberofpages_deci, @numberofpages AS numberofpagesFnl

SET @currentpage = 0 WHILE @currentpage <@numberofpages НАЧАТЬ ВЫБРАТЬ a. * FROM (ВЫБРАТЬ row_number () OVER (ORDER BY person_ID) AS ROW, * FROM sz_hold_visitsData) WHERE ROW> = @currentpage * @numberofitemsperpage +1 AND Row = (@ currentpage + 1) * @numberofitemsperpage

IF @@ ROWCOUNT = 0 BREAK SET @currentpage = @currentpage +1 КОНЕЦ

В этом фрагменте "sz_hold_visitsData" - это таблица в моей базе данных, а "person_ID" - это столбец в ней. Вы также можете дополнительно изменить скрипт для вывода в файл:

Объявить @numberofitemsperpage INT объявить @numberofpages INT объявить @currentpage int

DECLARE @countRecords float SET @countRecords = (Выберите COUNT(*) из sz_hold_visitsData) - Excel может одновременно содержать приблизительно ОДИН МИЛЛИОН записей. if @countRecords >= 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords < 1000000 AND @countRecords >= 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords < 500000 AND @countRecords >= 100000 SET @numberofitemsperpage = 50000 ELSE 10000

ОБЪЯВИТЬ @numberofpages_deci float SET @numberofpages_deci = @countRecords / @numberofitemsperpage

SET @numberofpages = CEILING (@numberofpages_deci) Выберите @countRecords AS countRecords, @numberofitemsperpage AS numberofitemsperpage, @numberofpages_deci AS numberofpages_deci, @numberofpages AS numberofpagesFnl

ОБЪЯВИТЬ @sevrName nvarchar(50) SET @sevrName = '.\ Sql14' ОБЪЯВИТЬ @outputFile nvarchar (500)

SET @currentpage = 0 WHILE @currentpage <@numberofpages BEGIN - ВЫБРАТЬ a. * FROM (ВЫБЕРИТЕ row_number () OVER (ORDER BY person_ID) AS ROW, * FROM sz_hold_visitsData) a WHERE ROW> = @currentpage * @numberofitemsperpage +1 AND Строка <= (@currentpage+1) * @numberofitemsperpage SET @outputFile = 'C:\PSM\outVisits_' +convert(nvarchar(50), @currentpage) + '.csv' - Выбрать @outputFile --TEST

DECLARE @cmd_ varchar (500) = 'sqlcmd -S' + @sevrName + '-E -Q "SELECT a. * FROM (SELECT row_number () OVER (ORDER BY person_ID) AS ROW, * FROM sz_hold_visitsData) ГДЕ ROW >= '+ CONVERT(nvarchar(500),@currentpage * @numberofitemsperpage +1) +' AND Row <= ' + 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 КОНЕЦ

Надежда помогает.

Другие вопросы по тегам