2010-05-05 38 views
12

我需要在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。在現實生活中,當然查詢對於大量的where子句和子查詢來說相當複雜。

+0

我想這是SQL Server的? – 2010-05-05 19:03:05

+1

誰在使用這兩個查詢?如果兩個消費者都意識到彼此(可能是他們的結果),爲什麼不提取整個列表並將其分爲消費者一方,這樣就沒有重複? – 2010-05-05 19:03:48

+0

是的。對不起,我忘了提及它。 – Mats 2010-05-05 19:03:56

回答

34

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

+1,在我的系統上測試過。 @Thomas,沒有'分區',只是'排序' – 2010-05-05 19:23:04

+2

@KM - 是的,也在我的系統上測試過。這對我來說是最簡單的解決方案,假設SQL2k5 +。 – Thomas 2010-05-05 19:24:28

+0

+1是最常被忽視的排名功能之一,實際上!好的答案 – 2010-05-05 19:24:50

6

你可以使用這兩個查詢:

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 
+0

我的想法確切。 – corsiKa 2010-05-05 19:05:54

+1

絕對是一個可行的答案。但是這不會影響兩半的分佈嗎?在OP中,他獲得了「上半部分」和「下半部分」,而不是「兩個不合格的一半」。 – 2010-05-05 19:08:07

+0

@Mark Canlas:你是對的。我讀到的問題是,只要行數是正確的,每個記錄的哪一半都沒有關係。但是你有一點可以解釋這個問題。 – 2010-05-05 19:12:04

1

試試這個:

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 
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) 
0

這是the query我發現有用(的道的修改後):

DECLARE @numberofitemsperpage INT DECLARE @numberofpages INT DECLARE @currentpage詮釋

DECLARE @countRecords浮動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浮球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 BEGIN SELECT 一個。* FROM(SELECT ROW_NUMBER)OVER(ORDER(BY PERSON_ID)AS ROW,* FROM sz_hold_visitsData)一個WHERE ROW> = @currentpage * @numberofitemsperpage 1和行< =(@當前第+ 1)* @numberofitemsperpage

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

在此摘錄中,「sz_hold_visitsData」是我的數據庫中的一個表,而「person_ID」是其中的一列。 您還可以進一步修改腳本以輸出到文件:

DECLARE @numberofitemsperpage INT DECLARE @numberofpages INT DECLARE @currentpage詮釋

DECLARE @countRecords浮SET @countRecords =(SELECT COUNT(*)從 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浮球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 =」 \ sql14' DECLARE @outputfile爲nvarchar(500)

SET @currentpage = 0 WHILE @currentpage < @numberofpages BEGIN - 選擇一個* FROM(SELECT row_number()OVER(ORDER BY person_ID)AS ROW,* FROM sz_hold_visitsData)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)一個WHERE ROW> = '+ CONVERT(nvarchar的(500),@當前頁* @numberofitemsperpage 1)+' AND 行< ='+ 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

希望有所幫助。

+0

請按照規定的方式標記您的代碼 - 留出一個空行並用4個空格縮進每行代碼。 – STLDeveloper 2017-07-04 15:23:42

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) 
相關問題