19

我需要在 Sql Server 2005 中选择查询的解决方案。

我想要一个返回两个结果集的查询,每个结果集恰好包含符合特定条件的所有记录的一半。我尝试将 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 子句和子查询。

4

6 回答 6

48

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用于下半部分

于 2010-05-05T19:13:37.443 回答
8

您可以使用这两个查询:

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
于 2010-05-05T19:04:56.810 回答
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 )
于 2010-05-05T19:14:11.767 回答
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
于 2010-05-05T19:13:51.653 回答
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)
于 2017-07-31T11:09:07.090 回答
-2

这是我发现有用的查询(当然修改后):

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

DECLARE @countRecords float SET @countRecords = (Select COUNT(*) From sz_hold_visitsData) -- Excel 一次可以保存大约一百万条记录。如果@countRecords> = 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords <1000000及@countRecords> = 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords <500000 AND @countRecords> = 100000 SET @numberofitemsperpage = 50000 ELSE SET @numberofitemsperpage = 10000

DECLARE @numberofpages_deci float SET @numberofpages_deci = @countRecords / @numberofitemsperpage

SET @numberofpages = CEILING(@numberofpages_deci) Select @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 AND Row < = (@currentpage+1) * @numberofitemsperpage

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

在这个摘录中,“sz_hold_visitsData”是我数据库中的一个表,而“person_ID”是其中的一个列。您还可以进一步修改脚本以输出到文件:

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

DECLARE @countRecords float SET @countRecords = (Select COUNT(*) From sz_hold_visitsData) -- Excel 一次可以保存大约一百万条记录。如果@countRecords> = 1000000 SET @numberofitemsperpage = 500000 ELSE IF @countRecords <1000000及@countRecords> = 500000 SET @numberofitemsperpage = 250000 ELSE IF @countRecords <500000 AND @countRecords> = 100000 SET @numberofitemsperpage = 50000 ELSE SET @numberofitemsperpage = 10000

DECLARE @numberofpages_deci float SET @numberofpages_deci = @countRecords / @numberofitemsperpage

SET @numberofpages = CEILING(@numberofpages_deci) Select @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 BEGIN --SELECT a.* FROM (SELECT 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' --Select @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) A WHERE 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 END

希望有所帮助。

于 2016-11-09T10:19:04.783 回答