I have Oracle 10g database. I want to mask my record of tables. It doesn't really need to make sense, it doesn't need to be readable. Just needs to be masked. For example:
select *
from customer;
LAST_NAME FIRST_NAME ADDRESS
-------------- -------------- --------------------
Doe John 10 someroad st
i convert to this :
LAST_NAME FIRST_NAME ADDRESS
-------------- -------------- --------------------
Ahd Uiea 55 xxxx ue
I need open source software that can do this work. What should i use?
You can use ORA_HASH or DBMS_CRYPTO package to full fill your requirements. Giving solution using DBMS_CRYPTO:
--Source data:
create table customer(last_name varchar2(50),first_name varchar2(50), address varchar2(200));
--Encrypt Function(Script Source):
CREATE OR REPLACE FUNCTION encrypt_value (p_in IN varchar2, p_key IN raw) RETURN raw IS l_enc_val raw (2000);
l_mod number := dbms_crypto.ENCRYPT_AES128 + dbms_crypto.CHAIN_CBC + dbms_crypto.PAD_PKCS5;
BEGIN l_enc_val := dbms_crypto.encrypt ( UTL_I18N.STRING_TO_RAW (p_in, 'AL32UTF8'), l_mod, p_key );
RETURN l_enc_val;
END;
--Function Implementation:
select encrypt_value(last_name,'AABBCC'),encrypt_value(first_name,'AABBCC'), encrypt_value(address,'AABBCC') from customer;
If you're using the Enterprise version of Oracle, you can use a Virtual Private Database (VPD) for this.
A VPD allows you to fine-grained access control (based on the account used to connect to the database). It can:
return only a subset of rows
use column masking to display sensitive columns as NULL values
It achieves this by appending a custom WHERE clause to every query run against the table. There's no way to circumvent it, and no need to adapt existing applications (for using a custom-built view etc.)
To create a VPD for your customer table, you need to:
create a function for generating the WHERE clause
create a policy for your database table
enable the policy
Function
CREATE OR REPLACE FUNCTION hide_address (
v_schema IN VARCHAR2,
v_objname IN VARCHAR2)
RETURN VARCHAR2 AS
result VARCHAR2 (200);
BEGIN
result := '1=0'; -- evaluates to FALSE for every account
RETURN (result);
END hide_address;
Creating a policy
BEGIN
DBMS_RLS.ADD_POLICY(
object_schema => 'scott',
object_name => 'customer',
policy_name => 'hide_address_policy',
policy_function => 'hide_address',
sec_relevant_cols =>' address',
sec_relevant_cols_opt => dbms_rls.ALL_ROWS);
END;
After enabling the policy, every query trying to access CUSTOMER.ADDRESS will return NULL. Depending on your requirements, you might want to add a view to access the table that returns a random address instead of NULL:
select name,
(case when address is NULL
then dbms_random.string('', 15)
else address end) as address
from
customer
Related
I would like to update table called people from:
to
Could you please help?
You need to parse out the beginning of the email address to add it to the domain name. Do that by finding the CHARINDEX of the # symbol, then subtracting one. Use that value as the length parameter in a LEFT function call.
Once you have the name from the email address, CONCATenate it to the static value of your domainname\.
I included a WHERE clause that you may want to use if you have a large number of rows where the Username is already correct and you don't want to waste a bunch of writes replacing a string with a duplicate of that same string. You could leave the WHERE off if you prefer.
UPDATE People
SET Username = CONCAT('domainname\',LEFT([E-mailAddress],CHARINDEX('#',[E-mailAddress])-1))
WHERE
Username <> CONCAT('domainname\',LEFT([E-mailAddress],CHARINDEX('#',[E-mailAddress])-1));
If you are working on earlier versions (cause CONCAT() is for 2012+ versions) and also if you have NULLs in the UserName column, you can do like
CREATE TABLE T(
[E-MailAddress] VARCHAR(50),
UserName VARCHAR(45)
);
INSERT INTO T VALUES
('abc#domainname.com', 'abc'),
('zxc#fhlbdm.com', NULL),
('MNO#domainname.com', 'MNO'),
('pqr#domainname.com', 'pq'),
('tyu#domainname.com', 'domainname\tyu');
UPDATE T
SET UserName = 'domainname\' + LEFT([E-MailAddress], CHARINDEX('#', [E-MailAddress])-1)
WHERE 'domainname\' + LEFT([E-MailAddress] , CHARINDEX('#', [E-MailAddress])-1) <> UserName
OR
UserName IS NULL;
SELECT *
FROM T;
I've a script that I simply paste into an SQL query window in POSTGRES 9.1 and run.
eg
-- Begin Scripts
-- Part 1
DO
$$
BEGIN
CREATE SEQUENCE base_listing_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE base_listing_id_seq
OWNER TO postgres;
EXCEPTION
WHEN duplicate_table THEN RAISE NOTICE 'sequence base_listing_id_seq already exists';
END
$$ LANGUAGE plpgsql;
-- Part 2
CREATE TABLE IF NOT EXISTS aes_fba_details
(
id serial NOT NULL,
product_id integer NOT NULL,
shippingprice numeric DEFAULT 0,
fbadatetime date NOT NULL,
currency text,
CONSTRAINT aes_fba_details_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE aes_fba_details
OWNER TO postgres;
-- End Scripts
What I want to do is to run part 1 or part 2 depending on a value (a version string if you like) that is read in from a table.
eg
myVariable = SELECT version-string FROM versionTable;
...
DO PART 1
...
If myVariable > 1 then
...
DO PART 2
...
End if
Is this even possible? I apologies in advance if I've mixed up the terminology.
It's possible, but you'll need to do all your DDL within a big DO block that uses IF conditions to decide what to do.
You cannot use variables or IF statements in plain SQL, only in PL/PgSQL.
We have a production Oracle database server maintained by our ERP partner.
For some custom development I need to connect to this Oracle database using Entity Framework 6. I have a user that can SELECT any table on the ERP schema and I create views in the schema/user used in my EF context.
The view itself is pretty straightforward, a few joins but all referencing tables on another schema ofcourse.
i.e.:
CREATE TABLE ERP.M_GROUP
(
FILE VARCHAR2(3 BYTE)
, MATFAM VARCHAR2(1 BYTE) NOT NULL
, GROUP VARCHAR2(20 BYTE) NOT NULL
, OMS1 VARCHAR2(60 BYTE)
, OMS2 VARCHAR2(60 BYTE)
, RESTW_FACTOR1_I NUMBER
)
CREATE VIEW EF6CTX.GROUPS AS
SELECT
GROUP Id,
MAX(OMS1) Name
FROM
M_GROUP
WHERE
FILE = 'BAT'
AND MATFAM IN ('B','C','I', 'K')
GROUP BY GROEP
When I connect to my database using Visual Studio's Entity Framework 6 Code First from Database identifing as user EF6CTX I can select this view and my model is created as it should.
But when I try to read these groups..
var ctx = new TestContext();
ctx.Database.Log = Console.WriteLine;
foreach (var group in ctx.GROUPS)
{
Console.WriteLine("Group: {0}", group.NAME);
}
I get this result:
Opened connection at 21/11/2014 15:29:05 +01:00
Started transaction at 21/11/2014 15:29:05 +01:00
create table "EF6CTX"."GROUPS"
(
"ID" varchar2(20 CHAR) not null,
"NAME" varchar2(60 CHAR) null,
constraint "PK_GROUPS" primary key ("ID")
)
-- Executing at 21/11/2014 15:29:05 +01:00
-- Failed in 217 ms with error: ORA-01031: insufficient privileges
The user EF6CTX has no permissions to create a table.. ofcourse. But why is it trying to create a table? It should USE the existing view!
Fixed when migrations are disabled:
System.Data.Entity.Database.SetInitializer<TestContext>(null);
I am not much strong in SQL, so looking for some help.
First I am looking for suggestion for the best way to implement this logic in SQL and then some sample code to implement.
My portal is going to connect Students and Training Providers.
Students: Select what courses (multiple) they want, type of delivery (online, class room), Industry(domain) to which the course to be targeted more, Location Preference.
Training Providers: Select what courses offering (so one record for each course), offering locations, type of delivery for each course, industries (multiple) it is targeting.
When student login:
I would like to create SP which in turn create view to store the matched records of the Training Providers data which matches that student needs of that StudentID, CourseID passed to SP
I have created the following sp ( but not included create view part as I am not sure how to do this)
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[sp_TPsMatched2StuCourse]
-- Add the parameters for the stored procedure here
#StuID int,
#CourseID int
AS
BEGIN
Select TP.MemID,TP.PastExp,SN.DeliveryType,SN.LocPref,SN.Industry,SC.CourseID from
tbl_TrainingProvider as TP , tbl_StuCourses as SC, tbl_StuNeeds SN
where SN.CourseID = #CourseID and SN.StuID = #StuID and
SN.DeliveryType in (TP.DeliveryMode) and
SN.LocPref IN (TP.LocOffering) and
SN.Industry IN (TP.Industries)
END
--- exec sp_ELsMatched2EntProp 1, 1
Why I need to put the data is as follows:
Assume the data is stored in that dynamic view and that would be bind to datagrid. Student then select interested TPs. Then only contact details would be shared to each other and this cannot be reveresed. So I would put this interested data in another table later. Every time data changes, hence the matches. Student can change some of his/her needs or new TPs join etc so view to be temparory.
when I executed this using above command, I am not getting data though it matches few records. What is wrong I am doing.
Any help would be greatly appreciated.
You are not getting expected results because you filter out too many records in WHERE( I'm talking about this part : SN.DeliveryType in (TP.DeliveryMode) and
SN.LocPref IN (TP.LocOffering) and SN.Industry IN (TP.Industries)). I'd recommend to use JOIN ... ON instead of specifying all tables in FROM and join condition in WHERE. I'm not sure what you want exactly, but I believe you are looking for
FROM tbl_StuNeeds SN
LEFT JOIN tbl_TrainingProvider as TP ON (TP.DeliveryMode = SN.DeliveryType AND
SN.LocPref = TP.LocOffering AND TP.Industries = SN.Industry)
WHERE SN.CourseID = #CourseID and SN.StuID = #StuID
Also, there is no join conditions in your code for tbl_StuCourses as SC which results in cross-join.
Finally, why do you need a stored procedure at all? From what I see in your example, a table-valued function will work better:
CREATE FUNCTION [dbo].getTPsMatched2StuCourse(#StuID INT,#CourseID INT)
RETURNS TABLE AS
RETURN
Select .... ;
I want that its name would be the page address. For example, if page has heading "Some Page", than its address should be http://somesite/some_page/.
"some_page"-name generated by system automatically. "some_page" - is the unique identifier of page. The problem in that the user in the future can enter a name which already exists that will cause an error.
It is necessary to find an optimum variant of the decision of a problem for great volumes of the data.
I have solved a problem as follows:
The page identifier in a database is the name of page and a suffix which is by default equal to zero. At page addition there is a check on existence. If such page does not exist, the suffix is equal 0 and its name is "some_page", if page is exist, than - search for the maximum number of a suffix and suffix=suffix+1 and page name become "some_page_1".
For this I create in a database the compound key from fields "suffix" and "pageName":
Table Pages
suffix|pageName |pageTitle
0 |some_page |Some Page
1 |some_page |Some Page
0 |other_page|Other Page
Addition of pages occurs through stored procedure:
CREATE PROCEDURE addPage (pageNameVal VARCHAR(100), pageTitleVal VARCHAR(100))
BEGIN
DECLARE v INT DEFAULT 0;
SELECT MAX(suffix) FROM pages WHERE pageName=pageNameVal INTO v;
IF v >= 0 THEN
SET v = v + 1;
ELSE
SET v = 0;
END IF;
INSERT INTO pages (suffix, pageName) VALUES (pageNameVal, v, pageTitleVal);
END;
Whether there are more the best decisions?
I think this should be okay - it would keep multiple instances of the key distinct. However, why not use a generated key instead of something provided by the user? If you maintain control over the page's lookup ID, you'll ensure no duplicates. Your current setup shouldn't cause any trouble, though.
The only problem (though it seems highly unlikely), is that your SP has a chance to duplicate the suffix for a particular key if two callers try to save the same key at the same time - ie, two simultaniousrequests with the same brand new pagename could both end up trying to use suffix 0. If you don't care about the result of your insert statement (and your current SP doesn't return it), then just do it in a single statement inside your SP:
CREATE PROCEDURE addPage (pageNameVal VARCHAR(100), pageTitleVal VARCHAR(100))
BEGIN
INSERT INTO pages (pageName, suffix, pageTitle)
SELECT n.pageNameVal, ISNULL(NextValue, 0), n.pageTitleVal
FROM (SELECT pageNameVal, pageTitleVal) n
LEFT
JOIN (SELECT MAX(suffix+1) as NextValue FROM pages WHERE pageName=pageNameVal) m
END