SQL Predicate
SQL Predicate
SQL Predicate
Oracle
SQL Predicate In Sales Cloud
INTRODUCTION
SQL Predicates are the units that stand behind all Application Roles from Sales Cloud.
Through SQL Predicates users gain access to the information that is contained in each object
you find in the application.
Regardless if that object is a seeded object or a custom made object,
information access is controlled via SQL Predicates
Learning to manipulate SQL Predicates will provide you the tools to set up the security of the
application according to your specific business requirements
In this document I will try to present how SQL Predicates are created and how they work, via
theory and practical examples.
I hope you will find it useful and will help you create your very own SQL predicates.
3
4 - SQL Predicate to show only those custom object records in which login user is in the sales
team of the account attached to the record.
Simply put the SQL Predicate is the WHERE clause of a SQL select operation.
In Sales Cloud every object, either custom made or out of the box is stored in a table or more tables from
the oracle database, the database on which the Sales Cloud environment(and I would say the entire
Fusion Suite) is constructed to.
So every piece of information you introduce in sales cloud will eventually end up as row in a
table from the oracle database.
Well in order for users of the application to retrieve and modify this information they are granted
access via what is called Application Job Roles.
This Application Job Roles are in turn constructed from multiple Duty Roles(or as they are also
called, Application Roles).
If we dig deeper the Application Roles are built by Functional Policies and Data securities
Functional Policies are the ones that provide access to things on the FUSE UI . So if you see Create
button or if you see Opportunity Icon on the dashboard, that is possible via Functional Policies.
The Data securities are the things via which uses can access the information contained in a
particular object. So when you see the records in Accounts(for example) that is due to Data Securities.
Now if we dig even Deeper at the core of a Data security are SQL Predicates
Note: This is a simplified view of the security model(in reality the security model is much more complex,
but this shows its essence)
5
As you can see the SQL Predicates are written at the level of the Database Resource.
To be mention here that from Release 12 onwards, seeded SQL Predicates can not be edited, to edit them
you have to create a new ones, copies of the seeded one.
But we will learn how to do that in the next chapters.
6
Also as you notice SQL Predicate is in essence simple SQL code, so to write SQL Predicate you have to
understand SQL Language.
I will not teach SQL in this document, if you do not know it here are some resources to help you out.
Tutorials Point: https://www.tutorialspoint.com/sql/
W3Schools.com : https://www.w3schools.com/SQL/deFault.asp
We will start simple, in the sense that we will be using a custom object to write our first SQL Predicate.
And this SQL Predicate will have to allow users to see only those records, from the custom object, that
they created.
Before we start making the SQL Predicate I have to mention that the application has out of the box few
SQL function we can use to retrieve information about to user logged in.
b) FND_GLOBAL.USER_NAME
- This will return user name of the user logged in
This 2 functions are quite useful when creating SQL Predicates, as you will see next.
So as I was saying, we want to create an SQL Predicate that will allow access on
those records created by the user logged in, on a custom object.
For this I have created in Application Composer a Custom object called
OSCSalesObj.
7
NOTE: When Writing SQL PRedicates on Custom Objects, those objects have to be in mainline!
SQL Predicates work only on mainline objects and attributes
When writing the SQL Predicate you have to use something like this:
&TABLE_ALIAS.COLUMN_NAME
This tells the system that the column you are referring to belongs to the object you are writing the SQL
Predicate for.
So back to our SQL Predicate, we want access to all records that login user created, for this we need an
field(attribute) from the object that stores creator name and the login user name.
Any custom object has an attribute, out of the box, that holds creator name and it is called Created By
and the column name of this attribute is created_by
Now we only need the username of the user logged in, and this we get using the second function I have
already mentioned, FND_GLOBAL.USER_NAME.
So now is time to put all together, as I said we need to make reference to the
object(table) via &TABLE_ALIAS.COLUMN_NAME and then use the function.
So the SQL Ppedicate that we need can be written as:
&TABLE_ALIAS.created_by = FND_GLOBAL.USER_NAME
Now that we have the code for the SQL Predicate we have to use it in the
application.
8
And as I was saying in the first chapter, we use the SQL Predicate on the database
resource which in this case is our custom object called OSCSalesObj.
For this you have to go to the security Console and select the last tab called
Administration
9
Next you search for the Object Name (Or Display Name) and you edit it
Once in Edit screen of the Object go to the Condition tab and create a new
condition
10
Now you give a meaningful name and description and you make the condition as
SQL Predicate and you put in the SQL Predicate box the predicate we made early
and save
Now the custom object has a new condition based on the SQL PRedicate we made.
But to give users access via this condition, we need to add it as a data security to
some role.
Since in Release 12 we can not edit out of the box roles, I will create a new CRM
Job Role specifically for this Custom object and assign it to a user I made for
testing.
11
My test user is called viorel.security and it has the standard roles you would find in a Sales
Representative.
Now I will Create a Job Role (In R12 you have to make CRM Job Role to see them under Object Security
in Application Composer).
Once you save and if you go back to the Security console and edit the Job Role, you will see functional
policies were added to the role and few grants(also related to functional policies)
14
Now if I assign this role to my test user, the user will be able to see the custom object but no records of
this object.
15
As you see I have logged in with my test user (viorel.security) and I can access the custom object landing
page, but I don’t see any records.
Remember when I said UI elements are given by Functional Policies and Data is given by Data Security.
This proves the point very well; user has the job role I previously created which only has functional
policies at this moment.
Next is time to create a data security and use the SQL Predicate created.
So Go to Security Console and Search the Job Role Created and Edit it
16
Now here you see some items, do not confuse it with data securities.
This are Functional stuff, I won’t go in details why are here, but the idea is if you see under Data Security
section conditions that are named functional, then those policies do not provide data access.
There is 1 data security and that is for Notes object, so that users can access and view notes on the custom
object. This was generated automatically by the system.
Now is time to make our data security, so click on Create Data security Policy button.
Name your policy, make it something suggestive so you know for what it is, I mill name mine
“ViewOwnRecords”.
Select Database resource, in my case is “OSCSalesObj” the API name of my object.
Set data set to “Select by instance set”.
On the Condition Name you should see the condition we previously created under the custom object.
I named mine “CreatedBy”.
And in actions you provide what kind of interaction the user should have with the object records, create
them, view them, update them, delete them.
I will provide all actions.
Start date, you should set it to the current date or a past date, so that Data Security is enabled.
And then click OK
17
Now you should see the new Data security in the list and you can go to Summary and Impact Report
section and save the role.
After you save the role, a good idea is to run the process “Import User and Role Application Security
Data” from Scheduled Processes to help the system refresh security changes.
Now if I log in with my test user viorel.security I should see only records created by this user only.
18
As you can see in the Custom object there are many more records, but due to the predicate viorel.security
can see only records created by himself.
Note: If you don't see any change after saving the role, have more patience give the system more time to refresh,
sometimes even by running the Import User and Role Application Security Data system needs more time to refresh.
Well congratulations are in order, you have just successfully created and implemented a custom
SQL Predicate.
In next lessons I will be showing how to make more complex predicates, but I will not show the entire
implementation flow.
You can always come back to this lesson to see how to make the roles and data securities, the
process is the same every time you want to make a new SQL Predicate.
19
And the user will set a resource in this DCL which will represent the Owner of the Custom Object
record.
Now the SQL predicate has to sort and show those records that match the Resource set in the
DCL with the User that is logged in.
So if Login user is X , this user should see only those records from the custom object that have
value X in the DCL.
The first step is to find out in which column, inside the database, the value of the DCL is stored.
In this KM you will find all the queries needed to get this information:
How To Extract The Information Needed From the Database on a Custom
Object (Doc ID 2242344.1)
The queries in the above document can be done in a BI Publisher data model as
below:
Go to Navigator > Reports and Analytics > Catalog(BI Publisher) > Create new
Data Model > Create new SQL Query
20
21
22
Ok, so coming back to our case here, once you make this Data Model you can
use the queries in the Km mentioned to get the needed information.
Specifically, you can this one of this 2 queries to find out the Column in which a
field is storing the value.
23
SQL Query 1
SELECT OBJECT_NAME AS OBJECT,OBJECT_ATTR_NAME AS ATRRIBUTE,OBJECT_ATTR_LEN AS
LENGTH,SUBSTR(OBJECT_ATTR_TYPE, - INSTR(REVERSE(OBJECT_ATTR_TYPE), '.') + 1) AS
DATA_TYPE,TXN_VO_ATTR_TABLE,TXN_VO_ATTR_COL
FROM FUSION.MKT_IMP_OBJECT_DETAILS D,FUSION.MKT_IMP_OBJECT_ATTRS A WHERE
D.OBJECT_DETAIL_ID=A.OBJECT_DETAIL_ID
AND A.OBJECT_ATTR_COL LIKE '%EXTN_ATTRIBUTE%' AND A.CREATED_BY != 'SEED_DATA_FROM_APPLICATION'
AND D.OBJECT_DETAIL_TABLE != 'MKT_IMP_JOBS' AND OBJECT_NAME LIKE '%<ObjectName>%'
Now typically this query works after you have generated artifacts.
However, if it happens you get no results, then you can use this SQL
SQL Query 2
select * from <DATABASE_OBJECT_NAME> where attribute_category ='<OBJ_NAME>'
Ok so now you know how to obtain all the information you need to create the SQL predicate.
In my own environment as mentioned above I have a custom object with API name : OSCSalesObj
Inside the custom object I have a DCL pointing to Resources, which represents Owner of the custom
record with API name: Owner_c
METHOD 1
As mentioned before, get the column from the database in which Owner_c is stored.
I make a Data Model and run the first query(SQL Query 1):
SELECT OBJECT_NAME AS OBJECT,OBJECT_ATTR_NAME AS ATRRIBUTE,OBJECT_ATTR_LEN AS
LENGTH,SUBSTR(OBJECT_ATTR_TYPE, - INSTR(REVERSE(OBJECT_ATTR_TYPE), '.') + 1) AS
DATA_TYPE,TXN_VO_ATTR_TABLE,TXN_VO_ATTR_COL
FROM FUSION.MKT_IMP_OBJECT_DETAILS D,FUSION.MKT_IMP_OBJECT_ATTRS A WHERE
D.OBJECT_DETAIL_ID=A.OBJECT_DETAIL_ID
AND A.OBJECT_ATTR_COL LIKE '%EXTN_ATTRIBUTE%' AND A.CREATED_BY != 'SEED_DATA_FROM_APPLICATION'
AND D.OBJECT_DETAIL_TABLE != 'MKT_IMP_JOBS' AND OBJECT_NAME LIKE '%OSCSalesObj%'
25
So as you can see Owner_c holds its value in the column called:
EXTN_ATTRIBUTE_NUMBER003
METHOD 2
But let’s presume that the query I ran above will return no results.
Then we make use of the second query I have mentioned at SQL Query 2.
For this query we need additional info so we ran in this order:
select *
from fusion.adf_extensible_table_usage
where ENTITYDEF_FULLNAME like '%OSCSalesObj%'
CONTEXT_COLUMN_VALUE (OSCSalesObj_c)
TABLE_ID (100000020154628)
Next we ran:
select TABLE_NAME from fusion.adf_extensible_table where TABLE_ID = 100000020154628
So now we have the custom object table as ZCA_REF_ENTITIES and attribute_category as OSCSalesObj_c
28
But, here is a bit tricky, if you don’t have any value in your DCl then you may not realize which of the
columns hold the value.
So what you can do is, go to UI put a value into that DCL, run the query to return just the record you
modified, then go back and remove the value from the DCL and run gain the query and observe which
column will get modified.
Notice I added additional condition to the query to search a specific custom record (RECORD_NAME=
'Test_3')
29
Ran again the query after setting the value and notice a column was populated, that’s the column holding
Owner_c values.
So that's 2 ways go get the needed information, other way we will get that the table of the custom object
is: ZCA_REF_ENTITIES and column for the Owner_c is EXTN_ATTRIBUTE_NUMBER003
Now we have the information from the Custom object side, but we now need to get the information from
the login user.
There is one thing that you need to know, when you have a DCL that points to Resource Object,
the Id of the resource is not Party Id, it is in fact Resource Profile Id.
Because the DCL will store the Primary Key of the Object to which it points to and the Resource
Object table is JTF_RS_RESOURCE_PROFILES which has as Primary key RESOURCE_PROFILE_ID.
http://docs.oracle.com/cloud/farel11/salescs_gs/OEDMS/JTF_RS_RESOURCE_PROFILES_tbl.htm
Problem now is how do we get the Resource Profile Id of the login user?
31
Well we make use of the application functions I already mentioned at chapter 2, specifically this function:
HZ_SESSION_UTIL.GET_USER_PARTYID
And we query the JTF_RS_RESOURCE_PROFILES table by the Party Id and we return the Resource
Profile Id,a s below:
SELECT RESOURCE_PROFILE_ID FROM JTF_RS_RESOURCE_PROFILES WHERE PARTY_ID =
HZ_SESSION_UTIL.GET_USER_PARTYID
Now we have the query that will return the resource profile id of the login user and is time to put
all the information together in making the SQL for the SQL predicate
And the SQL for the predicate look like this:
So that is the SQL for the Predicate, but it is not yet a SQL Predicate, to become one we need to add it
under the Database Resource for the Custom object with this format:
&TABLE_ALIAS.ID IN (
32
So now we can go to Security console and add the SQL Predicate a condition in the Custom object
Database Resource.
Steps how to do it already provided at chapter 2
You should end up with something like this in the end.
How to use this condition in a role is also explained at Chapter 2 so please refer to that section.
33
There are cases where in a custom object we have a Dynamic Choice List pointing to Account
Object.
The Account object, as you are well aware of has a child called sales team, which represents the
resources assigned to that account.
There could be a requirement to restrict visibility on the custom object, in such away that for a
user that is logged in, to see only those custom object records, in which he or she is member of the
account sales team, account that is associated via that Dynamic Choice List to the custom object record.
This is the case that we will treat in this chapter.
The first thing that needs to be done is to identify in which column from the database, is the
PartyId of the account associated with the custom object, stored.
And next is to identify which are the tables and columns where the account sales team are stored,
and how to retrieve that.
The Setup
Custom Object Name is: OSCSalesObj
Dynamic Choice List : Account_c
34
Requirement:
Show to log in user only those custom object records that are associated with an account and the user is in
that account sales team.
Step 1 - Get the column in which the account party id is stored in the database.
As you seen in previous chapter we will use BI Publisher and a data model to access the oracle
database.
And we will be using the same queries as before, to identify the table in which the custom object
is stored and then to find out the column where the Dynamic Choice List is held
As you already know there is a SQL query that can give us all the details needed in one go.
This is the Query:
Result is:
So we can see the attribute Account_Id_c (which is actually PatyId of the Account) is stored in column
called EXTN_ATTRIBUTE_NUMBER001 from the tables ZCA_REF_ENTITIES.
Note: If query does not return results, you method 2 from chapter 3 to get same information (page 26)
Step 3 - Find out in which tables and columns the Account Sales Team is stored
36
So what we need is to return the Party Id of the Account Team that matches the login user Party Id.
The Query is:
SELECT PARTY_ID
FROM ZCA_S_ACCT_RESOURCES acct_team,
ZCA_SALES_ACCOUNTS acct
WHERE acct_team.sales_account_id = acct.sales_account_id and acct_team.resource_id =
HZ_SESSION_UTIL.GET_USER_PARTYID
Notice we are using the function from Setp 2 , to find the matching account team member.
Step 4 - Put all together and get the final form of the SQL Predicate
So we have the Custom Object and DCL (Dynamy Choice List) Table and column, we also have the
account sales team info, we can build the SQL for the predicate as below:
SELECT ID
FROM ZCA_REF_ENTITIES
WHERE EXTN_ATTRIBUTE_NUMBER001 IN
(SELECT PARTY_ID
FROM ZCA_S_ACCT_RESOURCES acct_team,
ZCA_SALES_ACCOUNTS acct
WHERE acct_team.sales_account_id = acct.sales_account_id and acct_team.resource_id =
HZ_SESSION_UTIL.GET_USER_PARTYID)
But because we are going to use it as a SQL Predicate then we have to write the code, by adding
TABLE_ALIAS, so that system know we are working in the context of the custom object.
37
&TABLE_ALIAS.ID IN (
SELECT ID
FROM ZCA_REF_ENTITIES
WHERE EXTN_ATTRIBUTE_NUMBER001 IN
(SELECT PARTY_ID
FROM ZCA_S_ACCT_RESOURCES acct_team,
ZCA_SALES_ACCOUNTS acct
WHERE acct_team.sales_account_id = acct.sales_account_id and acct_team.resource_id =
HZ_SESSION_UTIL.GET_USER_PARTYID))
&TABLE_ALIAS.EXTN_ATTRIBUTE_NUMBER001 IN
(SELECT PARTY_ID
FROM ZCA_S_ACCT_RESOURCES acct_team,
ZCA_SALES_ACCOUNTS acct
WHERE acct_team.sales_account_id = acct.sales_account_id and acct_team.resource_id =
HZ_SESSION_UTIL.GET_USER_PARTYID))
Now you we can use it to make the condition on the database resource and create our data security policy.
Already shown how to do all this in chapter 2.
38
Opportunity
Resource
For example the login user in this case is Campbell,Scott and for him the value of the FCL in
resource Directory is “BB”.
So for him the SQL predicate should show all opportunities in which he is in the team and also
the opportunities have to have in their FCL field also “BB”
As before first thing is to identify in which columns from MOO_OPTY and from
JTF_RS_RESOURCE_PROFILES the value of FCL field is stored.
For this we make a Data Model in BI Publisher using the SQL already presented in the early
chapters.
SELECT OBJECT_NAME AS OBJECT,OBJECT_ATTR_NAME AS ATRRIBUTE,OBJECT_ATTR_LEN AS
LENGTH,SUBSTR(OBJECT_ATTR_TYPE, - INSTR(REVERSE(OBJECT_ATTR_TYPE), '.') + 1) AS
DATA_TYPE,TXN_VO_ATTR_TABLE,TXN_VO_ATTR_COL
FROM FUSION.MKT_IMP_OBJECT_DETAILS D,FUSION.MKT_IMP_OBJECT_ATTRS A WHERE
D.OBJECT_DETAIL_ID=A.OBJECT_DETAIL_ID
AND A.OBJECT_ATTR_COL LIKE '%EXTN_ATTRIBUTE%' AND A.CREATED_BY !=
'SEED_DATA_FROM_APPLICATION' AND D.OBJECT_DETAIL_TABLE != 'MKT_IMP_JOBS' AND OBJECT_NAME LIKE
'%Opportunity%'
Now what is left is to build the SQL to return all opportunities that have same value in FCL as in resource Directory
FCL and login user is in the sales team.
SELECT OPTY.OPTY_ID
FROM MOO_OPTY OPTY INNER JOIN MOO_OPTY_RESOURCES RES
ON (OPTY.OPTY_ID = RES.OPTY_ID ) INNER JOIN JTF_RS_RESOURCE_PROFILES R ON (RES.RESOURCE_ID =
R.PARTY_ID)
WHERE RES.RESOURCE_ID = HZ_SESSION_UTIL.GET_USER_PARTYID AND OPTY.EXTN_ATTRIBUTE_CHAR041 =
R.EXTN_ATTRIBUTE_CHAR009
Next is to make this SQL into a SQL Predicate, by adding &TABLE_ALIAS.OPTY_ID, as below:
&TABLE_ALIAS.OPTY_ID IN (
SELECT OPTY.OPTY_ID
FROM MOO_OPTY OPTY INNER JOIN MOO_OPTY_RESOURCES RES
ON (OPTY.OPTY_ID = RES.OPTY_ID ) INNER JOIN JTF_RS_RESOURCE_PROFILES R ON (RES.RESOURCE_ID =
R.PARTY_ID)
WHERE RES.RESOURCE_ID = HZ_SESSION_UTIL.GET_USER_PARTYID AND OPTY.EXTN_ATTRIBUTE_CHAR041 =
R.EXTN_ATTRIBUTE_CHAR009
)
41
Now all is left is to go to Manage Database Resources , open the Opportunity resource and add a new
Condition having this SQL Predicate
After this is done, the condition newly created can be used to create custom Data Securities.
And with this final example we conclude the tutorial on creation of SQL Predicates.
All other SQL predicates follow the same pattern, all that is needed is knowledge of SQL and of
course knowledge of the tables in Oracle Sales Cloud.