2015-09-08 52 views
0

說我們有一個表T
查詢中的SQL問題。需要一個更好的/備用查詢

+------+ 
| NUMM | 
+------+ 
| 1 | 
| 5 | 
| 3 | 
| 8 | 
+------+ 

我想從列numm最近的更大的數量在列numm1。 結果會是這樣

+-------------+ 
| NUMM | NUMM1| 
+-------------+ 
| 1 | 3 | 
| 3 | 5 | 
| 5 | 8 | 
+-------------+  

我寫這樣的查詢和它的作品。但我想知道是否有更好的解決方法。

select numm, numm + min(dif) as numm1 
    from (select distinct a.numm numm, b.numm numm1, b.numm - a.numm dif 
     from (select * 
       from T 
      where numm != (select max(numm) from T)) a 
     join T b 
     on 1 = 1) 
where dif > 0 
group by numm 
+0

如果你有5行? –

+1

這並不是100%清楚你期望的結果 - 你想要每個數字的繼任者嗎? –

+0

@a_horse_with_no_name與我的查詢可以處理任意數量的行。 – arminrock

回答

3

如果你想獲得的直接繼任者,您可以使用lead()窗口函數:

select * from (
    select 
    numm, 
    lead(numm) over (order by numm) as numm1 
    from t 
) 
where numm1 is not null 
order by numm; 
+0

比較我的解決方案和另一個答案在這裏,這似乎是最快的方式 謝謝 – arminrock

+0

這似乎是一個正確的查詢,但是,如果您的記錄重複比上述查詢將失敗。要處理重複記錄,請參閱下面的解決方案。我希望這會有所幫助。 –

1

如果是Oracle,您可以使用ROW_NUMBER()函數來進行排名,然後內有加盟[left_table] .rank = [right_table] .rank - 1:

SELECT a.numm, 
     b.numm 
FROM 
    (SELECT numm, row_number() over(order by numm) AS rank FROM pn_test) a 
INNER JOIN 
    (SELECT numm, row_number() over(order by numm) AS rank FROM pn_test) b 
ON a.rank = b.rank - 1; 
1

嘗試下面的查詢,如果您已在表中重複的記錄:

WITH CTE_ABC 
AS (
    SELECT DISTINCT NUMM 
    FROM [Table] 
    ) 
    ,CTE_XYZ 
AS (
    SELECT * 
    FROM (
     SELECT NUMM 
      ,lead(NUMM) OVER (
       ORDER BY NUMM 
       ) AS numm1 
     FROM CTE_ABC 
     ) A 
    WHERE numm1 IS NOT NULL 
    ) 
SELECT A.NUMM 
    ,B.numm1 
FROM [Table] A 
LEFT JOIN CTE_XYZ B 
    ON A.columnId = B.columnId 
WHERE B.numm1 IS NOT NULL 
1

弗蘭克的答案很可能是最好的,當沒有重複的數字,但如果你能重複結束了這裏的一個可能的解決方案:

with t1 as (
select numm 
     , dense_rank() over (order by numm) rnk 
    from t 
) 
select t1.numm 
    , t2.numm numm1 
    from t1 
    join (select distinct numm, rnk-1 rnk from t1) t2 
    on t1.rnk = t2.rnk; 

在這個解決方案中DENSE_RANK解析函數中首先使用T1給每個不同的NUMM一個序號(RNK)。在第二階段,T1在RNK上連接到來自t1的不同組的numm和rnk-1值。

尋找更好的性能,這可能做的工作:

with t1 as (
select numm 
     , dense_rank() over (order by numm) rnk 
     , row_number() over (partition by numm order by rownum) ord 
    from t 
) 
select t1.numm 
    , t2.numm numm1 
    from t1 
    join t1 t2 
    on t1.rnk = t2.rnk-1 
    and t2.ord = 1; 

這裏我添加了一個方法來抓住每個numm到subfactored查詢一個記錄,在T2消除了不同的操作。對於僅有5條記錄且沒有索引的有限數據集,其成本爲9,而對於先前的查詢,成本爲10。

+0

有點貴,但是,是的,這涵蓋了所有情況,並且查詢很容易理解。謝謝 – arminrock

+1

由於有限的數據集提供了我原來的查詢和我剛添加的查詢之間的成本差異,可以忽略不計。 – Sentinel