在oracle中的单行中选择不同的列值

时间:2016-04-20 13:39:55

标签: sql oracle distinct

我有以下要求。

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

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

Abc 02 03 05 07 <null> 

应删除重复项,但列应保持不变。

感谢您的帮助!!

谢谢, 西

4 个答案:

答案 0 :(得分:0)

您将数据存储在应该在行中的列中。数据结构应该如下所示:

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

然后你的查询会很简单。您可以通过取消隐藏来获得所需的值:

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;

答案 1 :(得分:0)

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

另请注意,如果我可以假设所有列名都是大写的话会容易得多。我不想假设它,所以代码看起来更复杂的上层(...) - 因为Oracle会在未透刻时将列名更改为大写(否则我将不得不做更多的工作。 ..)

我将结果返回到一个新的&#34;表&#34; format(如果t有多行,则可以使用此方法 - 输出的行数相同)。我没有在&#34;更新t ...&#34;格式;如果需要,这应该相对容易。我无法判断我是否必须改变价值观#34;意味着就位(即更新)或者如果它与输入相比在输出中意味着什么。

这是输入表(仅一行)的样子:

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))

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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