Postgres create view as not a view - sql

Maintaining code from a former employee found a piece of SQL i cannot understand:
CREATE OR REPLACE VIEW my_view AS Not a view
There's no info on official documentation and I've beenseeking for information on this query but to no avail.
any hint?

The view was deleted.
Your script was generated by an application which uses pg_get_viewdef(view_oid). When there is no a view with a given oid then the function returns the string not a view. Simple test:
create view my_view as select 1;
select oid
from pg_class
where relname = 'my_view';
oid
--------
151388
(1 row)
select pg_get_viewdef(151388);
pg_get_viewdef
----------------
SELECT 1;
(1 row)
drop view my_view;
select pg_get_viewdef(151388);
pg_get_viewdef
----------------
Not a view
(1 row)
Note that it does not mean that my_view does not exist. If you recreate the view it'll have another oid. The only certain conclusion is that your script is not up-to-date (It's inconsistent with the current content of the database). As a remedy you should dump the schema in SQL format, e.g.
pg_dump --schema-only --format=plain my_database > my_database.dump

Related

Create a view with uuid_generate_v4()

I have a problem and have no idea how to solve it.
I need to create a view (let's name it "revision") from another view which updates very frequently.
In my view "revision", I have all the columns from another view table + a unique id for that I use uuid_generate_v4().
CREATE VIEW test_view AS
(
SELECT uuid_generate_v4() AS gid, fw.*
FROM First_view fw
);
The view itself looks ok, however, my problem is that I need to have stable gid as I am going to use my view to populate another table and I need to use gid as a reference so I need stable ids, but as view always runs the query, every time it generates a new gid.
I was thinking about creating a new rule but was not able to figure out how it can help.
What should I do to avoid this problem? Is there at all any solution to overcome this problem?
Thanks
Mani
If the table is static, you might wanna use a MATERIALIZED VIEW. It will ensure that the values remain unchanged until you run a REFRESH, e.g.
CREATE MATERIALIZED VIEW test_view AS
SELECT uuid_generate_v4() AS gid, 'foo';
SELECT * FROM test_view;
gid | ?column?
--------------------------------------+----------
5a789003-dd0e-4aa0-a324-890cb7adf007 | foo
(1 Zeile)
SELECT * FROM test_view;
gid | ?column?
--------------------------------------+----------
5a789003-dd0e-4aa0-a324-890cb7adf007 | foo
(1 Zeile)

Mapped relation in postgresql

I have been playing with postgresql for a while now and this one caught my eye. What is a "mapped relation" in postgresql. According to the documentation,
When the name of on-disk file is zero, it is called a "mapped"
relation whose disk file name is determined by low - level state.
Is it a simple relation that doesnt have a fixed OID to reference it with. Why is it created? What is its significance?Or is it similar to a temp table?
can some one thow light on this?
https://www.postgresql.org/docs/current/static/storage-file-layout.html
Also, for certain system catalogs including pg_class itself,
pg_class.relfilenode contains zero. The actual filenode number of
these catalogs is stored in a lower-level data structure, and can be
obtained using the pg_relation_filenode() function.
t=# select relfilenode from pg_class where relname = 'pg_class';
relfilenode
-------------
0
(1 row)
t=# select pg_relation_filenode('pg_class');
pg_relation_filenode
----------------------
12712
(1 row)
now a little barbarian (yet user friendly) way to make sure it is the file:
t=# create table very_special_name(i int);
CREATE TABLE
t=# CHECKPOINT; --to actually write to disk
CHECKPOINT
t=# select oid from pg_database where datname='t';
oid
----------
13805223
(1 row)
so we check the readable strings:
-bash-4.2$ strings /pg/data/base/13805223/12712 | grep very_special
very_special_name
New table name is in...

Refresh view in HSQL

I would like to update a view in HSQL without writing the same statement again and again.
I have a table CONTACTS with ID, First_NAME and LAST_NAME. I also have a VIEW for this table, which I created with
CREATE VIEW IDGREATERTHREE AS SELECT * FROM CONTACTS WHERE ID > 3;
How can I update my VIEW after I added a new column to my table. I want to update my table without anything like this:
ALTER VIEW IDGREATERTHREE AS SELECT * FROM CONTACTS WHERE ID > 3;
I would like to find a way to refresh my invalid view in a similar way like in Oracle:
ALTER VIEW IDGREATERTHREE COMPILE;
I am also looking for a way to select just the invalid views. WithSELECT * FROM INFORMATION_SCHEMA.VIEWS I am not able to see any difference between an invalid and a non-invalid view.
A solution for this would be to write an ON DDL trigger.
In this ON DDL trigger , you check if your modifying your table.
If this is the case, then you use Dynamic SQL to recreate your view. This is doable with plsql (you tagged with oracle). There is ample documentation on creating triggers and dynamic SQL on the Internet.
HSQLDB cannot have invalid views. When you create a view, the SELECT * FROM CONTACTS is expanded to the actual column names. When you add a column to the table the view is recompiled with the original column names and the new column is not included.

Not able to re-create materialized view on prebuilt table

Steps I am trying to execute:
CREATE TABLE sample.MV(application_mode varchar2(25));
CREATE MATERIALIZED VIEW sample.MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM sample.tbl_name
WHERE cnt > 0;
When any other user is trying to drop and re-create the MV
DROP MATERIALIZED VIEW sample.MV;
CREATE MATERIALIZED VIEW sample.MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM sample.tbl_name
WHERE cnt > 0;
He gets below error while re-creation:
ORA-32334: cannot create prebuilt materialized view on a table already
referenced by a MV
why is so?
User got a work around for the same which is to drop the table first
and then recreate the table, recreate the MV.
Really weird behaviour of oracle is that all the subsequent attempts of that user of dropping and re-creating MV work well with no error.
update 2: it really is connected to some other mview which directly or indirectly uses/used this one. (as suggested by #Marmite Bomber, but his all_snapshots based query does not help)
You can find it out with user_dependencies (or maybe all_dependencies) using something like the following query. You may have to follow some dependency graph over synonyms, views, functions etc. to find the connection.
(In my case I knew that there had been a dependency before dropping the matview with preserve table. So this table is still "somehow connected" to some depending "higher" matview and thus the error seems to be issued.)
select * from user_dependencies
where 1=1 -- for easier comment filter usage below
--and referenced_owner=user -- if only current user relevant
--and not type in ('TRIGGER') -- e.g. to skip some auto-gen. triggers
and referenced_name = '<my matview>'
order by name, referenced_name
So a working solution was to also drop the "higher"/depending mview(s) (e.g. with the preserve table option) and recreate them (e.g. with the prebuilt table option so there is no rebuilt necessary).
Previous/old findings/workarounds:
I had the same problem where I automatically "renamed" some materialized views, which is programatically not possible (11.2).
So I created new matviews from old ones
deleting them, but not the table data (preserve table) and
reassociating the existing table with the new ones (prebuilt table).
Everything worked fine but for one matview that caused this ORA-32334 :-(
Debugging with the following SQLs did not give a clue why the system thinks this table is still associated with some matview so I can only assume it is a bug with some kind of random behaviour:
select * from user_mviews
select * from user_objects
where object_name like '%<some meaningful filter criteria>%'
order by object_type, object_name
My workaround: recreating the specific mview from scratch.
The problem with ORA-32334 is that you have nested materialized views.
A possible scenario is as follows - your materialized view MV is referenced by other materialized view MV2
create table mv as
SELECT max(application_mode) application_mode
FROM tbl_name
WHERE cnt > 0
GROUP BY modes;
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
create MATERIALIZED VIEW MV2
REFRESH FORCE ON DEMAND
AS
SELECT *
FROM MV
;
The DROP of MVis not a problem...
DROP MATERIALIZED VIEW MV;
But re-creation gives error:
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
SQL-Fehler: ORA-32334: cannot create prebuilt materialized view on a table already referenced by a MV
The key is in already referenced by a MV
So let find the materialized view that is causing the problem:
select name, owner, master_owner, master
from all_snapshots where
master ='MV';
NAME OWNER MASTER_OWNER MASTER
------------------------------ ------------------------------ ------------------------------ ------------------------------
MV2 SAMPLE SAMPLE MV
The MV2 must be dropped first
DROP MATERIALIZED VIEW MV2;
Than the materializes view MV can be rebuilt.
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
and after that the MV2 must be build again.
This is the expected bahaviour on 11.2
select * from v$version;
Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
Define a table MV and build a materialized view on it.
create table mv as
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
Now check that both object exĂ­sts
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
MATERIALIZED VIEW MV
Now drop the materialzed view and re-check the objects
DROP MATERIALIZED VIEW MV;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
OK, materialized view disapeared, but table exists, why?
You may want to check documentation here
If you drop a materialized view that was created on a prebuilt table, then the database drops the materialized view, and the prebuilt table reverts to its identity as a table.
So, the table exists and you may again build a materialized view on it.
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
MATERIALIZED VIEW MV
Note in your case when teh materialized view is based on prebuilt table the "PRESERVE TABLE" is default behaviour in DROP, so teh same effect you get with
DROP MATERIALIZED VIEW MV PRESERVE TABLE;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
The table exist after the DROP materialize view.
Please check this simple scenario to see if it works. Check also your Oracle version - PRESERVE TABLEwas introduced in 10g.

How to auto-redefine view when underlying table changes (new column)?

We've got a view that's defined like this
CREATE VIEW aView as
SELECT * from aTable Where <bunch of conditions>;
The "value" of the view is in the where-condition, so it is okay to use a Select * in this case.
When a new column is added to the underlying table, we have to redefine the view with a
CREATE OR REPLACE FORCE VIEW aView as
SELECT * from aTable Where <bunch of conditions>;
as the Select * seems to get "translated" into all the columns present at the time the view is (re-)defined.
My question: How can we avoid this extra step?
(If the answer is dependent on the RDBMS, we're using Oracle.)
I know you specified Oracle, but the behavior is the same in SQL Server.
One way to update the view with the new column is to use:
exec sp_refreshview MyViewName
go
Of course, I also agree with the other comments about not using a SELECT * in a view definition.
This extra step is mandatory in Oracle: you will have to recompile your view manually.
As you have noticed, the "*" is lost once you create a view:
SQL> create table t (id number);
Table created
SQL> create view v as select * from t;
View created
SQL> select text from user_views where view_name = 'V';
TEXT
-------------------------------------------------------
select "ID" from t
You should not be using * in your views. Specify the columns explicitly.
That way you are only retrieving the data you need, and thus avoid potential issues down the road where someone adds a column to a table that you do not want that view to return (e.g., a large binary column that would adversely impact performance).
Yes, you need to recompile the view to add another column, but this is the correct process. That way you avoid other compilation issues, such as if the view reference two tables, and someone adds a duplicate column name in one of the tables. The compiler would then have issues determining which of the columns was being referred to if you did not prefix a reference to the column with a table alias, or it might complain if there are duplicate column names in the results.
The problem with automatically updating views to add columns comes when you extend your model, for example to
SELECT a.*, std_name_format(a.first_name, a.middle_names, a.last_name) long_name
or even
SELECT a.*, b.* from table_a a join table_b b....
If you have a view of just SELECT * FROM table, then you probably should be using a synonym or addressing the table directly.
If the view is hiding rows (SELECT * FROM table WHERE...), then you can look at the feature variously known as Fine Grained Access Control (FGAC), Row Level Security (RLS) or Virtual Private Database (VPD).
You might be able to do something with a DDL trigger but that would get complicated.