As a part of ETL, table continuous_trips has continuous flow of incoming records.
New records are aggregated and get inserted into temp. table called trips_agg every 5 minutes.
CREATE TABLE IF NOT EXISTS trips_agg AS (
SELECT start_time, station_id, from_station, to_station, from_terminus, end_terminus, previous_station, next_station,
AVG(wait_span) AS wait_span,
AVG(walk_span) AS walk_span,
AVG(delay_span) AS delay_span,
SUM(passengers_requests) AS passengers_requests
FROM continuous_trips
GROUP BY start_time, station_id, from_station, to_station, from_terminus, end_terminus, previous_station, next_station
)
The table trips_agg gets dropped after inserting all records into the table daily_trips and recreated during next cycle.
Tables daily_trips & trips_agg have the same columns.
CREATE TABLE IF NOT EXISTS daily_trips (
start_time timestamp without time zone NOT NULL,
station_id text NOT NULL,
from_station text NOT NULL,
to_station text NOT NULL,
from_terminus text NOT NULL,
end_terminus text NOT NULL,
previous_station text,
next_station text,
wait_span interval NOT NULL,
walk_span interval NOT NULL,
delay_span interval NOT NULL,
passengers_requests numeric NOT NULL
)
Note: columns 'previous_station' and 'next_station' allows null.
composite unique key is added as follows:
ALTER TABLE daily_trips ADD CONSTRAINT daily_trips_unique_row UNIQUE
(start_time, station_id, from_station, to_station, from_terminus, end_terminus, previous_station, next_station);
In case unique key is violated upon insertion, the record should be updated. So used upsert strategy.
INSERT INTO daily_trips SELECT * FROM trips_agg
ON CONFLICT (start_time, station_id, from_station, to_station, from_terminus, end_terminus,
previous_station, next_station) DO UPDATE
set wait_span = (daily_trips.wait_span + EXCLUDED.wait_span)/2,
walk_span = (daily_trips.walk_span + EXCLUDED.walk_span)/2 ,
delay_span = (daily_trips.delay_span + EXCLUDED.delay_span)/2,
passengers_requests =(daily_trips.passengers_requests + EXCLUDED.passengers_requests);
When values for all columns are present this setup works perfectly but, it's not the case when any of nullable columns have a null value.
Since Postgres doesn't consider null values to invoke unique constraint, whenever any of nullable columns have null value, a new row is inserted, instead of update. This results into multiple rows for the unique key.
To overcome this, added an index on the table daily_trips after referring this article.
create unique index daily_trips_unique_trip_idx ON daily_trips
(start_time, station_id, from_station, to_station, from_terminus, end_terminus,
(previous_station IS NULL), (next_station IS NULL)
where previous_station IS NULL or fnext_station IS NULL
However, only one row could be added with null value for any nullable column.
For next row with null value for any nullable column, update is not happening and instead getting following error:
ERROR: duplicate key value violates unique constraint "daily_trips_unique_trip_idx"
What is needed?
The unique constraint should be respected and update should happen when there is null value in either of nullable columns 'previous_station' or 'next_station'.
Any help is appreciated.
The solution is to translate NULL to some other value, more specifically the 0-length string (''). The coalesce function does precisely that when used as coalesce (column_name, ''). The problem being creating a unique constraint with that generates a syntax error. So you cannot create that constraint. However, there is a work around, although not a easy one. Postgres enforces unique constraints through a unique index, so just create the index directly.
create unique index daily_trips_unique_row on daily_trips
( start_time
, station_id
, from_station
, to_station
, from_terminus
, end_terminus
, coalesce(previous_station , '')
, coalesce(next_station, '')
);
However, while the above respects the null-ability of index columns it no longer recognizes INSERT ... ON CONFLICT (See example here) . You will either need a function/procedure to handle the exception or use Select ... if exists then Update else Insert logic.
Only one row is allowed to have parent_id NULL:
CREATE TABLE simple21_page (
id integer NOT NULL,
name character varying(120) NOT NULL,
text text NOT NULL,
parent_id integer
);
This is a tree and there should be exactly one root node.
I tried this, but it does not work:
create unique index on simple21_page (parent_id) where parent_id is null;
Is this possible with an constraint or unique index, or is a trigger needed?
You are almost there. To get a singleton, you need a unique constraint on a constant value:
CREATE UNIQUE INDEX ON simple21_page ((1)) WHERE parent_id IS NULL;
Another way to enforce this kind of uniqueness is usage of COALESCE and index on expression:
CREATE UNIQUE INDEX ON simple21_page(COALESCE(parent_id, -1));
The value provided as substitute should be out of scope of permitted values.
db<>fiddle demo
INSERT INTO simple21_page VALUES (1, 'a', 'text', NULL);
-- success
INSERT INTO simple21_page VALUES (2, 'b', 'text', NULL);
-- ERROR: duplicate key value violates unique constraint "simple21_page_coalesce_idx"
CREATE TABLE instances(
ser_name VARCHAR(20) NOT NULL,
id INTEGER NOT NULL ,
ser_ip VARCHAR(16) NOT NULL,
status VARCHAR(10) NOT NULL,
creation_ts TIMESTAMP,
CONSTRAINT instance_id PRIMARY KEY(id)
);
CREATE TABLE characters(
nickname VARCHAR(15) NOT NULL,
type VARCHAR(10) NOT NULL,
c_level INTEGER NOT NULL,
game_data VARCHAR(40) NOT NULL,
start_ts TIMESTAMP ,
end_ts TIMESTAMP NULL ,
player_ip VARCHAR(16) NOT NULL,
instance_id INTEGER NOT NULL,
player_username VARCHAR(15),
CONSTRAINT chara_nick PRIMARY KEY(nickname)
);
ALTER TABLE
instances ADD CONSTRAINT ins_ser_name FOREIGN KEY(ser_name) REFERENCES servers(name);
ALTER TABLE
instances ADD CONSTRAINT ins_ser_ip FOREIGN KEY(ser_ip) REFERENCES servers(ip);
ALTER TABLE
characters ADD CONSTRAINT chara_inst_id FOREIGN KEY(instance_id) REFERENCES instances(id);
ALTER TABLE
characters ADD CONSTRAINT chara_player_username FOREIGN KEY(player_username) REFERENCES players(username);
insert into instances values
('serverA','1','138.201.233.18','active','2020-10-20'),
('serverB','2','138.201.233.19','active','2020-10-20'),
('serverE','3','138.201.233.14','active','2020-10-20');
insert into characters values
('characterA','typeA','1','Game data of characterA','2020-07-18 02:12:12','2020-07-18 02:32:30','192.188.11.1','1','nabin123'),
('characterB','typeB','3','Game data of characterB','2020-07-19 02:10:12',null,'192.180.12.1','2','rabin123'),
('characterC','typeC','1','Game data of characterC','2020-07-18 02:12:12',null,'192.189.10.1','3','sabin123'),
('characterD','typeA','1','Game data of characterD','2020-07-18 02:12:12','2020-07-18 02:32:30','192.178.11.1','2','nabin123'),
('characterE','typeB','3','Game data of characterE','2020-07-19 02:10:12',null,'192.190.12.1','1','rabin123'),
('characterF','typeC','1','Game data of characterF','2020-07-18 02:12:12',null,'192.188.10.1','3','sabin123'),
('characterG','typeD','1','Game data of characterG','2020-07-18 02:12:12',null,'192.188.13.1','1','nabin123'),
('characterH','typeD','3','Game data of characterH','2020-07-19 02:10:12',null,'192.180.17.1','2','bipin123'),
('characterI','typeD','1','Game data of characterI','2020-07-18 02:12:12','2020-07-18 02:32:30','192.189.18.1','3','dhiraj123'),
('characterJ','typeD','3','Game data of characterJ','2020-07-18 02:12:12',null,'192.178.19.1','2','prabin123'),
('characterK','typeB','4','Game data of characterK','2020-07-19 02:10:12','2020-07-19 02:11:30','192.190.20.1','1','rabin123'),
('characterL','typeC','2','Game data of characterL','2020-07-18 02:12:12',null,'192.192.11.1','3','sabin123'),
('characterM','typeC','3','Game data of characterM','2020-07-18 02:12:12',null,'192.192.11.1','2','sabin123');
here I need a view that shows the name of the server, the id of the instance and the number of active sessions (a session is active if the end timestamp is null). do my code wrong or something else? i am starting to learn so hoping for positive best answers.
my view
create view active_sessions as
select i.ser_name, i.id, count(end_ts) as active
from instances i, characters c
where i.id=c.instance_id and c.end_ts = null
group by i.ser_name, i.id;
This does not do what you want:
where i.id = c.instance_id and c.end_ts = null
Nothing is equal to null. You need is null to check a value against null.
Also, count(end_ts) will always produce 0, as we know already that end_ts is null, which count() does not consider.
Finally, I would highly recommend using a standard join (with the on keyword), rather than an implicit join (with a comma in the from clause): this old syntax from decades ago should not be used in new code. I think that a left join is closer to what you want (it would also take in account instances that have no character at all).
So:
create view active_sessions as
select i.ser_name, i.id, count(c.nickname) as active
from instances i
left join characters c on i.id = c.instance_id and c.end_ts is null
group by i.ser_name, i.id;
I am working with Oracle 12c in which I have below table structure:-
CREATE TABLE patients (
patient_id Integer NOT NULL,
customer_id Integer NOT NULL,
title varchar(5) NOT NULL,
fname varchar(125) NOT NULL,
lname varchar(125) NOT NULL,
dob date NOT NULL,
is_medical_card NUMBER(1) NOT NULL CHECK (is_medical_card IN (0,1)),
scheme_number Integer NOT NULL,
status varchar(50) NOT NULL,
created_on date NOT NULL,
last_update_date date NOT NULL,
consent_flag NUMBER(1) NOT NULL CHECK (consent_flag IN (0,1)),
relationship varchar(50) NOT NULL
);
Where patient_id is my primary key so now I want to make it auto increment as well so please let me how can I do this so make it auto increment.
Thanks!
Need to create auto increment to existing column.
You might want to use Identities - Creating a table with an Identity gives you the chance to omit the ID values and let Oracle use a sequence on your desired column:
1. Let's Create the Table:
CREATE TABLE identities (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
description varchar2(100) NOT NULL
);
Table created.
2. You'll want to create a primary key to ensure uniqueness:
alter table identities add constraint id_pk primary key (ID);
Table altered.
3. Let's insert some data in different ways:
INSERT INTO identities (description)
VALUES('Insert Description omitting ID');
1 row created.
INSERT INTO identities (id,description)
VALUES(NULL,'Insert with explicit NULL value');
1 row created.
4. Save the work done
commit;
Commit complete.
5. Check the results
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
As you can see we dind't specify any number for the ID, but the Identity on the ID column did for us
Note: Mind that you can manually insert an ID, but this will mess up with the Identity as it'll normally do with a standard Sequence:
INSERT INTO identities (id,description)
VALUES(3,'Manually insert an ID value');
1 row created.
INSERT INTO identities (description)
VALUES('Test Nextval');
INSERT INTO identities (description)
*
ERROR at line 1:
ORA-00001: unique constraint (XXX.ID_PK) violated
This error, because it tries to insert a '3' into the ID that was manually inserted with the statement before.
Check the table:
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
3 Manually insert an ID value
Re-Run the "NEXTVAL" insert:
INSERT INTO identities (description)
VALUES('Test Nextval');
1 row created.
Re-Check the table:
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
3 Manually insert an ID value
4 Test Nextval
Hope this Helps.
I have such table:
CREATE TABLE employee (
id INTEGER DEFAULT NEXTVAL('ids'::regclass) NOT NULL,
name CHARACTER VARYING NOT NULL,
employer INTEGER DEFAULT (-1)
);
And I want to insert sth into this table (I want to leave employer as default, -1):
INSERT INTO employee (name, id) VALUES('Doe', 2);
but my PostgreSQL 9.1 is complaining:
ERROR: insert or update on table "employee" violates foreign key constraint "FK_employer"
DETAIL: Key (employer)=(-1) is not present in table "employer".
I know that theres no employer with id = -1 but still, I want it that way. I want to set employer as -1 for this emplyee. Is it possible with postgreSQL?
Make the default null. Is it good?
employer INTEGER DEFAULT null