I am looking for a simple way to de-identificate data in BigQuery (and in SQL in general), that handle:
- Anonymize Personally identifiable information (PII) with a unique random value
- Always have the same de-identificate value for a PII value
- Have the possibility to retrieve the original value
I have tried to implement a solution, but I would like to know if there is a more efficient way to handle this. In our database, we don't have a lot of data to anonymise (max 100 000 entries).
This is a simple exemple of the solution:
CREATE SCHEMA dataset_raw_data; -- (only Admin has access to this dataset)
CREATE SCHEMA dataset_clean_data; -- (all team have access to this dataset)
CREATE table dataset_raw_data.users(
id string,
email_pii string,
name_pii string
)
CREATE table dataset_clean_data.users(
id string,
email string,
name string
)
I created a mapping table (only accessible by the Admin):
create table dataset_raw_data.pii_mapping(
pii_value STRING,
anonimize_value STRING
)
And this is my script to populate the table dataset_clean_data.users. If this is the right approach, the objective will be to create a procedure that generates these requests dynamically
-- Insert missing values in table dataset_raw_data.pii_mapping
insert into dataset_raw_data.pii_mapping
select lower(users.pii_value) as pii_value, GENERATE_UUID() as anonimize_value
from (
select distinct email_pii as pii_value from dataset_raw_data.users
union distinct
select distinct name_pii as pii_value from dataset_raw_data.users
) as base_table
LEFT JOIN dataset_raw_data.pii_mapping as pii_mapping
ON lower(base_table.pii_value) = pii_mapping.pii_value
WHERE pii_mapping.pii_value IS NULL
and base_table.pii_value IS NOT NULL;
-- Populate the table dataset_clean_data.users
insert into table dataset_clean_data.users
select base_table.id as id
pii_mapping1.anonimize_value as email
pii_mapping2.anonimize_value as name
from
dataset_raw_data.users as base_table,
dataset_raw_data.pii_mapping as pii_mapping1,
dataset_raw_data.pii_mapping as pii_mapping2
where
lower(base_table.email) = pii_mapping1.pii_value
AND lower(base_table.name) = pii_mapping2.pii_value
;
So at the end I have those data:
select * from dataset_raw_data.users LIMIT 1; -- 1 | bob@gmail.com | Bob
select * from dataset_clean_data.users LIMIT 1; -- 1 | 7d25df8d-4b4d-46ad-9df3-8c71bf092f9f | 1f042eaa-a6b1-4b86-95a9-f6188d3f70d7
Thanks for your feedback.