Oracle转换表从行到列

时间:2015-12-10 17:14:07

标签: sql oracle

我有一个问题:

select vrec, valnum, valte from val_tb where  
recd in (select recd from rectb where setd = 17)
AND (vid = 3 OR vid = 26 OR vid = 28);

对于上面的结果,我得到:

vrec      valnum       valte
98945823  NULL         Total
98945823  NULL         06001
98945823  16.57        NULL 
98945824  NULL         Total
98945824  NULL         06005
98945824  0.36         NULL 

我想将其转换为:

98945823    06001   Total   16.57
98945824    06005   Total   0.36

即。结合vrec的结果。

是否可以使用Oracle SQL执行此操作?

5 个答案:

答案 0 :(得分:6)

区分valte值的一种方法是检查字符串是否只包含数字(解决方案不好但应该有效):

WITH cte( vrec,valnum, valte) AS
(
  SELECT 98945823 AS vrec,   NULL AS valnum,'Total' AS valte FROM dual
  UNION ALL SELECT 98945823, NULL,  '06001'      FROM dual
  UNION ALL SELECT 98945823, 16.57,  NULL        FROM dual
  UNION ALL SELECT 98945824, NULL,  'Total'      FROM dual
  UNION ALL SELECT 98945824, NULL,  '06005'      FROM dual
  UNION ALL SELECT 98945824, 0.36,  NULL         FROM dual
)
SELECT 
    vrec
   ,MAX(CASE WHEN REGEXP_LIKE(valte, '^[[:digit:]]*$') THEN valte ELSE NULL END)
   ,MAX(CASE WHEN NOT REGEXP_LIKE(valte, '^[[:digit:]]*$') THEN valte ELSE NULL END)
   ,MAX(valnum)
FROM cte
GROUP BY vrec;

SqlFiddleDemo

输出:

╔═══════════╦═══════════════╦═══════════════╦═════════════╗
║   VREC    ║ MAX(CASE...)  ║ MAX(CASE...)  ║ MAX(VALNUM) ║
╠═══════════╬═══════════════╬═══════════════╬═════════════╣
║ 98945823  ║        06001  ║ Total         ║ 16.57       ║
║ 98945824  ║        06005  ║ Total         ║ 0.36        ║
╚═══════════╩═══════════════╩═══════════════╩═════════════╝

对于您的案例交换cte硬编码值:

select vrec, valnum, valte from val_tb where  
recd in (select recd from rectb where setd = 17)
AND (vid = 3 OR vid = 26 OR vid = 28);

您的数据结构非常差,因此此解决方案只是解决方法。你应该真的改变底层结构。

答案 1 :(得分:0)

你是对的,这是最简单的解决方案......但你错过了一个小组:

 select vrec, MAX(valnum),'Total' ,MAX(valte) 
   from val_tb 
  where recd in (select recd from rectb where setd = 17)
    AND (vid = 3 OR vid = 26 OR vid = 28)
    AND valte <>'Total' --<< Lines with constant 'Total' are of no use...
GROUP BY vrec;

答案 2 :(得分:0)

还有一个选择。从@ lad2025获取测试数据

WITH cte( vrec,valnum, valte) AS
(
  SELECT 98945823 AS vrec,   NULL AS valnum,'Total' AS valte FROM dual
  UNION ALL SELECT 98945823, NULL,  '06001'      FROM dual
  UNION ALL SELECT 98945823, 16.57,  NULL        FROM dual
  UNION ALL SELECT 98945824, NULL,  'Total'      FROM dual
  UNION ALL SELECT 98945824, NULL,  '06005'      FROM dual
  union all select 98945824, 0.36,  null         from dual
)
select vrec, max(id), max(tot), sum(sum)
  from
(
  select vrec, valte      id ,null tot ,null sum from cte where not valte       = 'Total' 
  union all
  select vrec, null          ,valte ,null from cte where     valte       = 'Total' 
  union all
  select vrec, null          ,null  ,to_char(valnum) from cte where     valnum is not null
)
group by vrec
;

答案 3 :(得分:0)

select vrec, 
       max(valte),
       'Total' || max(valnum)
from val_tb 
where recd in (select recd from rectb where setd = 17)
and (vid = 3 OR vid = 26 OR vid = 28)
and NVL(valte, '#') != 'Total'
group by vrec;

这背后的想法是:

  1. 我们不关心{Total}的valte记录。我们可以将“总计”添加到我们要求的valte之前。因此,我们会排除valte为“总数”的记录,并保留NULL值,因此我们会保留valnum的记录。
  2. valnum只有一个valte和一个NOT NULL vrec,因此MAXGROUP BY vrec 1}}。

答案 4 :(得分:0)

您可以使用PIVOT查询获取它:

WITH pivot_data AS (
            select vrec, valnum, valte from val_tb where  
recd in (select recd from rectb where setd = 17)
AND (vid = 3 OR vid = 26 OR vid = 28)
            )
    SELECT *
    FROM   pivot_data
    PIVOT (
              max(valte )        --<-- pivot_clause
          FOR table --<-- pivot_for_clause

         IN  (FORM Hidden FIELD Name)    --<-- pivot_in_clause         
);

对于动态IN子句,创建一个表单隐藏字段并将以下查询结果传递给此字段。然后将该字段引用到上述查询的IN子句中。

SELECT LISTAGG(dbms_assert.enquote_literal(valnum ), ', ') WITHIN GROUP (ORDER BY valnum ) valnum 
FROM (select valnum from val_tb where  
recd in (select recd from rectb where setd = 17)
AND (vid = 3 OR vid = 26 OR vid = 28) and valnum is not null)