我们处理了很多敏感数据,我想仅使用每个名称部分的第一个和最后一个字母来掩盖乘客姓名,并将这些名称加入三个星号(***),
例如:名称'John Doe'将成为'J *** n D *** e'
对于由两部分组成的名称,可以通过使用表达式查找空格来实现:
LEFT(CardHolderNameFromPurchase, 1) +
'***' +
CASE WHEN CHARINDEX(' ', PassengerName) = 0
THEN RIGHT(PassengerName, 1)
ELSE SUBSTRING(PassengerName, CHARINDEX(' ', PassengerName) -1, 1) +
' ' +
SUBSTRING(PassengerName, CHARINDEX(' ', PassengerName) +1, 1) +
'***' +
RIGHT(PassengerName, 1)
END
但是,乘客名称可以有两个以上的部分,没有实际限制。我怎样才能找到表达式中所有空格的索引?或者我应该以不同的方式解决这个问题?
非常感谢任何帮助或指针!
答案 0 :(得分:5)
此解决方案可以满足您的需求,但在尝试隐藏可识别个人身份的数据时,这种方法确实是错误的,正如戈登在答案中的解释所示。
SQL:
declare @t table(n nvarchar(20));
insert into @t values('John Doe')
,('JohnDoe')
,('John Doe Two')
,('John Doe Two Three')
,('John O''Neill');
select n
,stuff((select ' ' + left(s.item,1) + '***' + right(s.item,1)
from dbo.fn_StringSplit4k(t.n,' ',null) as s
for xml path('')
),1,1,''
) as mask
from @t as t;
输出:
+--------------------+-------------------------+
| n | mask |
+--------------------+-------------------------+
| John Doe | J***n D***e |
| JohnDoe | J***e |
| John Doe Two | J***n D***e T***o |
| John Doe Two Three | J***n D***e T***o T***e |
| John O'Neill | J***n O***l |
+--------------------+-------------------------+
基于Jeff Moden's Tally Table approach的字符串拆分功能:
create function [dbo].[fn_StringSplit4k]
(
@str nvarchar(4000) = ' ' -- String to split.
,@delimiter as nvarchar(1) = ',' -- Delimiting value to split on.
,@num as int = null -- Which value to return, null returns all.
)
returns table
as
return
-- Start tally table with 10 rows.
with n(n) as (select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1)
-- Select the same number of rows as characters in @str as incremental row numbers.
-- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length.
,t(t) as (select top (select len(isnull(@str,'')) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
-- Return the position of every value that follows the specified delimiter.
,s(s) as (select 1 union all select t+1 from t where substring(isnull(@str,''),t,1) = @delimiter)
-- Return the start and length of every value, to use in the SUBSTRING function.
-- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,isnull(@str,''),s),0)-s,4000) from s)
select rn
,item
from(select row_number() over(order by s) as rn
,substring(@str,s,l) as item
from l
) a
where rn = @num
or @num is null;
GO
答案 1 :(得分:2)
如果您将PassengerName视为敏感信息,则不应将其以明文形式存储在通常可访问的表中。周期。
有几种不同的选择。
一个是提供敏感信息的参考表。引用它的任何表都将具有id而不是名称。中提琴。如果没有访问参考表,就无法获得敏感信息,这将受到严格限制。
第二种方法是可逆压缩算法。这将使得价值变得胡言乱语,但是如果有正确的知识,它可以转化为有意义的价值。典型的方法是由Rivest,Shamir和Adelman(RSA编码)设计的公钥加密算法。
如果你想做名字的第一个和最后一个字母,我会非常小心亚洲名字。当用拉丁文写成时,其中许多由两到三个字母组成。这并不是很隐蔽。 SQL Server没有简单的机制来执行此操作。您可以使用循环编写用户定义的函数来管理进程。但是,我认为这是最不安全和最不可取的方法。
答案 2 :(得分:2)
这使用了Jeff Moden的DelimitedSplit8K,以及SQL Server 2017 STRING_AGG
中的新功能。因为我不知道你正在使用什么版本,所以我已经离开了#34;整个生猪"并且假设您使用的是最新版本。
Jeff的功能在这里非常宝贵,因为它返回了序数位置,这是微软从他们自己的函数中忽略了愚蠢的东西,STRING_SPLIT
(并且没有2017年加入)。顺序位置是关键,因此我们无法使用内置函数。
WITH VTE AS(
SELECT *
FROM (VALUES ('John Doe'),('Jane Bloggs'),('Edgar Allan Poe'),('Mr George W. Bush'),('Homer J Simpson')) V(FullName)),
Masking AS (
SELECT *,
ISNULL(STUFF(Item, 2, LEN(item) -2,'***'), Item) AS MaskedPart
FROM VTE V
CROSS APPLY dbo.delimitedSplit8K(V.Fullname, ' '))
SELECT STRING_AGG(MaskedPart,' ') AS MaskedFullName
FROM Masking
GROUP BY Fullname;
编辑:没关系,OP评论说他们正在使用2008,所以STRING_AGG
是不可能的。然而,@ amddave发布了一个与我自己非常相似的答案,只需按照旧式的XML方式进行操作即可。
答案 3 :(得分:2)
根据您的SQL Server版本,您可以使用内置字符串拆分为名称中空格的行,执行字符串格式设置,然后使用XML路径回滚到名称级别。
create table dataset (id int identity(1,1), name varchar(50));
insert into dataset (name) values
('John Smith'),
('Edgar Allen Poe'),
('One Two Three Four');
with split as (
select id, cs.Value as Name
from dataset
cross apply STRING_SPLIT (name, ' ') cs
),
formatted as (
select
id,
name,
left(name, 1) + '***' + right(name, 1) as out
from split
)
SELECT
id,
(SELECT ' ' + out
FROM formatted b
WHERE a.id = b.id
FOR XML PATH('')) [out_name]
FROM formatted a
GROUP BY id
结果:
id out_name
1 J***n S***h
2 E***r A***n P***e
3 O***e T***o T***e F***r
答案 4 :(得分:2)
您可以使用此功能执行此操作。
create function [dbo].[fnMaskName] (@var_name varchar(100))
RETURNS varchar(100)
WITH EXECUTE AS CALLER
AS
BEGIN
declare @var_part varchar(100)
declare @var_return varchar(100)
declare @n_position smallint
set @var_return = ''
set @n_position = 1
WHILE @n_position<>0
BEGIN
SET @n_position = CHARINDEX(' ', @var_name)
IF @n_position = 0
SET @n_position = LEN(@var_name)
SET @var_part = SUBSTRING(@var_name, 1, @n_position)
SET @var_name = SUBSTRING(@var_name, @n_position+1, LEN(@var_name))
if @var_part<>''
SET @var_return = @var_return + stuff(@var_part, 2, len(@var_part)-2, replicate('*',len(@var_part)-2)) + ' '
END
RETURN(@var_return)
END