This article describes a function that will return random data based on a given value. The function intends to determine the data type and return data that is absolutely irrelevant to the original data but the same length and the same type of data.
Why?
The joy of working with the plethora of applications out there result in me using MySQL, Oracle PL/SQL and Transact SQL in my day job. The equivalent functions have to be written up all in the name of "seamless integration"...
How?
Previously I had tried to write a smart function which could determine the datatype automatically but as you may know, Oracle has a funny way of working with dates which made this need to be changed. The following function now requires a second parameter where you specify the data type:
CREATE OR REPLACE FUNCTION UFN_DATASCRAMBLE ( p_original_value IN VARCHAR2, p_original_datatype IN VARCHAR2, p_original_range_1 IN VARCHAR2 DEFAULT NULL, -- no effect on strings p_original_range_2 IN VARCHAR2 DEFAULT NULL -- no effect on strings ) RETURN VARCHAR2 IS v_char_at NUMBER := 0; -- v_char_at : internal variable for string indexing v_rand_param1 VARCHAR2(50) := ''; -- v_rand_param1 : parameter 1 for dbms_random function v_rand_param2 VARCHAR2(50) := ''; -- v_rand_param2 : parameter 2 for dbms_random function v_returnedval VARCHAR2(255) := ''; -- v_returnedval : value to be returned BEGIN IF p_original_value IS NULL THEN v_returnedval := NULL; ELSIF p_original_datatype='INT' THEN -- Check Parameters and assign proper default values IF p_original_range_1 IS NULL THEN v_rand_param1 := POWER(10, (LENGTH(p_original_value)-1)); -- should yield eg. 100000 ELSE v_rand_param1 := p_original_range_1; END IF; IF p_original_range_2 IS NULL THEN v_rand_param2 := POWER(10, LENGTH(p_original_value))-1; -- should yield eg. 999999 ELSE v_rand_param2 := p_original_range_2; END IF; -- Determined submitted value as 'INTEGER'; v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2)); v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value)); ELSIF p_original_datatype='FLOAT' THEN -- Determined submitted value as 'FLOAT'; v_char_at := (INSTR(p_original_value, '.')-1); v_rand_param1 := POWER(10, (LENGTH(p_original_value) - v_char_at)); -- should yield eg. 10 v_rand_param2 := POWER(10, (LENGTH(p_original_value) - v_char_at+1)-1); -- should yield eg. 99 v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2)); v_rand_param1 := POWER(10, (v_char_at - 1)); -- should yield eg. 100000 v_rand_param2 := POWER(10, v_char_at) - 1; -- should yield eg. 999999 v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2))||'.'||v_returnedval; v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value)); ELSIF p_original_datatype='VARCHAR' THEN IF LENGTH(TRIM(TRANSLATE(p_original_value, 'abcdefghijklmnopqrstuvwxyz ', ' '))) IS NULL THEN -- Determined submitted value as 'ALPHALOWER'; v_rand_param1 := 'L'; v_rand_param2 := LENGTH(p_original_value); v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2); ELSIF LENGTH(TRIM(TRANSLATE(p_original_value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ', ' '))) IS NULL THEN -- Determined submitted value as 'ALPHAUPPER'; v_rand_param1 := 'U'; v_rand_param2 := LENGTH(p_original_value); v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2); ELSIF LENGTH(TRIM(TRANSLATE(p_original_value, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ', ' '))) IS NULL THEN -- Determined submitted value as 'ALPHABOTH'; v_rand_param1 := 'A'; v_rand_param2 := LENGTH(p_original_value); v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2); ELSIF LENGTH(TRIM(TRANSLATE(LOWER(p_original_value), 'abcdefghijklmnopqrstuvwxyz0123456789 ', ' '))) IS NULL THEN -- Determined submitted value as 'ALPHANUMERIC'; v_rand_param1 := 'X'; v_rand_param2 := LENGTH(p_original_value); v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2); ELSE -- Determined submitted value as 'STRING'; v_rand_param1 := 'P'; v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, LENGTH(p_original_value)); END IF; v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value)); ELSIF p_original_datatype='DATE' THEN -- Check Parameters and assign proper default values IF p_original_range_1 IS NULL THEN v_rand_param1 := '01/01/1901 00:00:00'; ELSE v_rand_param1 := p_original_range_1; END IF; IF p_original_range_2 IS NULL THEN v_rand_param2 := '01/01/2001 23:59:59'; ELSE v_rand_param2 := p_original_range_2; END IF; -- Determined submitted value as 'DATE'; v_rand_param1 := TO_CHAR(TO_DATE(v_rand_param1,'dd/mm/yyyy hh24:mi:ss'),'J'); -- eg. from 01/01/1901 (Julian Days) v_rand_param2 := TO_CHAR(TO_DATE(v_rand_param2,'dd/mm/yyyy hh24:mi:ss'),'J'); -- eg. to 01/01/2001 (Julian Days) v_returnedval := TO_DATE(TRUNC(DBMS_RANDOM.VALUE(v_rand_param1,v_rand_param2)),'J'); END IF; RETURN v_returnedval; EXCEPTION WHEN no_data_found THEN RETURN ('Error in submitted value'); WHEN others THEN RETURN ('Unable to generate random value'); END UFN_DATASCRAMBLE;
- CREATE OR REPLACE FUNCTION UFN_DATASCRAMBLE
- (
- p_original_value IN VARCHAR2,
- p_original_datatype IN VARCHAR2,
- p_original_range_1 IN VARCHAR2 DEFAULT NULL, -- no effect on strings
- p_original_range_2 IN VARCHAR2 DEFAULT NULL -- no effect on strings
- )
- RETURN VARCHAR2
- IS
- v_char_at NUMBER := 0; -- v_char_at : internal variable for string indexing
- v_rand_param1 VARCHAR2(50) := ''; -- v_rand_param1 : parameter 1 for dbms_random function
- v_rand_param2 VARCHAR2(50) := ''; -- v_rand_param2 : parameter 2 for dbms_random function
- v_returnedval VARCHAR2(255) := ''; -- v_returnedval : value to be returned
- BEGIN
- IF p_original_value IS NULL THEN
- v_returnedval := null;
- ELSIF p_original_datatype='INT' THEN
- -- Check Parameters and assign proper default values
- IF p_original_range_1 IS NULL THEN
- v_rand_param1 := POWER(10, (LENGTH(p_original_value)-1)); -- should yield eg. 100000
- ELSE
- v_rand_param1 := p_original_range_1;
- END IF;
- IF p_original_range_2 IS NULL THEN
- v_rand_param2 := POWER(10, LENGTH(p_original_value))-1; -- should yield eg. 999999
- ELSE
- v_rand_param2 := p_original_range_2;
- END IF;
- -- Determined submitted value as 'INTEGER';
- v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2));
- v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value));
- ELSIF p_original_datatype='FLOAT' THEN
- -- Determined submitted value as 'FLOAT';
- v_char_at := (INSTR(p_original_value, '.')-1);
- v_rand_param1 := POWER(10, (LENGTH(p_original_value) - v_char_at)); -- should yield eg. 10
- v_rand_param2 := POWER(10, (LENGTH(p_original_value) - v_char_at+1)-1); -- should yield eg. 99
- v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2));
- v_rand_param1 := POWER(10, (v_char_at - 1)); -- should yield eg. 100000
- v_rand_param2 := POWER(10, v_char_at) - 1; -- should yield eg. 999999
- v_returnedval := TRUNC(DBMS_RANDOM.VALUE(v_rand_param1, v_rand_param2))||'.'||v_returnedval;
- v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value));
- ELSIF p_original_datatype='VARCHAR' THEN
- IF LENGTH(TRIM(TRANSLATE(p_original_value, 'abcdefghijklmnopqrstuvwxyz ', ' '))) IS NULL THEN
- -- Determined submitted value as 'ALPHALOWER';
- v_rand_param1 := 'L';
- v_rand_param2 := LENGTH(p_original_value);
- v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2);
- ELSIF LENGTH(TRIM(TRANSLATE(p_original_value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ', ' '))) IS NULL THEN
- -- Determined submitted value as 'ALPHAUPPER';
- v_rand_param1 := 'U';
- v_rand_param2 := LENGTH(p_original_value);
- v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2);
- ELSIF LENGTH(TRIM(TRANSLATE(p_original_value, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ', ' '))) IS NULL THEN
- -- Determined submitted value as 'ALPHABOTH';
- v_rand_param1 := 'A';
- v_rand_param2 := LENGTH(p_original_value);
- v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2);
- ELSIF LENGTH(TRIM(TRANSLATE(LOWER(p_original_value), 'abcdefghijklmnopqrstuvwxyz0123456789 ', ' '))) IS NULL THEN
- -- Determined submitted value as 'ALPHANUMERIC';
- v_rand_param1 := 'X';
- v_rand_param2 := LENGTH(p_original_value);
- v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, v_rand_param2);
- ELSE
- -- Determined submitted value as 'STRING';
- v_rand_param1 := 'P';
- v_returnedval := DBMS_RANDOM.STRING(v_rand_param1, LENGTH(p_original_value));
- END IF;
- v_returnedval := SUBSTR(v_returnedval,1,LENGTH(p_original_value));
- ELSIF p_original_datatype='DATE' THEN
- -- Check Parameters and assign proper default values
- IF p_original_range_1 IS NULL THEN
- v_rand_param1 := '01/01/1901 00:00:00';
- ELSE
- v_rand_param1 := p_original_range_1;
- END IF;
- IF p_original_range_2 IS NULL THEN
- v_rand_param2 := '01/01/2001 23:59:59';
- ELSE
- v_rand_param2 := p_original_range_2;
- END IF;
- -- Determined submitted value as 'DATE';
- v_rand_param1 := TO_CHAR(TO_DATE(v_rand_param1,'dd/mm/yyyy hh24:mi:ss'),'J'); -- eg. from 01/01/1901 (Julian Days)
- v_rand_param2 := TO_CHAR(TO_DATE(v_rand_param2,'dd/mm/yyyy hh24:mi:ss'),'J'); -- eg. to 01/01/2001 (Julian Days)
- v_returnedval := TO_DATE(TRUNC(DBMS_RANDOM.VALUE(v_rand_param1,v_rand_param2)),'J');
- END IF;
- RETURN v_returnedval;
- EXCEPTION
- WHEN no_data_found THEN
- RETURN ('Error in submitted value');
- WHEN others THEN
- RETURN ('Unable to generate random value');
- END UFN_DATASCRAMBLE;
Usage
SELECT -- UFN_DATASCRAMBLE(DATE_CREATED, 'DATE') scramble_column, -- testing inputted column UFN_DATASCRAMBLE(0123456789012345, 'INT') random_integer, -- testing 16 digit number UFN_DATASCRAMBLE(0123456789012345, 'INT',1,9) random_integer_range, -- testing integer with range UFN_DATASCRAMBLE(1234.567, 'FLOAT') random_float, -- testing decimal UFN_DATASCRAMBLE('ABCDEFGH', 'VARCHAR') random_upper, -- testing uppercase UFN_DATASCRAMBLE('abcdefgh', 'VARCHAR') random_lower, -- testing lowercase UFN_DATASCRAMBLE('ABCDefgh', 'VARCHAR') random_both, -- testing upper and lowercase UFN_DATASCRAMBLE('ABCD1234', 'VARCHAR') random_alphanum, -- testing alphanumeric UFN_DATASCRAMBLE('ABcd12.!', 'VARCHAR') random_other, -- testing string (any char) UFN_DATASCRAMBLE(TO_DATE('01:00:00','HH:MI:SS'), 'DATE') random_time, -- testing time UFN_DATASCRAMBLE(TO_DATE('12/31/2012','mm/dd/yyyy'), 'DATE') random_date, -- testing date UFN_DATASCRAMBLE(TO_DATE('2012-01-01 05:31:18','YYYY-MM-DD HH24:MI:SS'), 'DATE') random_timestamp, -- testing timestamp UFN_DATASCRAMBLE(TO_DATE('2012-01-01','yyyy-mm-dd'), 'DATE','01/01/1000','31/12/1002') random_daterange -- testing date range FROM UFN_STUDENT_ACCOUNTS WHERE ROWNUM
- SELECT
- -- UFN_DATASCRAMBLE(DATE_CREATED, 'DATE') scramble_column, -- testing inputted column
- UFN_DATASCRAMBLE(0123456789012345, 'INT') random_integer, -- testing 16 digit number
- UFN_DATASCRAMBLE(0123456789012345, 'INT',1,9) random_integer_range, -- testing integer with range
- UFN_DATASCRAMBLE(1234.567, 'FLOAT') random_float, -- testing decimal
- UFN_DATASCRAMBLE('ABCDEFGH', 'VARCHAR') random_upper, -- testing uppercase
- UFN_DATASCRAMBLE('abcdefgh', 'VARCHAR') random_lower, -- testing lowercase
- UFN_DATASCRAMBLE('ABCDefgh', 'VARCHAR') random_both, -- testing upper and lowercase
- UFN_DATASCRAMBLE('ABCD1234', 'VARCHAR') random_alphanum, -- testing alphanumeric
- UFN_DATASCRAMBLE('ABcd12.!', 'VARCHAR') random_other, -- testing string (any char)
- UFN_DATASCRAMBLE(TO_DATE('01:00:00','HH:MI:SS'), 'DATE') random_time, -- testing time
- UFN_DATASCRAMBLE(TO_DATE('12/31/2012','mm/dd/yyyy'), 'DATE') random_date, -- testing date
- UFN_DATASCRAMBLE(TO_DATE('2012-01-01 05:31:18','YYYY-MM-DD HH24:MI:SS'), 'DATE') random_timestamp, -- testing timestamp
- UFN_DATASCRAMBLE(TO_DATE('2012-01-01','yyyy-mm-dd'), 'DATE','01/01/1000','31/12/1002') random_daterange -- testing date range
- FROM
- UFN_STUDENT_ACCOUNTS
- WHERE
- ROWNUM
Additional
Note the return values for the dates and times, in Oracle you would need to specify how you want the return date specified. In the case where the above is used to update a set of data in a table (hopefully a copy of the original one :)), the database will set the format automatically:
UPDATE my_table SET my_column=UFN_DATASCRAMBLE(my_column, my_datatype);
- UPDATE my_table SET my_column=UFN_DATASCRAMBLE(my_column, my_datatype);