Есть ли способ разделить результаты запроса выбора на две равные половины?
Мне нужно решение для запроса select в Sql Server 2005.
Я хотел бы получить запрос, возвращающий два ResultSets, каждый из которых содержит ровно половину всех записей, соответствующих определенным критериям. Я попытался использовать TOP 50 PERCENT в сочетании с Order By, но если количество записей в таблице нечетное, одна запись будет отображаться в обоих наборах результатов. Я не хочу, чтобы какая-либо запись дублировалась по наборам записей. Пример:
У меня есть простая таблица с полями TheID (PK) и TheValue (varchar (10)) и 5 записей. Пропустите предложение where на данный момент.
SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID asc
приводит к выбранному id 1,2,3
SELECT TOP 50 PERCENT * FROM TheTable ORDER BY TheID desc
приводит к выбранному id 3,4,5
3 - это dup. В реальной жизни, конечно, запросы довольно сложны с тонной частью предложений и подзапросов.
Ответы
Ответ 1
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
для нижней половины
Ответ 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
Ответ 3
Если это SQL Server 2000, я был бы склонен найти PK среднего значения следующим образом:
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 )
Ответ 4
попробуйте следующее:
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
Ответ 5
Это запрос, который я нашел полезным (после изменений курса):
DECLARE @numberofitemsperpage INT DECLARE @numberofpages INT DECLARE @currentpage int
DECLARE @countRecords float SET @countRecords = (Выберите COUNT (*) From sz_hold_visitsData) - Excel может хранить одновременно записи за один миллион. если @countRecords >= 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords < 1000000 И @countRecords >= 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords < 500000 И @countRecords >= 100000 SET @numberofitemsperpage = 50000 ELSE SET @numberofitemsperpage = 10000
DECLARE @numberofpages_deci float SET @numberofpages_deci = @countRecords/@numberofitemsperpage
SET @numberofpages = ПОТОЛОК (@numberofpages_deci) Выберите @countRecords AS countRecords, @numberofitemsperpage AS numberofitemsperpage, @numberofpages_deci AS numberofpages_deci, @numberofpages AS numberofpagesFnl
SET @currentpage = 0 WHILE @currentpage < @numberofpages BEGIN SELECT a. * FROM (SELECT row_number() OVER (ORDER BY person_ID) AS ROW, * FROM sz_hold_visitsData) WHERE ROW >= @currentpage * @numberofitemsperpage +1 И Row <= (@currentpage + 1) * @numberofitemsperpage
IF @@ROWCOUNT = 0 BREAK SET @currentpage = @currentpage +1 END
В этом выводе "sz_hold_visitsData" - это таблица в моей базе данных, в то время как "person_ID" - это столбец.
Вы также можете дополнительно модифицировать script для вывода в файл:
DECLARE @numberofitemsperpage INT DECLARE @numberofpages INT DECLARE @currentpage int
DECLARE @countRecords float SET @countRecords = (Выберите COUNT (*) From sz_hold_visitsData) - Excel может хранить одновременно записи за один миллион. если @countRecords >= 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords < 1000000 И @countRecords >= 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords < 500000 И @countRecords >= 100000 SET @numberofitemsperpage = 50000 ELSE SET @numberofitemsperpage = 10000
DECLARE @numberofpages_deci float SET @numberofpages_deci = @countRecords/@numberofitemsperpage
SET @numberofpages = ПОТОЛОК (@numberofpages_deci) Выберите @countRecords AS countRecords, @numberofitemsperpage AS numberofitemsperpage, @numberofpages_deci AS numberofpages_deci, @numberofpages AS numberofpagesFnl
DECLARE @sevrName nvarchar (50) SET @sevrName = '.\sql14' DECLARE @outputFile nvarchar (500)
SET @currentpage = 0 WHILE @currentpage < @numberofpages НАЧАТЬ --SELECT a. * FROM (SELECT row_number() OVER (ORDER BY person_ID) AS ROW, * FROM sz_hold_visitsData) WHERE ROW >= @currentpage * @numberofitemsperpage +1 И Row <= (@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) WHERE ROW >= '+ CONVERT (nvarchar (500), @текущая страница * @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 END
Надежда помогает.
Ответ 6
Вот еще одно решение:
Вам нужно будет использовать временную таблицу для хранения первых 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)