Create a view with uuid_generate_v4() - sql

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)

Related

Set up trigger to get sum of all values in a column

I am creating a trigger in SQL to sum up all the values in a column after a change is made. I am stuck and encountering an error when I try this:
`
CREATE OR REPLACE TRIGGER GET_NUM_ATHLETES
AFTER DELETE OR UPDATE OF NUM_ATHLETES OR INSERT ON DELEGATION
BEGIN
SELECT
SUM("A1"."NUM_") "SUM(NUM_)"
INTO x_1 FROM
"DBF19"."DELEGATION" "A1";
END;
`
My table looks like this:
ID
Num_
ABC
2
XYZ
4
I just used the Oracle SQL Developer GUI to create, but obviously doing something wrong.
You could use a view instead of maintaining the data in a table. That way the view would get the results "live" each time.
And also you wouldn't need to do the extra task of loading data into another table
CREATE VIEW NUM_ATHLETES
AS
SELECT SUM("A1"."NUM_") "SUM(NUM_)"
FROM "DBF19"."DELEGATION" "A1";
Do not create a table, use a VIEW (or if you were doing more complicated calculations a MATERIALIZED VIEW):
DROP TABLE num_athletes;
then:
CREATE VIEW num_athletes (id, num) AS
SELECT id, SUM(num_)
FROM DBF19.DELEGATION
GROUP BY id;

POstgresSQL: ERROR: cannot delete from view "view_name"

I am trying to delete rows from a VIEW that appear in another VIEW. This is a trial operation with TABLE, but couldn't figure out how it works with VIEW.
For example, consider these two VIEWS:
SELECT * FROM trips;
id session_ids distance
535780 {8024,8026} 74695.31
535268 {4567} 455.84
543477 {63331} 18546.94
540797 {43350} 412.65
SELECT * FROM sessions
session_id timestamp
4567 2016-04-07 15:39:31.578
8024 2016-04-09 14:31:19.068
1526 2016-04-04 07:50:24.544
10311 2016-04-10 16:48:14.883
Note that the column trips.session_ids is type integer array, and the column sessions.session_id is type integer.
I want to delete rows from trips that are in sessions, so:
DELETE FROM trips t
USING sessions s
WHERE s.session_id = ANY(t.session_ids)
Error:
ERROR: cannot delete from view "trips"
DETAIL: Views that do not select from a single table or view are not automatically updatable.
HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.
SQL state: 55000
Expected result (after delete):
SELECT * FROM trips;
id session_ids distance
543477 {63331} 18546.94
540797 {43350} 412.65
EDIT
To shed more light to my question, the trips VIEW was created from a large table (a subset of raw table), something like:
CREATE VIEW trips
AS
SELECT * FROM raw_table
WHERE some_condition;
Now I need a way to further filter trips to exclude rows that appear in sessions.
EDIT-2
As illustrated in this dbfiddle,it worked fine, but not in my real database.
CREATE TABLE raw_table(id int, session_ids integer[], distance double precision);
INSERT INTO raw_table(id, session_ids, distance)
VALUES (535780,'{8024,8026}',4695.31),
(535268,'{4567}',455.84),
(543477,'{63331}',18546.94),
(544400,'{15304}',25546.24),
(544210,'{12012,17577}',32546.24),
(540797,'{43350}',412.65);
CREATE VIEW trips
AS
SELECT * FROM raw_table
WHERE distance < 25000;
CREATE TABLE sessions (session_id int, timestamp TIMESTAMP);
INSERT INTO sessions (session_id, timestamp)
VALUES (4567,'2016-04-07 15:39:31.578+01'),
(8024,'2016-04-09 14:31:19.068+01'),
(1526,'2016-04-04 07:50:24.544+01'),
(10311,'2016-04-10 16:48:14.883+01');
DELETE FROM trips t
USING sessions s
WHERE s.session_id = ANY(t.session_ids)
Only very simple views allow data modifications.
If you want to run DELETE on a more complicated view, you have to write an INSTEAD OF DELETE trigger that performs some appropriate action instead instead, for example delete something from the tables underlying the view.

Postgres create view as not a view

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

SQL.Working with views

I have a table 'Goods' with different information about goods (name, price, etc). I need to create a view at the same scheme as table 'Goods' has. But the view must be empty. And when user adds new good to the view it is saved in table 'Goods', but the view remains empty when user opens it next time. So main idea is not to show existing data to the user which has access to the view.
Assuming your on a database system that supports a concept like SQL Server's CHECK OPTION, and you're allowed to create a view that doesn't have that option set, you should be fine:
create table T (ID int not null)
go
create view V
as
select * from T where 1=0
go
select * from V
go
insert into V(ID) values (10)
go
select * from V
go
select * from T
The two selects from V return 0 rows. The select from T returns one row:
ID
----
10
CHECK OPTION:
Forces all data modification statements executed against the view to follow the criteria set within select_statement. When a row is modified through a view, the WITH CHECK OPTION makes sure the data remains visible through the view after the modification is committed.
And you want the opposite - you want to allow data modifications performed through the view to create rows which are invisible through the view.
Create table Goods1 with "insert trigger" on it which make insert into Goods and delete from Goods1
As far as I know this isn't possible. The whole point of a view is that it is a view to a table or grouping of tables, ie. it must show the data that matches the view.
http://www.w3schools.com/sql/sql_view.asp
What you could do is create another table called GoodsView and add a trigger to it to INSERT into Goods table and DELETE from GoodsView afterwards.
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fsqlp%2Frbafysqltrig.htm

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.