【问题标题】:Select distinct column values in a single row in oracle在 oracle 的单行中选择不同的列值
【发布时间】:2016-04-20 13:39:55
【问题描述】:

我有以下要求。

Column1 Column2 Column3 Column4 Column5 Column6
Abc     02      03      02      05      07

当我选择这一行时,我应该得到如下值

Abc 02 03 05 07 <null> 

应消除重复项,但列应保持原样。

感谢您的帮助!!

谢谢, 赛

【问题讨论】:

  • 您的查询在哪里?
  • 其实我在找写sql的方法。我不知道。
  • 不使用查询如何获得当前结果?
  • @ErayBalkanli - 这不是“当前结果” - 这是期望的结果。不是来自查询,而是来自需求。
  • @Sr.TechnicalSpecialist - 您是否希望自己更新列中的值?不清楚 - 如果第 4 列中的值是重复的,您想将剩余列中的值“向左一列”移动并在 LAST 列中插入 NULL?

标签: sql oracle distinct


【解决方案1】:

您将数据存储在应该在行中的列中。数据结构应该是这样的:

column1 number value
  ABC     1      02
  ABC     2      03
  ABC     3      02
. . .

那么您的查询将很容易。您可以通过 unpivoting 获得所需的值:

select distinct column1, value
from (select column1, column2 as valuefrom t union all
      select column1, column3 from t union all
      select column1, column4 . . .
     ) x;

您可以使用以下方法将它们作为列表获取:

select column1, listagg(value, ', ') within group (order by value)
from (select column1, column2 as valuefrom t union
      select column1, column3 from t union
      select column1, column4 . . .
     ) x
group by column1;

