我们有一个包含大量数据的大型数据库。我最近发现我们的销售和运输部门一直在使用应用程序的一部分来公开存储客户的信用卡号码。我们已经停止了它,但现在有数千行数字。
我们试图弄清楚如何连续扫描某些16列的数据(或破折号分隔)并用X替换它们。
这不是一个简单的UPDATE语句,因为卡号存储在大量文本中。到目前为止,我一直无法弄清楚SQL Server是否能够使用正则表达式(看起来不是这样)。
所有其他方法都失败了我会通过PHP做到这一点,因为这是我最擅长的......但它会很痛苦。
答案 0 :(得分:4)
听起来你需要使用PATINDEX和WHERE LIKE子句。
像这样的东西。使用类似的东西创建一个存储过程,然后用你已经识别的一堆不同参数(使@pattern& @patternlength the params)调用它,直到你替换了所有的实例。
declare @pattern varchar(100), @patternlength int
set @pattern = '[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]'
set @patternlength = 19
update tableName
set fieldName =
LEFT(fieldName, patindex('%'+ @pattern + '%', fieldName)-1)
+ 'XXXX-XXXX-XXXX-XXXX'
+ SUBSTRING(fieldName, PATINDEX('%'+ @pattern + '%', fieldName)+@patternlength, LEN(fieldName))
from tableName
where fieldName like '%'+ @pattern + '%'
诀窍就是找到合适的模式,并设置适当的@patternlength值(不是@pattern的长度,因为它不起作用!)
答案 1 :(得分:4)
我认为你最好以编程方式做这件事,特别是因为你提到数据可以采用几种不同的格式。请记住,并非所有信用卡号码都是16位数字(美国运通卡是15,维萨是13或16等)。
如果可能的话,检查各种正则表达式和验证代码的能力可能最好在清理作业级别提供。
答案 2 :(得分:1)
简易肖恩的答案。
以下内容将在@text中找到@maskPattern的所有匹配项,并将其替换为' x'。 例如,如果@maskPattern = XXXX-XXXX-XXXX-XXXX,它将在@text中找到此模式,并用XXXX-XXXX-XXXX-XXXX替换所有出现的模式。如果没有发现任何事件,它将保留文本原样。
此存储过程也可以被操作为仅掩盖maskPattern开头的3/4。干杯!
ALTER PROCEDURE [dbo].[SP_MaskCharacters] @text nvarchar(max),
@maskPattern nvarchar(500)
AS
BEGIN
DECLARE @numPattern nvarchar(max) = REPLACE(@maskPattern, 'x', '[0-9]')
DECLARE @patternLength int = LEN(@maskPattern)
WHILE (@text IS NOT NULL)
BEGIN
IF PATINDEX('%' + @numPattern + '%', @text) = 0 BREAK;
SET @text =
LEFT(@text, PATINDEX('%' + @numPattern + '%', @text)-1) --Get beginning chars of the input text until first occurance of pattern is found
+ @maskPattern --Append aasking pattern
+ SUBSTRING(@text, PATINDEX('%' + @numPattern + '%', @text) + @patternLength, LEN(@text)) -- Get & append rest of the text found after masking attern
END
SELECT @text
END
答案 3 :(得分:0)
您可以使用patindex。它不会很漂亮,可能会有更简洁的方式来编写它。但你可以使用集合[0-9]
patindex:http://msdn.microsoft.com/en-us/library/ms188395.aspx
答案 4 :(得分:0)
对于发现此问题的人谁想要使用PHP,这里我使用的功能是信用卡号码(所有数字,带破折号或空格)并替换除了第一个和最后4个数字之外的所有数字与' X'。
要接受带破折号的信用卡号,请改用此正则表达式:
$cc_regex_pattern = '/(\d{4})(-)?(\d{4})(-)?(\d{4})(-)?(\d{4})/'
并删除删除短划线的cc编号的预处理:
$compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
所以替换字符串变为(因为我们已经改变了模式的索引 - 注意$ 7):
$cc_regex_replacement = '$1' . $cc_middle_pattern . '$7';
或者如果您愿意,只需替换整个cc号码,就像在原始问题中一样:
$cc_regex_replacement = 'XXXX$2XXXX$4XXXX$6XXXX';
这是信用卡号码的原始功能,包含或不包含空格或破折号,这些功能会混淆和删除任何破折号:
/**
* @param integer|string $credit_card_number
* @return mixed
*/
static function obfuscate_credit_card($credit_card_number)
{
$compressed_cc_number = preg_replace('/(\ |-)/', '', $credit_card_number);
$cc_length = strlen($compressed_cc_number);
$cc_middle_length = $cc_length >= 9 ? $cc_length - 8 : 0;
//create middle pattern
$cc_middle_pattern = '';
for ($i = 0; $i < $cc_middle_length; $i++) {
$cc_middle_pattern .= 'X';
}
//replace cc middle digits with middle pattern
$cc_regex_pattern = '/(\d{4})(\d+)(\d{4})/';
$cc_regex_replacement = '$1' . $cc_middle_pattern . '$3';
$obfuscated_cc = preg_replace($cc_regex_pattern, $cc_regex_replacement, $compressed_cc_number);
return $obfuscated_cc;
}
答案 5 :(得分:0)
我最近遇到了这种情况。使用 Patindex 和 Stuff 应该会有所帮助,但您需要分别对具有不同位数的 CC 号码进行重复。
-- For 16 digits CC numbers
UPDATE table
SET columnname = Stuff (columnname, Patindex(
'%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
, columnname), 16, '################')
WHERE Patindex(
'%[3-6][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
, columnname) > 0