行中的 Oracle Shuffle 列

Oracle Shuffle columns in rows

基于这个问题的解决方案 - - 我需要申请这个,一个新的条件:名字必须保证性别:男性,女性或未知。

所以,我的 table 有一个名为 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 

在分析函数的 PARTITION BY 子句和 JOIN 子句中包含性别。如果您没有要匹配的主键,那么您可以使用 ROWID pseudo-column.

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