2017-02-24 42 views
1

我想基於參數(參數默認爲999)列和ID來複制一行。例如,在下面的示例中,我們有一個閾值999,如果一個ID有一行ParamComp = 999,而另一行有ParamComp <>999,那麼對於ParamComp <>999的行,我們必須創建一個ColVal爲ParamComp = 999的新記錄。基於列的重複行oracle

如果某個ID的行只有ParamComp = 999,請直接將其加載到目標(不需要重複邏輯)。

而且如果一個ID具有與僅ParamComp <> 999行,只要將其加載到目標直接(無需複製邏輯)

輸入數據

id ParamComp ColVal 
1 999   a 
1 80   b 
2 999   c 
3 85   d 

目標數據

id ParamComp ColVal 
1 999   a 
1 80   b 
1 80   a 
2 999   c 
3 85   d 
+0

我不認爲您的示例數據遵循您指定的規則。如果是這樣,那麼'id = 1'將有兩行999。請澄清這個問題。 –

+0

當你說你想「複製一列」你的意思是一排,對嗎?我沒有看到任何額外的列創建。然後:如果您基於現有的一行創建新行,但ParamComp值不同,那麼它甚至不是「重複」。在標題中:關係數據庫具有「行」而不是「記錄」。 – mathguy

+0

@GordonLinoff對於一個ID,999是要比較的值,根據999個其他行的ColVal被複制 - (如果一個ID的ParamComp爲'999'且非999值)。 –

回答

1

戈登的回答另一種(可能是也可能不是更快)是對一個兩行假「表」的部分交叉連接,就像這樣:

WITH your_table AS (SELECT 1 ID, 999 paramcomp, 'a' colval FROM dual UNION ALL 
        SELECT 1 ID, 80 paramcomp, 'b' colval FROM dual UNION ALL 
        SELECT 2 ID, 999 paramcomp, 'c' colval FROM dual UNION ALL 
        SELECT 3 ID, 85 paramcomp, 'd' colval FROM dual UNION ALL 
        SELECT 4 ID, 999 paramcomp, 'e' colval FROM dual UNION ALL 
        SELECT 4 ID, 75 paramcomp, 'f' colval FROM dual UNION ALL 
        SELECT 4 ID, 70 paramcomp, 'g' colval FROM dual) 
-- end of mimicking your table; see SQL below: 
SELECT yt.ID, 
     yt.paramcomp, 
     case WHEN dummy.id = 1 THEN yt.colval 
      WHEN dummy.id = 2 THEN yt.paramcomp_999_colval 
     END colval 
FROM (SELECT ID, 
       paramcomp, 
       colval, 
       MAX(CASE WHEN paramcomp = 999 THEN colval END) OVER (PARTITION BY ID) paramcomp_999_colval 
     FROM your_table) yt 
     INNER JOIN (SELECT 1 ID FROM dual UNION ALL 
        SELECT 2 ID FROM dual) dummy ON dummy.id = 1 -- ensures every yt row is returned 
                OR (dummy.id = 2 
                 AND paramcomp_999_colval IS NOT NULL 
                 AND yt.paramcomp != 999) -- returns an extra row if the 999 paramcomp row exists but the current row isn't 999 
ORDER BY yt.ID, yt.paramcomp DESC, yt.colval; 

     ID PARAMCOMP COLVAL 
---------- ---------- ------ 
     1  999 a 
     1   80 b 
     1   80 a 
     2  999 c 
     3   85 d 
     4  999 e 
     4   75 e 
     4   75 f 
     4   70 g 
     4   70 e 

這是假設有每個id只有一個999 paramcomp行(例如,存在(id,paramcomp)的唯一約束)。

你必須測試一下這個和Gordon的答案,看看哪個數據性能最高。


埃塔:這裏是戈登的回答的一個固定的版本供您使用比較:

select id, paramcomp, colval 
from your_table 
union all 
select id, paramcomp, paramcomp_999_colval colval 
from (select yt.*, MAX(CASE WHEN paramcomp = 999 THEN colval END) OVER (PARTITION BY ID) paramcomp_999_colval 
     from your_table yt 
    ) t 
where paramcomp_999_colval IS NOT NULL and paramcomp <> 999 
ORDER BY ID, paramcomp DESC, colval; 

ETA2:

如果您:使用虛表的詳細解釋想要複製表中的所有行,可以交叉連接到具有兩行的表/子查詢,如下所示:

SELECT * 
FROM your_table yt 
CROSS JOIN (SELECT 1 ID FROM dual UNION ALL 
      SELECT 2 ID FROM dual) dummy; 

     ID PARAMCOMP COLVAL   ID 
---------- ---------- ------ ---------- 
     1  999 a    1 
     1   80 b    1 
     2  999 c    1 
     3   85 d    1 
     4  999 e    1 
     4   75 f    1 
     4   70 g    1 
     1  999 a    2 
     1   80 b    2 
     2  999 c    2 
     3   85 d    2 
     4  999 e    2 
     4   75 f    2 
     4   70 g    2 

但是,您並不總是希望出現重複行,因此您需要執行一個有點選擇性的內部連接。我會在最初的答案中分解內連接,這樣你就可以看到它做得更好了。

首先,這裏的部分加入,以確保在your_table每一行返回:

SELECT * 
FROM your_table yt 
INNER JOIN (SELECT 1 ID FROM dual UNION ALL 
      SELECT 2 ID FROM dual) dummy ON dummy.id = 1; 

     ID PARAMCOMP COLVAL   ID 
---------- ---------- ------ ---------- 
     1  999 a    1 
     1   80 b    1 
     2  999 c    1 
     3   85 d    1 
     4  999 e    1 
     4   75 f    1 
     4   70 g    1 

其次,這裏的的加入,確保選擇性加入

SELECT * 
FROM your_table yt 
INNER JOIN (SELECT 1 ID FROM dual UNION ALL 
      SELECT 2 ID FROM dual) dummy ON dummy.id = 2 
              AND yt.paramcomp != 999; 

     ID PARAMCOMP COLVAL   ID 
---------- ---------- ------ ---------- 
     1   80 b    2 
     3   85 d    2 
     4   75 f    2 
     4   70 g    2 

你的一部分可以看到第二部分,我們仍然得到id = 3行,這是我們不想要的。因此,在上面的最終答案中,我發現了paramcomp = 999行的colval,並使用條件最大分析函數返回了所有行。然後,我將它添加到第二個連接條件部分,以僅返回具有999 colval的行(如果它們沒有值,則假定999行不存在)。這確實假設colval將始終存在於999行。

+0

Gordon的答案沒有給出所需的輸出,它是用999自己複製記錄並將非999記錄的colval複製到它。你的答案是工作d給了我想要的輸出。我們是否有任何解決方法來糾正戈登的答案,以便我可以比較表現。 –

+0

爲什麼我們在id 1和2中使用虛擬表格?你能幫忙嗎? –

+1

我已將我的答案更新爲包含Gordon答案的工作版本。 – Boneist

0

如果我假設999是0123的最大值,那麼解析函數和union all就可以解決這個問題。繼在文本中指定的規則,這將是:

select id, paramcomp, colval 
from t 
union all 
select id, 999 as paramcomp, colval 
from (select t.*, max(paramcomp) over (partition by id) as max_paramcomp 
     from t 
    ) t 
where max_paramcomp = 999 and paramcomp <> 999; 

這是很容易修改規則的簡單變種。

+0

在這張表中,我們只有'999'作爲閾值。我也不希望999行被複制, –