Changing a DB View dynamically according the current user-group - postgresql

we are currently digging into Amazon Redshift and testing different functionalities.
One of our basic requirements is that we will define different user groups which in turn will be granted access to different views.
One way to go about this would be to implement one view seperately for each user-group. However, since we have a lot of user-groups that share almost the exact same need for information, I'm looking for a way to implement this more dynamically in Redshift.
For instance, let's say I have a user group called users_london and another one called users_berlin. Both will have access to a view called v_employee_master_data which contains the columns employee_name, employee_job_title and employee_city.
Both groups share the same scope of information with one exception - the column employee_city.
In essence, the view should be pre-filtered for a certain value in the column employee_city according to the currently logged-in user-group.
In SQL - something like this:
For the usergroup users_london:
SELECT * FROM v_employee_master_data WHERE employee_city = 'London';
For the usergroup users_berlin:
SELECT * FROM v_employee_master_data WHERE employee_city = 'Berlin';
Now to make the connection back to Amazon Redshift. Does the underlying DB runtime provide an out-of-the-box functionality to somehow catch the currently logged user-group as a form of global variable and alter the SQL-statement according to the value of that variable?

It is possible to do:
get current user
select current_user
find what group it belongs to
select groname from pg_group where current_user_id = any(grolist);
Extract city and capitalize it:
select initcap(substring(groname from 'users_(.*)')) from pg_group where current_user_id = any(grolist);
Now you have your city based on the "user". So just inject it in the view
... WHERE employee_city = initcap(substring(groname from 'users_(.*)') ...

Related

How to create a parameter and use inside a custom sql query in Tableau

I have a list of countries.
I need to create a parameter that can be used inside a custom sql.
For Eg:
List of countries
Argentina,Brazil,Colombia,Ecuador...
The requirement is
User should be able to select multiple countries
Based on that selection, need to run a custom sql that uses SQL IN query or multiple OR.
If user select Argentina and Brazil
Custom sql will be like
select * from players where countries in ('Argentina','Brazil)'
I tried with Set and Filters. But how can I create a parameter based on the selection of filters/Sets?
Parameters are single select only. So in your scenario it is not possible. You could create multiple parameters but that would mean the user would need to pick a country for each otherwise your query would not work. Here are instructions for creating and using parameters in custom sql. https://help.tableau.com/current/pro/desktop/en-us/customsql.htm#use-parameters-in-a-custom-sql-query

How to execute graphql query for a specific schema in hasura?

As it can be seen in the following screenshot, the current project database (postgresql)
named default has these 4 schema - public, appcompany1, appcompany2 and appcompany3.
They share some common tables. Right now, when I want to fetch data for customers, I write a query like this:
query getCustomerList {
customer {
customer_id
...
...
}
}
And it fetches the required data from public schema.
But according to the requirements, depending on user interactions in front-end, that query will be executed for appcompanyN (N=1,2,3,..., any positive integer). How do I achieve this goal?
NOTE: Whenever the user creates a new company, a new schema is created for that company. So the total number of schema is not limited to 4.
I suspect that you see a problem where it does not exists actually.
Everything is much simpler than maybe it seems.
A. Where all those tables?
There are a lot of schemas with identical (or almost identical) objects inside them.
All tables are registered in hasura.
Hasura can't register different tables with the same name, so by default names will be [schema_name]_[table_name] (except for public)
So table customer will be registered as:
customer (from public)
appcompany1_customer
appcompany2_customer
appcompany3_customer
It's possible to customize entity name in GraphQL-schema with "Custom GraphQL Root Fields".
B. The problem
But according to the requirements, depending on user interactions in front-end, that query will be executed for appcompanyN (N=1,2,3,..., any positive integer). How do I achieve this goal?
There are identical objects that differs only with prefixes with schema name.
So solutions are trivial
1. Dynamic GraphQL query
Application stores templates of GraphQL-queries and replaces prefix with real schema name before request.
E.g.
query getCustomerList{
[schema]_customer{
}
}
substitute [schema] with appcompany1, appcompany2, appcompanyZ and execute.
2. SQL view for all data
If tables are 100% identical then it's possible to create an sql view as:
CREATE VIEW ALL_CUSTOMERS
AS
SELECT 'public' as schema,* FROM public.customer
UNION ALL
SELECT 'appcompany1' as schema,* FROM appcompany1.customer
UNION ALL
SELECT 'appcompany2' as schema,* FROM appcompany2.customer
UNION ALL
....
SELECT `appcompanyZ',* FROM appcompanyZ.customer
This way: no need for dynamic query, no need to register all objects in all schemas.
You need only to register view with combined data and use one query
query{
query getCustomerList($schema: string) {
all_customer(where: {schema: {_eq: $schema}}){
customer_id
}
}
About both solutions: it's hard to call them elegant.
I myself dislike them both ;)
So decide yourself which is more suitable in your case.

PostgreSQL 9.5 Update virtual column in view

I am using PostgreSQL for GIS purposes with PostGIS and QGIS, but I think I might find more informations here than on gis.stackexchange.com since my question is not directly GIS related.
I am using views to diplay datas at will for the specific needs of my users, like that they have access to the datas as they are in the DB, but with just what they need. I added some rules to my views to make them "updatable" in QGIS and make them directly "workable" by the users.
Display in QGIS is based on attributes, but since there is the possibility that different persons will access the same data at the same moment, and they might want to display and hide some of these datas according to their needs (map printing for once). So I am looking for a way to give possibility to have a specific display for each view, and I thought about simply adding a "virtual" column in the view definition, with for example a boolean like such:
CREATE VIEW view1 AS
SELECT oid, column1, True as display from table1;
But I would like my users to be able to change the value of this column, to simply make appear or disappear the objects from the canvas (with a ruled-base styling considering this parameter). And obviously it doesn't work direclty since the update would be in conflict with the definition of the view.
Does anyone have any idea on how to achieve that? Maybe a materialized view (but I quite like the dynamics of the regular view)?
Thanks.
If the unique ID field is read from the table (i.e. it is not dynamically created via the row_number() trick commonly used with spatial views in QGIS), you could create a visibility manager table and use it in the view. You could have one table by view or one for all of them. Something similar to:
create table visibility_manager (oid bigint, visibility_status boolean, viewname text);
CREATE VIEW view1 AS
SELECT table1.oid, column1, coalesce(visibility_status,true) as display
from table1
left outer join visibility_manager
on (table1.oid = visibility_manager.oid and visibility_manager.viewname = 'view1');
see it in action:
http://rextester.com/OZPN1777

I would like to use a parameter for the table name. The table names can be presented to the user from a database view.

I would like to use a parameter for the table name. I have an application that creates several new tables each month. I therefore need the table name to be sent into CR via a parameter. The fields for the tabkes are always identical. I can present a list (view) from the database to the end user that would display a user friendly name for the table, when the user selects the instance they want I then have the table name I want to report from.
I'm not sure if that is possible. Even if your tables have the same structure, the field names will ultimately be different. Let's say you have a {table1.field1} in your report. Now you want to run the report from table2 instead of table1. So your field now would have to become {table2.field1}. Does that make sense? I think a better approach might be to try stored procedures that will create the fields you need so the field names won't change.

In SQL Server 2008R2 can I force a View to use objects within the user's default schema instead of the schema in which the View exists?

A bit of background. I have a base application and most clients use it as standard. However some clients have small code and database customisations.
Each of these clients has their own branch and maintenance can be tricky.
I want to consolidate all these into a single database structure (not a single database - we aren't doing multi-tenancy) to enable upgrades to be applied in a much more uniform fashion.
I'm still at the proof of concept stage, but the route I was going down would be to have the standard objects stay in the schema they currently exist in (mostly dbo) and have the custom objects reside in a schema for each client.
For example, I could have dbo.users and client1.users which has some additional columns. If I set the default schema for the client to be "client1" then the following query
SELECT * FROM users
will return data from the client1 schema or the dbo schema depending on which login is connected.
This is absolutely perfect for what I'm trying to achieve.
The problem I'm running into is with Views.
I have many views which are in the dbo schema and refer to the Users table. No matter which user I connect to the database as, these views always select from dbo.users.
So I'm guessing the question I have is:
Can I prefix the tables in the view with some variable like "DEFAULT"? e.g.
SELECT u.username, u.email, a.level
FROM DEFAULT.users u INNER JOIN accessLevels a ON u.accessID = a.accessID
If this isn't possible and I'm totally barking up the wrong tree, do you have any suggestions as to how I can achieve what I'm setting out to do?
Many thanks.
Just reference the name of the schema in which the views reside...
Select a., b.
from schema1.TABLEA A
join schema2.TABLEB B on A.ID = B.ID