Как пакетно заменить строки в поле в SQL - PullRequest
0 голосов
/ 28 января 2019

Контекст и цель

Я пытаюсь псевдоанонимизировать некоторые номера продуктов в моей таблице данных.Смотрите пример кода ниже.Номера продуктов состоят из 10 цифр и могут быть или не быть уникальными для таблицы.

Поскольку есть потенциально другие таблицы, на которые я хотел бы сослаться, я хотел бы использовать неслучайный способ псевдоанонимизации данных.

Система - SQLite 3.10.1.Тем не менее, подойдет любой тип СУБД с SQL.

Мои ограничения:

  • Сохраняйте ту же длину, что и исходная
  • Обменяйте каждую цифровую цифру налибо другая цифровая цифра, либо буква

Действия, которые я предпринял

Я буквально собирался просмотреть каждую возможную цифру и обновить ее, как показано ниже.Однако это выглядит как очень неэффективный способ сделать это.

UPDATE test
SET pseudo_num = replace(pseudo_num, '0', 'B');
UPDATE test
SET pseudo_num = replace(pseudo_num, '1', 'T');
UPDATE test
SET pseudo_num = replace(pseudo_num, '2', 'A');
UPDATE test
SET pseudo_num = replace(pseudo_num, '3', 'A');
UPDATE test
SET pseudo_num = replace(pseudo_num, '4', 'D');
UPDATE test
SET pseudo_num = replace(pseudo_num, '5', '3');
UPDATE test
SET pseudo_num = replace(pseudo_num, '6', '2');
UPDATE test
SET pseudo_num = replace(pseudo_num, '7', '4');
UPDATE test
SET pseudo_num = replace(pseudo_num, '8', 'X');
UPDATE test
SET pseudo_num = replace(pseudo_num, '9', 'L');

Вопросы

  1. Есть ли более быстрый способ сделать это, например, с помощью партиизамены?
  2. Существует ли альтернативный стандартный способ выполнения псевдоанонимизации, на котором я могу опираться, с учетом ограничений, которые я обрисовал выше?

Пример кода для создания данныхстол

CREATE TABLE test (
  prod_num varchar(14),
  owner varchar(255) default NULL,
  prod_date varchar(255)
);

INSERT INTO test (prod_num,owner,prod_date) VALUES ("260619275","Kieran","Feb 10, 2018"),("316556232","Steven","Jan 6, 2020"),("625302534","Oliver","Feb 10, 2018"),("811424845","Jeremy","Apr 12, 2018"),("060961216","Quinlan","Jul 19, 2019"),("713794360","Stuart","Nov 1, 2019"),("553381666","George","Jan 8, 2019"),("978519361","Macon","Nov 26, 2018"),("352718969","Raphael","Jul 21, 2019"),("803299478","Byron","Nov 26, 2019");
INSERT INTO test (prod_num,owner,prod_date) VALUES ("696124452","Dalton","Jul 17, 2018"),("892088485","Keane","Jul 9, 2018"),("817054190","Dillon","Apr 23, 2018"),("500170097","Fitzgerald","Feb 11, 2019"),("663252252","Thomas","Apr 10, 2018"),("061983557","Alan","May 12, 2018"),("492057435","Jarrod","Apr 16, 2018"),("837802495","Shad","Mar 22, 2019"),("725698187","Mark","Jul 22, 2018"),("153352349","Akeem","Feb 19, 2018");

ALTER TABLE test 
ADD pseudo_num NVARCHAR(20);

UPDATE test 
SET pseudo_num = prod_num;

Ответы [ 4 ]

0 голосов
/ 28 января 2019

На Мариадб:

alter table test add primary key (prod_num);
replace into test(prod_num, owner, prod_date, pseudo_num)
select 
    prod_num,
    owner,
    prod_date,
    replace(
        replace(
            replace(
                replace(
                    replace(
                        replace(
                            replace(
                                replace(
                                    replace(
                                        replace(prod_num,'0','B')
                                    ,'1','T')
                                ,'2','A')
                            ,'3','A')
                        ,'4','D')
                    ,'5','3')
                ,'6','2')
            ,'7','4')
        ,'8','X')
    ,'9','L') as pseudo_num
from test;
0 голосов
/ 28 января 2019

Вы сказали, что «подойдет любой тип СУБД с SQL», так что это для Postgres:

В Postgres вы можете использовать для этого функцию translate () :

UPDATE test
  SET pseudo_num = translate(pseudo_num, '0123456789', 'BTAAD324XL');

Онлайн пример: https://rextester.com/OIMBB72939

0 голосов
/ 28 января 2019

Вы можете использовать функцию хеширования (или шифрования) для преобразования номеров продуктов в строки с символами и числами одинаковой длины.Те же номера продуктов также получают тот же хэш / значение:

Пример на TSQL:

-- preview (old and new prod_num)
SELECT prod_num, RIGHT(CONVERT(VARCHAR(32), HASHBYTES('SHA1', prod_num), 2), LEN(prod_num)) 
FROM test;

-- the UPDATE
UPDATE test SET pseudo_num = RIGHT(CONVERT(VARCHAR(32), HASHBYTES('SHA1', prod_num), 2), LEN(prod_num));

демо на dbfiddle.uk

Пример на MySQL:

-- preview (old and new prod_num)
SELECT prod_num, UPPER(RIGHT(MD5(prod_num), LENGTH(prod_num))) 
FROM test;

-- the UPDATE
UPDATE test SET pseudo_num = UPPER(RIGHT(MD5(prod_num), LENGTH(prod_num)));

демо на dbfiddle.uk

Пример на Oracle:

-- preview (old and new prod_num)
SELECT prod_num, SUBSTR(STANDARD_HASH(prod_num, 'MD5'), LENGTH(prod_num) * -1) pseudo_prod_num 
FROM test;

-- the UPDATE
UPDATE test SET pseudo_num = SUBSTR(STANDARD_HASH(prod_num, 'MD5'), LENGTH(prod_num) * -1);

демо на dbfiddle.uk

Пример PostgreSQL:

-- preview (old and new prod_num)
SELECT prod_num, UPPER(RIGHT(MD5(prod_num), LENGTH(prod_num))) 
FROM test;

-- the UPDATE
UPDATE test SET pseudo_num = UPPER(RIGHT(MD5(prod_num), LENGTH(prod_num)));

демо на dbfiddle.uk

0 голосов
/ 28 января 2019

Вы можете попробовать использовать здесь соединение для замены.Если у вас нет формальной таблицы, которая содержит отображение из старого в новое pseduo_num, то мы можем попробовать использовать CTE.

WITH map AS (
    SELECT '0' AS pseudo_num, 'B' AS output UNION ALL
    SELECT '1', 'T' UNION ALL
    SELECT '2', 'A' UNION ALL
    SELECT '3', 'A' UNION ALL
    SELECT '4', 'D' UNION ALL
    SELECT '5', '3' UNION ALL
    SELECT '6', '2' UNION ALL
    SELECT '7', '4' UNION ALL
    SELECT '8', 'X' UNION ALL
    SELECT '9', 'L'
),
cte AS (
    SELECT t.pseudo_num, m.output
    FROM test t
    INNER JOIN map m
        ON t.pseudo_num = m.psuedo_num
)

UPDATE cte
SET pseudo_num = output;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...