Oracle Shuffle行的行

时间:2017-02-14 11:36:53

标签: oracle shuffle oracle12c masking

如果这个问题基于解决方案 - Shuffle a column between rows - 我需要适用于此,一个新条件:名称必须保证性别:男性,女性或未知。

所以,我的表有一个名为gender的列。我需要对同一性别的列进行洗牌。

我试过这个,但在某些情况下我无法保证性别

merge into original_table o
  using (
    with
         helper ( id, gender, rn, rand_rn ) as (
           select id,
                  gender,
                  row_number() over (order by id),
                  row_number() over (order by dbms_random.value())
           from   original_table
         )
    select ot.name, ot.gender, h2.id
    from   original_table ot inner join helper h1 on (ot.id = h1.id and ot.gender = h1.gender)
                             inner join helper h2 on h1.rand_rn = h2.rn
  ) p
on (o.id = p.id)
when matched then update set o.name = p.name
;

如果性别不可用(为空值),例如公司名称,则此合并不会更新任何内容。

我可以在3个不同的合并语句中拆分此查询。我拥有的每个性别一个。但我正在寻找一个更好,更简单的陈述。因为我需要在不同的环境和不同的条件下应用相同的解决方案。 感谢。

编辑:示例数据

 ID       GENDER  NAME                                                                                                 
3721       M      MARK
3722       M      JUSTIN
3723       F      RUTH
3724       F      MARY
3725       F      ANNE
4639              CAMPANY SA                                                                               
4640       M      JOHN
4641       M      LUCAS
4642              COMPANY HOLDER SA 

一种可能的解决方案:

 ID       GENDER  NAME                                                                                                 
3721       M      LUCAS
3722       M      JOHN
3723       F      MARY
3724       F      ANNE
3725       F      RUTH
4639              CAMPANY HOLDER SA                                                                               
4640       M      MARK
4641       M      JUSTIN
4642              COMPANY SA 

1 个答案:

答案 0 :(得分:2)

在分析函数和PARTITION BY子句中的JOIN子句中包含性别。如果您没有匹配的主键,则可以使用ROWID伪列。

Oracle安装程序

CREATE TABLE original_table ( id, gender, name, company ) AS
SELECT 1, 'F', 'Alice', CAST( NULL AS VARCHAR2(20) ) FROM DUAL UNION ALL
SELECT 2, 'M', 'Bobby', 'ACME' FROM DUAL UNION ALL
SELECT 3, 'F', 'Carol', 'XYZ'  FROM DUAL UNION ALL
SELECT 4, 'M', 'David', NULL   FROM DUAL UNION ALL
SELECT 5, 'M', 'Errol', 'ACME' FROM DUAL UNION ALL
SELECT 6, 'F', 'Fiona', 'XYZ'  FROM DUAL;

<强>更新

MERGE INTO original_table dst
USING (
  WITH rnd ( rid, rn, rnd_rn, gender, name ) AS (
    SELECT ROWID,
           ROW_NUMBER() OVER ( PARTITION BY gender ORDER BY id ),
           ROW_NUMBER() OVER ( PARTITION BY gender ORDER BY DBMS_RANDOM.VALUE ),
           gender,
           name
    FROM   original_table
  )
  SELECT o.rid, r.name
  FROM   rnd o INNER JOIN rnd r
         ON ( ( o.gender = r.gender OR ( o.gender IS NULL AND r.gender IS NULL ) )
             AND o.rn = r.rnd_rn )
)
ON ( dst.ROWID = src.ROWID )
WHEN MATCHED THEN
  UPDATE SET name = src.name;

<强>输出

SELECT * FROM original_table;

ID G NAME  COMPANY
-- - ----- -------
 1 F Fiona  
 2 M David ACME
 3 F Alice XYZ
 4 M Bobby 
 5 M Errol ACME
 6 F Carol XYZ