Как маскировать определенные значения и поддерживать уникальность при использовании оператора case ... when в MS SQL Server? - PullRequest
0 голосов
/ 23 октября 2018

Скажем, у меня есть столбец в таблице SQL Server со следующими записями:

+----+-----+
| ids| col1|
+----+-----+
|4   | a   |
|4   | b   |
|4   | a   |
|4   | b   |
|5   | a   |
+----+-----+

Я хотел бы замаскировать столбец ids, учитывая, что col1 = a.Однако я также хотел бы сохранить уникальность маскировки ids, поэтому результат будет выглядеть следующим образом:

+----+-----+
| ids| col1|
+----+-----+
|XX  | a   |
|4   | b   |
|XX  | a   |
|4   | b   |
|YY  | a   |
+----+-----+

Я использовал случай ... когда с алгоритмом SHA2_256 для поддержания уникальностикак в этом посте: Как замаскировать / зашифровать данные в представлении, но сохранить уникальность значений?

, но тогда получающаяся в результате маска представляет собой «выглядящие по-китайски» символы, которые кажутся машинныминечитаемым.Есть ли лучший способ?

Ответы [ 5 ]

0 голосов
/ 23 октября 2018

Вы также можете скрыть идентификаторы по целым числам (не знаю, достаточно ли это безопасно в вашем случае)

CREATE TABLE #t (ids int, col1 char(1));
INSERT INTO #t VALUES
(4, 'a'),
(4, 'b'),
(4, 'a'),
(4, 'b'),
(5, 'a');

Запрос

SELECT ISNULL(t2.num, t1.ids) AS ids, t1.col1
FROM 
    #t t1 LEFT JOIN 
    (
    SELECT 
        ROW_NUMBER() OVER (ORDER BY ids, col1) + (SELECT MAX(ids) FROM #t) AS num, 
        ids, col1 
    FROM #t 
    WHERE col1 = 'a' 
    GROUP BY ids, col1) t2 
        ON t1.ids = t2.ids AND t1.col1 = t2.col1;

Результат

ids                  col1
-------------------- ----
6                    a
4                    b
6                    a
4                    b
7                    a
0 голосов
/ 23 октября 2018

Так вот, что я в итоге и сделал.Используя пример, предоставленный @Zohar Peled, но с учетом того, что столбец ids является varchar, мы можем составить таблицу следующим образом:

DECLARE @T AS TABLE
(
    ids varchar(150), 
    col1 char(1)
)

INSERT INTO @T VALUES
(4, 'a'),
(4, 'b'),
(4, 'a'),
(4, 'b'),
(5, 'a')

и затем выполнить следующие действия:

SELECT  CASE WHEN col1 = 'a' THEN CONVERT(VARCHAR(150),HashBytes('SHA2_256', ids),2) ELSE ids END As ids,
col1
FROM @T

Это более похоже на первоначальное решение в ссылке, я полагаю.

0 голосов
/ 23 октября 2018

Будут ли цифры в порядке?

Сначала создайте и заполните образец таблицы ( Пожалуйста сохраните этот шаг в ваших будущих вопросах)

DECLARE @T AS TABLE
(
    ids int, 
    col1 char(1)
)

INSERT INTO @T VALUES
(4, 'a'),
(4, 'b'),
(4, 'a'),
(4, 'b'),
(5, 'a')

Запрос:

SELECT  CASE WHEN col1 = 'a' THEN CHECKSUM(CAST(Ids as varchar(11))) ELSE ids END As ids, 
        col1
FROM @T

Результаты:

ids     col1
136     a
4       b
136     a
4       b
137     a
0 голосов
/ 23 октября 2018

Предлагаемые вами маскированные выходные значения XX и YY, возможно, вводят в заблуждение, потому что если в вашей таблице миллионы значений id, то две буквы не смогут однозначно / случайным образом охватить все данные.Одним из вариантов здесь может быть использование NEWID() для генерации уникального UUID для каждой id группы:

WITH cte AS (
    SELECT DISTINCT id, NEWID() AS mask
    FROM yourTable
)

SELECT t2.mask, t1.col
FROM yourTable t1
INNER JOIN cte t2
    ON t1.id = t2.id;

Если вы не хотите показывать весь UUID, поскольку он слишком длинный, тогдавместо этого вы можете показать ее подстроку, например, только для первых 5 символов:

SELECT LEFT(t2.mask, 5) AS mask, t1.col
FROM yourTable t1
INNER JOIN cte t2
    ON t1.id = t2.id;

Но имейте в виду, что чем короче отображаемый вами UUID, тем больше вероятность, что два разных idгруппы будут отображаться с одинаковой маской.

0 голосов
/ 23 октября 2018

Попробуйте этот запрос (замените #test на ваше фактическое имя таблицы). В будущем может возникнуть ситуация, когда вам нужно будет добавить и другие символы в дополнение к просто 'a'.

Таблица ниже поможет вамс этим.

create table #list
(
col1 varchar(1)

)

insert into #list values ('a')

 select case when isnull(b.col1,'0')<>'0' then a.col1+cast ( Dense_rank() OVER(PARTITION BY a.col1 ORDER BY a.col1 ASC) as varchar(max)) else cast(a.ids as varchar(max)) end as ids, 
a.col1  from #test a
left join #list b
on a.col1 =b.col1

Out Put

enter image description here

...