有没有办法将选择查询的结果分成两个相等的一半?

时间:2010-05-05 19:01:33

标签: sql sql-server result-partitioning

我需要在Sql Server 2005中为select查询提供解决方案。

我想让一个查询返回两个ResultSet,每个ResultSet都保留了与某个条件匹配的所有记录的一半。我尝试将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是一个副本。在现实生活中,查询相当复杂,有大量where子句和子查询。

6 个答案:

答案 0 :(得分:40)

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作为下半部分

答案 1 :(得分:7)

您可以使用以下两个查询:

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

答案 2 :(得分:2)

如果这是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 )

答案 3 :(得分:1)

试试这个:

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

答案 4 :(得分:0)

这是另一种解决方案:

您需要使用临时表来保存前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)

答案 5 :(得分:-1)

这是the query我发现有用(经过修改后):

  
    

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

  
     

DECLARE @countRecords float SET @countRecords =(选择COUNT(*)From   sz_hold_visitsData)    - Excel一次可以容纳大约一百万条记录。 if @countRecords&gt; = 1000000 SET @numberofitemsperpage = 500000 ELSE IF   @countRecords&lt; 1000000 AND @countRecords&gt; = 500000 SET   @numberofitemsperpage = 250000 ELSE IF @countRecords&lt; 500000 AND   @countRecords&gt; = 100000 SET @numberofitemsperpage = 50000 ELSE SET   @numberofitemsperpage = 10000

     

DECLARE @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&lt; @numberofpages BEGIN SELECT   a。* FROM(SELECT row_number()OVER(ORDER BY person_ID)AS ROW,*   FROM sz_hold_visitsData)一个WHERE ROW&gt; = @currentpage *   @numberofitemsperpage +1 AND Row&lt; =(@ currentpage + 1)*   @numberofitemsperpage

     

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

在此摘录中,&#34; sz_hold_visitsData&#34;是我数据库中的一个表,而#34; person_ID&#34;是一个专栏。 您还可以进一步修改脚本以输出到文件:

  

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

     

DECLARE @countRecords float SET @countRecords =(选择COUNT(*)From   sz_hold_visitsData)    - Excel一次可以容纳大约一百万条记录。 if @countRecords&gt; = 1000000 SET @numberofitemsperpage = 500000 ELSE IF   @countRecords&lt; 1000000 AND @countRecords&gt; = 500000 SET   @numberofitemsperpage = 250000 ELSE IF @countRecords&lt; 500000 AND   @countRecords&gt; = 100000 SET @numberofitemsperpage = 50000 ELSE SET   @numberofitemsperpage = 10000

     

DECLARE @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

     

DECLARE @sevrName nvarchar(50)SET @sevrName =&#39;。\ sql14&#39;宣布   @outputFile nvarchar(500)

     

SET @currentpage = 0 WHILE @currentpage&lt; @numberofpages BEGIN   --SELECT a。* FROM(SELECT row_number()OVER(ORDER BY person_ID)AS ROW,* FROM sz_hold_visitsData)WHERE ROW&gt; = @currentpage *   @numberofitemsperpage +1 AND Row&lt; =(@ currentpage + 1)*   @numberofitemsperpage SET @outputFile =&#39; C:\ PSM \ outVisits _&#39;   + convert(nvarchar(50),@ currentpage)+&#39; .csv&#39; - 选择@outputFile --TEST

     

DECLARE @cmd_ varchar(500)=&#39; sqlcmd -S&#39; + @sevrName +&#39; -E -Q   &#34; SELECT a。* FROM(SELECT row_number()OVER(ORDER BY person_ID)AS   ROW,* from sz_hold_visitsData)a WHERE ROW&gt; =&#39; +   CONVERT(nvarchar(500),@ currentpage * @numberofitemsperpage +1)+&#39;和   行&lt; =&#39; + CONVERT(nvarchar(500),((@ currentpage + 1)*   @numberofitemsperpage))+&#39;&#34; -s&#34;,&#34; -o&#39; + @ outputFile +&#39; &#39; -   &#34; C:\ PSM \ outVisits.csv&#34; &#39; EXEC xp_cmdshell @cmd _

     

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

希望有所帮助。