I have an hierarchy Table which I try to add in QlikView in order to use RESTRICTION (Section Access) on users to show/hide data.
On the Table, I have the user REFERENCE, with an ID which is linked to an IDPARENT in order to have an hierarchy.
I want that all the user "on top" of the leaf user (the last one in the hierarchy) could have access on his data.
In order to do this, I use this SQL query :
Select
REFERENCE,
LEVEL-1 "LEVEL",
from HIERARCHYTABLE
start with TYPE='VD' //Start hierarchy with all the users with type='VD'
connect by ID = prior IDPARENT;
It return :
VD254 0
IG203 1
GR203 2
VD255 0
IG232 1
GR258 2
IG235 1
GR259 2
-> So IG203 and GR203 can access to the VD254 data
And IG232, GR258, IG235 and GR259 can access to the VD255
With that, I have all my REFERENCE associated to the LEVEL (Here the user on the bottom is the level "0").
I want my AUTHENTIFICATE table to be like :
ACCESS, REFERENCE, PASSWORD, RESTRICTION
ADMIN, ADMIN, ADMIN, *
USER, VD254, VD254, VD254
USER, VD254, VD254, VD255 // Here the user VD254 can access to his data and the VD255 user data
So I was thinking of that when I have a 0 LEVEL, all the next users would have the REFERENCE of the 0 level in RESTRICTION until the loop see another 0 LEVEL :
But I can't make it works :
. The IterNo() is alway at '0' so the IF condition is alway true with the wrong value !
. It add an infinite number of rows to AUTH, so LEVEL <> '0' is never true...
AUTHRESIDENT:
LOAD
REFERENCE,
LEVEL,
Select
REFERENCE,
LEVEL-1 "LEVEL",
from HIERARCHYTABLE
start with TYPE='VD' //Start hierarchy with all the users with type='VD'
connect by ID = prior IDPARENT;
Let vRowCount = NoOfRows('AUTHRESIDENT');
DO WHILE (IterNo() <> vRowCount)
IF peek('LEVEL', IterNo(), 'AUTHRESIDENT')='0' THEN
Let vNumVd = peek('REFERENCE', IterNo(), 'AUTHRESIDENT');
AUTH:
LOAD
'USER' as ACCESS,
'00211' as REFERENCE, // Only to test
'00211' as PASSWORD,
$(vNumVd) as RESTRICTION
RESIDENT AUTHRESIDENT
WHILE LEVEL <> '0';
ENDIF;
LOOP;
Thank you a lot for your help !
I finally found the solution with the unbalanced hierarchy, here is my code for people in the same case :
HIERARCHY:
HierarchyBelongsTo(IDNOEUD, IDNOEUDPARENT, REFERENCE, TreeID, TreeName)
LOAD
REFERENCE,
IDNOEUD,
IDNOEUDPARENT,
Select
REFERENCE,
IDNOEUD,
IDNOEUDPARENT,
from HIERARCHYTABLE;
Trees:
LOAD
*,
Upper(TreeName) as PERMISSION,
REFERENCE as MYPERMISSIONFIELD // Field which is the filter
Resident HIERARCHY;
Drop Table HIERARCHY;
Section Access;
AUTH:
LOAD * INLINE [
ACCESS, USERID, PASSWORD, PERMISSION
ADMIN, ADMIN, ADMIN, * // To add the ADMIN !
];
AUTH:
LOAD
'USER' as ACCESS,
REFERENCE as USERID,
REFERENCE as PASSWORD,
UPPER(REFERENCE) as PERMISSION;
SELECT
REFERENCE
FROM HIERARCHYTABLE;
Section Application;
Then the PERMISSION is linked to all the MYPERMISSIONFIELD.
Related
I have 2 tables contractPoint and contractPointHistory
ContractPointHistory
ContractPoint
I would like to get contractPoint where point will be subtracted by pointChange. For example: ContractPoint -> id: 3, point: 5
ContractPointHistory has contractPointId: 3 and pointChange: -5. So after manipulating point in contractPoint should be 0
I wrote this code, but it works just for getRawMany(), not for getMany()
const contractPoints = await getRepository(ContractPoint).createQueryBuilder('contractPoint')
.addSelect('"contractPoint".point + COALESCE((SELECT SUM(cpHistory.point_change) FROM contract_point_history AS cpHistory WHERE cpHistory.contract_point_id = contractPoint.id), 0) AS points')
.andWhere('EXTRACT(YEAR FROM contractPoint.validFrom) = :year', { year })
.andWhere('contractPoint.contractId = :contractId', { contractId })
.orderBy('contractPoint.grantedAt', OrderByDirection.Desc)
.getMany();
The method getMany can be used to select all attributes of an entity. However, if one wants to select some specific attributes of an entity then one needs to use getRawMany.
As per the documentation -
There are two types of results you can get using select query builder:
entities or raw results. Most of the time, you need to select real
entities from your database, for example, users. For this purpose, you
use getOne and getMany. But sometimes you need to select some specific
data, let's say the sum of all user photos. This data is not an
entity, it's called raw data. To get raw data, you use getRawOne and
getRawMany
From this, we can conclude that the query which you want to generate can not be made using getMany method.
In my rails app, I have Users and Listings. The Listings belong to a User. Listing has user_id and its filled with users id who is creating the listing.
A user can be a premium user, gold user or silver user.
What I want is for each premium user, select one random listing to show in premium listings.
I can do it in O(n**2) time or n+1 query as follow:
users_id = User.where(:role => "premium").pluck[:id]
final_array = Array.new
users_id.each do |id|
final_array << Listing.where(:user_id => id).sample(1)
end
final_array
Is there a better way of doing this?
You could try this:
listings = Listing.select(
<<~SQL
DISTINCT ON (users.id) users.id,
listings.*,
row_number() OVER (PARTITION BY users.id ORDER BY random())
SQL
)
.joins(:user)
.includes(:user)
.where(users: { role: :premium })
It gives a random Listing for every premium user.
It produces the only request to db and also it won't make an extra request for getting listing's user, so you are free to do something like this:
listings.each do |listing|
p listing.user
end
random_user_listings = []
User.includes(:listings).where(role: "premium").find_each do |user|
random_user_listings << user.listings.sample(1)
end
random_user_listings
To avoid N+1 query you need to combine them, perform query one time like this:
list = Listing.includes(:user).where(:role => "premium").sample(1)
Feel free to deal with list instead of Listing. Because now you're dealing with variable, not Query.
ids = list.pluck(:user_id).uniq
Getting array of ids like above and doing further steps as you did (but with list, not Listing)
Need to be noticed that, when you deal with Model you're dealing with QUERY. Avoiding doing that in loop statement.
I'm somewhat of a SFDC novice when it comes to integration, but is there any way I can query just the contacts shared with a given user, taking into account all the ways the share can occur? Essentially just see the same contacts the user would see in within the platform?
I think this is what you are looking for. I added some inline comments to explain what each step is doing. The end result should be all the contacts that can be read by a specified user in your org.
// add a set with all the contact ids in your org
List<contact> contacts = new List<contact>([Select id from Contact]);
Set<ID> contactids = new Set<ID>();
for(Contact c : contacts)
contactids.add(c.id);
// using the user record access you can query all the recordsids and the level of access for a specified user
List<UserRecordAccess> ura = new List<UserRecordAccess>([SELECT RecordId, HasReadAccess, HasTransferAccess, MaxAccessLevel
FROM UserRecordAccess
WHERE UserId = 'theuserid'
AND RecordId in: contactids
] );
// unfortunatelly you cannot agregate your query on hasReadAccess=true so you'd need to add this step
Set<id> readaccessID = new Set<ID>();
for(UserRecordAccess ur : ura)
{
if(ur.HasReadAccess==true)
{
readaccessID.add(ur.RecordID);
}
}
// This is the list of all the Contacts that can be read by the specified user
List<Contact> readAccessContact = new List<Contact>([Select id, name from contact where id in: readaccessID]);
// show the results
system.debug( readAccessContact);
I have a scenario as shown below ,
I want to query the database so I get the following result,
User Resource Permissions
Edi Plan A [view]
Where
resource.name = 'Plan A' and user.name = 'Edi'
my query for above is
SELECT name,
out('hasARole').out('ofType').in('isOfType')[name = 'Plan A'].name,
set(out('hasARole').out('hasA').name) as permission
FROM user
WHERE name = 'Edi'
It should display
User Resource Permissions
Adrian Plan A [view,edit, delete]
if I change it to,
Where
resource.name = 'Plan A' and user.name = 'Adrian'
my query for above is
SELECT name,
out('hasARole').out('ofType').in('isOfType')[name = 'Plan A'].name,
set(out('hasARole').out('hasA').name) as permission
FROM user
WHERE name = 'Adrian'
Now above queries work as long as the users don't have another role on another type of resource. e.g. if Edi had Admin role on let's say a resource type of Workspace then the query gives me back all the permissions that an Admin would have , instead of just view as he only has view permission on Plan A
I have used the following graph for my answer. Note that I have corrected some incositencies with your original edges.
I see a number of possible queries for this problem. I am a bit confused why you would want to return the User and Resource in the query, as you probably already have these records due to the fact you use them to create the query. You can't 'nest' the full records in the results either (unless you JSON them). Further to this, querying on the name field, and returning only the name field seem a little nonsensical to me - but maybe you have done so to simplify the question. Regardless, the following queries will get you on your way to your desired results.
My first idea is to run a query to get all of the Roles related to a Resource. We then run a query over these results to filter for the Roles that include the User. This looks like the following;
select from (
select expand(out('isOfType').in('ofType')) from Resource where name = "Plan A"
) where in('hasARole') contains first((select from User where name = "Edi"))
This query correctly returns just the Viewer record for both Edi and Adrian.
My second idea is to run 1 query for the Roles related to a Resource (similar to above), and another for the Roles related to a User, and then find the intersect. This looks like the following, and gives the same results as the query above;
select expand(intersect) from (
select intersect($resource_roles, $user_roles)
let
$resource_roles = (select expand(out('isOfType').in('ofType')) from Resource where name = "Plan A"),
$user_roles = (select expand(out('hasARole')) from User where name = "Edi")
)
Now if you really do want the User, Resource and Permissions all in the 1 result, you can use the following, or a variant of;
select first($user).name as User, first($resource).name as Resource, intersect(resource_roles, user_roles).name as Permissions from (
select $resource.out('isOfType').in('ofType') as resource_roles, $user.out('hasARole') as user_roles
let
$resource = (select from Resource where name = "Plan A"),
$user = (select from User where name = "Edi")
)
or
select first($user).name as User, first($resource).name as Resource, intersect($resource_roles, $user_roles).name as Permissions
let
$resource = (select from Resource where name = "Plan A"),
$resource_roles = (select expand(out('isOfType').in('ofType')) from $parent.$resource),
$user = (select from User where name = "Edi"),
$user_roles = (select expand(out('hasARole')) from $parent.$user)
I have some problems with this fql.query method:
select music
from user
where uid = ......
and music in (select music
from user
where uid = ......
)
I want to obtain common music interest between two users; it works with queries like this
select uid
from user
where uid = ......
and uid in (select uid
from user
where uid = ......
)
I think the problem is that the second query returns an integer and the first one returns a string array. Can anyone help me with this?
(Excuse my bad English! I'm from Spain ;) )
Does not the first query already gives you your answer?
I mean it does the following :
-- Display only music field
select music
from user
where uid = <first_USER> -- Selection of your first user
and music in ( -- We want to macth the string with another
select music -- Selects only the music field
from user
where uid = <second_USER> -- Selection of your second user
)
So you gets a music name that match in two user records.
Your second query seems a bit odd to me :
select uid
from user
where uid = <first_USER?>
and uid in (select uid
from user
where uid = <second_USER?>
)
Which basically translates to find the user_id matching user one and user two. Thing that does never happen since each user has it's own uid.
By the way, I don't know how facebook handles music string, but it may appear that user don't write their favorite music name in a common spelling and/or format. That may impede your matching system.
I tried this:
select music
from user
where uid=UID1
AND music IN (SELECT music from user where uid=UID2)
And it works fine when the UID1 music string matches exactly the UID2's one.