【问题标题】:Oracle transform table from row to columnOracle 将表从行转换为列
【发布时间】:2016-03-16 10:34:39
【问题描述】:

我有一个问题:

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 做到这一点?

【问题讨论】:

  • @dang..从昨天开始,您提出了一系列问题。你应该付出一些努力来解决它们。
  • 大多数情况下,低效的数据库设计会造成这种复杂性。
  • 同意@MohamedSaligh
  • 除非您没有显示其他一些列,否则无法区分 valnum 为 NULL 的两行。

标签: sql oracle


【解决方案1】:

区分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);

您的数据结构很差,所以这个解决方案只是解决方法。你真的应该改变底层结构。

【讨论】:

    【解决方案2】:

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

     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;
    

    【讨论】:

      【解决方案3】:

      您可以使用 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         
      );
      

      对于Dynamic 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)
      

      【讨论】:

        【解决方案4】:
        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. 我们不关心valte 为“总计”的记录。我们可以在我们需要的valte 前面加上“总计”。因此,我们排除了 valte 为 'total' 的记录,保留了 NULL 的值,因此我们保留了 valnum 的记录。
        2. 每个vrec 只有一个valnum 和一个valteNOT NULL,所以我们采用MAXGROUP BY vrec

        【讨论】:

          【解决方案5】:

          还有一个选择。从@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
          ;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多