Есть ли способ разбить результаты запроса на две равные половины?
Мне нужно решение для запроса на выборку в 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 КОНЕЦ
Надежда помогает.