【讨论】:

    【解决方案2】:

    好的。我将所有内容(包括基表)放入一个查询中,以便其他人可以使用它 - 测试它,找到更好的方法等。在现实生活中,我称之为“t”(第二个 cte 或公用表表达式)是起始表和我所说的“c”(第一个 cte)应该作为表或视图存在于某处,或者它可以像我一样动态构建。要求:必须事先知道表 t 中所有列的数量、名称和顺序,它们不能是动态的(除非想使用动态 SQL 重写)。

    还要注意,如果我可以假设所有列名都是大写的,那会容易得多。我不想假设它,所以使用大写(...)的代码看起来更复杂 - 因为 Oracle 会在取消透视时将列名更改为大写(否则我将不得不做更多的工作...... )

    我以新的“表格”格式返回结果(如果 t 有多于一行,则可以使用该格式 - 输出是相同数量的行)。我没有写成“update t...”格式;如果需要,这应该相对容易做到。我不知道“我必须改变值”是否意味着到位(即更新),或者它是否意味着输出与输入相比。

    输入表(仅一行)如下所示:

    COLUMN1    COLUMN2    COLUMN3    COLUMN4    COLUMN5    COLUMN6
    ---------- ---------- ---------- ---------- ---------- ----------
    Abc        02         03         02         05         07
    

    输出:

    COLUMN1    COLUMN2    COLUMN3    COLUMN4    COLUMN5    COLUMN6
    ---------- ---------- ---------- ---------- ---------- ----------
    Abc        02         03         05         07
    

    还有代码:

    with c (col_rank, col_name) as (select 1, upper('Column1') from dual union all
                                    select 2, upper('Column2') from dual union all
                                    select 3, upper('Column3') from dual union all
                                    select 4, upper('Column4') from dual union all
                                    select 5, upper('Column5') from dual union all
                                    select 6, upper('Column6') from dual          ),
         t (Column1, Column2, Column3, Column4, Column5, Column6) as 
                             (select 'Abc', '02', '03', '02', '05', '07' from dual),
         x as (select * from t unpivot (col_value for col_name in (Column1, 
                                     Column2, Column3, Column4, Column5, Column6))),
         y as (select col_rank, col_name, col_value from x natural join c),
         z as (select col_rank, col_value, 
                      case when col_value in (select y1.col_value from y y1 
                                              where y1.col_rank < y2.col_rank) then 0 
                                                              else 1 end flag from y y2),
         u as (select col_value, 
                      count(flag) over (order by col_rank rows between unbounded preceding 
                                           and current row) val_rank from z where flag = 1)
    select * from (select col_name, col_value from c left outer join u 
                                                      on c.col_rank = u.val_rank )
    pivot (min(col_value) for col_name in (upper('Column1') Column1, upper('Column2') Column2,
                                           upper('Column3') Column3, upper('Column4') Column4, 
                                           upper('Column5') Column5, upper('Column6') Column6))
    

    【讨论】:

      【解决方案3】:

      Oracle 设置

      CREATE TABLE table_name ( col1, col2, col3, col4, col5, col6 ) AS
      SELECT 'abc', '02', '03', '02', '05', '07' FROM DUAL UNION ALL
      SELECT 'abc', '05', '04', '02', '03', '01' FROM DUAL UNION ALL
      SELECT 'abc', '01', '01', '01', '01', '01' FROM DUAL;
      
      CREATE TYPE stringlist AS TABLE OF VARCHAR2(100);
      /
      

      查询 - 不使用用户定义的函数

      SELECT MAX( col1 ) AS col1,
             MAX( CASE rn WHEN 1 THEN value END ) AS col2,
             MAX( CASE rn WHEN 2 THEN value END ) AS col3,
             MAX( CASE rn WHEN 3 THEN value END ) AS col4,
             MAX( CASE rn WHEN 4 THEN value END ) AS col5,
             MAX( CASE rn WHEN 5 THEN value END ) AS col6
      FROM   (
        SELECT col1,
               rid,
               ROW_NUMBER() OVER (PARTITION BY t.rid ORDER BY v.column_value) AS rn,
               v.COLUMN_VALUE AS value
        FROM   ( SELECT col1,
                        ROWID AS rid, 
                        SET( stringlist( col2, col3, col4, col5, col6 ) ) AS cols
                 FROM   table_name ) t,
                 TABLE( t.cols ) v
      )
      GROUP BY rid;
      

      查询 - 使用 UDF

      CREATE FUNCTION nth_item(
        collection STRINGLIST,
        n          INT
      ) RETURN VARCHAR2 DETERMINISTIC
      AS
      BEGIN
        IF collection IS NULL OR n < 1 OR n > collection.COUNT THEN
          RETURN NULL;
        END IF;
        RETURN collection(n);
      END;
      /
      

      然后:

      SELECT col1,
             nth_item( cols, 1 ) AS col2,
             nth_item( cols, 2 ) AS col3,
             nth_item( cols, 4 ) AS col4,
             nth_item( cols, 4 ) AS col5,
             nth_item( cols, 5 ) AS col6
      FROM   (
        SELECT  col1,
                SET( stringlist( col2, col3, col4, col5, col6 ) ) AS cols
        FROM    table_name
      );
      

      输出(对于两个查询)

      COL1 COL2 COL3 COL4 COL5 COL6
      ---- ---- ---- ---- ---- ----
      abc  02   03   05   07
      abc  01   02   03   04   05
      abc  01
      

      【讨论】:

        【解决方案4】:
        with
          tbl as (
            select  'Abc' Column1, '02' Column2, '03' Column3,  '02' Column4, '03' Column5, '07' Column6, 1 rrowid from dual union all 
            select  'Dfg' Column1, '10' Column2, '10' Column3,  '10' Column4, '10' Column5, '10' Column6, 2 rrowid from dual
          ),
          unpv as (
            select *
            from tbl
            unpivot (val FOR col IN (column1 AS 1, column2 AS 2, column3 AS 3, column4 AS 4, column5 as 5, column6 as 6))
          ),
          clc as (
            select rrowid, val, row_number() over (partition by rrowid order by col) col
            from (
              select rrowid, col,
                decode(row_number() over (partition by rrowid, val order by col), 1, val, null) val
              from unpv
            )
            where not val is null)
        select * from clc
        pivot  (max(val) AS val FOR (col) IN (1 AS a, 2 AS b, 3 AS c, 4 as d, 5 as e, 6 as f));
        

        结果是:

            RROWID A_VAL B_VAL C_VAL D_VAL E_VAL F_VAL
        ---------- ----- ----- ----- ----- ----- -----
                 1 Abc   02    03    07          
                 2 Dfg   10      
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多