PostgreSQL 9.5 Update virtual column in view - postgresql

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

Related

How do I generate a list of views dependent on a certain table in postgresql?

I need to update a mapping table in postgresql, but of course it won't allow me to replace/drop the original table as there are dependencies.
The error message details does list the dependent views, but I'd like to generate a list programmatically so that I can make temp views while I drop my original mapping table and migrate the views back afterwards.
Prefer not to do this in SQL Shell incidentally. Any pointers would be much appreciated.

Error on create view with cast numeric as decimal on postgresql

Good morning everyone!
I currently work with postgresql. Well, I need to create views where the numeric columns stay rounded 15.3 but I'm encountering a problem I could not understand.
The select work:
select cast(15.2547 as decimal(15,3)) as quantidade_medida_estatistica
The view not working:
create or replace view teste as select cast(15.2547 as decimal(15,3)) as quantidade_medida_estatistica
Error:
ERROR: can not change the data type of column view "quantidade_medida_estatistica" of numeric (15,4) to numeric (15,3)
Thanks!
This is a known "bug" in Postgres, which you can read about here.
CREATE OR REPLACE VIEW is not exactly the same as dropping the view and re-creating it. In this case the existing columns in the view need to be the same, as described in the documentation:
CREATE OR REPLACE VIEW is similar, but if a view of the same name
already exists, it is replaced. The new query must generate the same
columns that were generated by the existing view query (that is, the
same column names in the same order and with the same data types), but
it may add additional columns to the end of the list. The calculations
giving rise to the output columns may be completely different.
You can do what you want by dropping and re-creating the view.
You didn't explicitly state that, but I guess the view already exists - at least the error message indicates that.
Unfortunately you can't change the data types of the columns of an existing view when using create or replace.
You need to drop and create the view:
drop view teste;
create view teste
as
select cast(15.2547 as decimal(15,3)) as quantidade_medida_estatistica;

Changing a DB View dynamically according the current user-group

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_(.*)') ...

Any difference between result set from a view vs a physical table?

I am dealing with a software vendor who insisted that view is behaving differently from a physical table. The system is having error and they blame us for using view than the physical table.
Is this true? I'm using SQL2008R2. It will be helpful also if there is a strong reference to proof it. Thank you.
It might be behaving differently if the view makes an aggregation or if the view combines several tables or does anything else apart from just showing the original table.
If your view is created as
create view my_view as select * from my_table
there is no difference in behaiviour or data
But if your view is created for example as
create view my_view as select * from my_table inner join other_table on ...
there might be differences because of potencial data loose in the join.
Hope it helps.
The bytes returned to the application are the same irrespective of what internal structure SQL Server used to obtain them.

How to call function within a view

I'd like call function within a view to resolve virtual column. Calculating depends on data in actual row and did not want to multiple times selecting a data. Is this correct?? And like bonus, is possible call function within a call another?
CREATE VIEW my_view AS SELECT c.column1,c.columns2,... my_function(c) FROM my_table c
CREATE VIEW my_view AS SELECT c.money, c.quantity,... my_ratio_function(c.money,c.quantity,select sum_all_pays(my_view)) FROM my_table c
note. I'm put here because when looked for, cannot find that. If you have any other ideas, put it. Second one command not sure if is correct.
It is fine to use functions in the view definition. The only constraint — you should always give an explicit name to the column that is actually a function call, otherwise PostgreSQL doesn't know how to present a view definition.
Still, you cannot reference the view from inside the view. Instead, you might create 2 views, then you can reference the inside one from the outside view. Another approach is to use the WITH construct, which I find very handy and do use a lot.
Please note, that view is just a server-stored SQL and functions will be called for each row each time you will be querying the view. To get some performance improvements you might want to define your functions either as IMMUTABLE or as STABLE.
And I do agree with Frank — go ahead and test your views.