基于列

时间:2017-02-24 11:44:47

标签: sql oracle

我想基于参数复制一行(默认情况下参数为999)列和ID。例如,在下面的示例中,我们有一个阈值999,如果一个ID的行包含ParamComp = 999,另一行包含ParamComp <>999,则行ParamComp <>999我们必须使用ParamComp = 999的ColVal创建一条新记录。

如果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

2 个答案:

答案 0 :(得分:1)

戈登答案的替代方案(可能会或可能不会更快)是在两排虚拟&#34;表&#34;上进行部分交叉连接,如下所示:

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的答案,以了解哪种方式对您的数据最有效。

ETA:这是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是什么,并使用条件最大分析函数返回所有行的colval。然后,我将其添加到第二个连接条件部分,只返回具有999 colval的行(如果它们没有值,那么我们假设999行不存在)。这确实假设colval将始终存在于999行。

答案 1 :(得分:0)

如果我假设999是paramcomp的最大值,那么分析函数和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;

对于简单的规则变体,可以轻松修改。