Multi-column partitioning in Greenplum - postgresql

I am trying to do multi-column partitioning in Greenplum database using PostgreSQL. However I keep getting an error -
ERROR: partition key has 2 columns but 1 columns specified in VALUES
clause LINE 15: VALUES ('10001','2014-03-11'),
^
********** Error **********
ERROR: partition key has 2 columns but 1 columns specified in VALUES
clause SQL state: 42P16 Character: 341
This is the query that I used:
CREATE TABLE EMP_TABLE
(
EMP_ID CHARACTER VARYING(9) NOT NULL,
JOB_ID CHARACTER VARYING(10) NOT NULL,
DT_OF_JOIN DATE NOT NULL,
SALARY NUMERIC(20,8) NOT NULL
-- CONSTRAINT ENTITY_MODEL_SCORE_PKEY PRIMARY KEY (ENTITY_ID, MODEL_ID, MODEL_RUN_DT)
)
WITH (
OIDS=FALSE
)
DISTRIBUTED BY (EMP_ID)
PARTITION BY LIST(EMP_ID,DT_OF_JOIN)
(
VALUES ('10001','2014-03-11'),
VALUES ('10002','2014-03-12')
)
I am not sure what I am missing. Can someone help me with the right syntax to do multi-column partition in Greenplum using PostgreSQL?

You can try it following using subpartition
CREATE TABLE sandbox.EMP_TABLE
(
EMP_ID CHARACTER VARYING(9) NOT NULL,
JOB_ID CHARACTER VARYING(10) NOT NULL,
DT_OF_JOIN date NOT NULL,
SALARY NUMERIC(20,8) NOT NULL
-- CONSTRAINT ENTITY_MODEL_SCORE_PKEY PRIMARY KEY (ENTITY_ID, MODEL_ID, MODEL_RUN_DT)
)
WITH (
OIDS=FALSE
)
DISTRIBUTED BY (JOB_ID)
PARTITION BY LIST(EMP_ID)
SUBPARTITION BY LIST(DT_OF_JOIN)
SUBPARTITION TEMPLATE
(
SUBPARTITION year1 VALUES ('2014-03-11'),
SUBPARTITION year2 VALUES ('2014-03-12')
)
(
values ('1001'),
values('10002')
)

Related

Columns with Postgresql Operator Classes specified cannot be constrained?

I wrote the following query.
-- TB_PK_INDEX
CREATE TABLE TB_PRIMARY_INDEX
(
COL VARCHAR COLLATE pg_catalog."POSIX" NOT NULL
)
WITH (
OIDS=false
);
-- TB_PK_INDEX Primary Key
CREATE UNIQUE INDEX PK_TB_PRIMARY_INDEX
ON TB_PRIMARY_INDEX
( -- TB_PK_INDEX
COL COLLATE pg_catalog."POSIX" varchar_pattern_ops ASC
);
-- TB_PK_INDEX
ALTER TABLE TB_PRIMARY_INDEX
ADD CONSTRAINT PK_TB_PRIMARY_INDEX
PRIMARY KEY
USING INDEX PK_TB_PRIMARY_INDEX
NOT DEFERRABLE;
And the following error occurs.
SQL Error [42809]: Error: "pk_tb_primary_index" no primary sort method for index 1 column
Detail: Cannot create a primary key or unique constraint using such an index.
Test was conducted on PostgreSQL 14.2.. The concept of operator class is lacking. Please advise.

How to select rows that fail exclusion constraint

I have a table with rows in it (source) that I am trying to insert into another table (target). The target has an exclusion constraint in place. However, when I do this, some of the rows fail the exclusion constraint. I would like to be able to select these rows in the source, that fail the exclusion constraint. Is this possible?
create table target(
id bigint primary key
,external_data_source_id bigint not null
,external_id text not null
,external_id_domain_id bigint not null
,internal_id bigint not null
,valid_period tstzrange not null
,EXCLUDE USING gist (external_data_source_id with = , external_id_domain_id with =, internal_id with =, external_id with =, valid_period WITH &&)
);
create table source(
id bigint primary key
,external_data_source_id bigint not null
,external_id text not null
,external_id_domain_id bigint not null
,internal_id bigint not null
,valid_period tstzrange not null
);
insert into source
select 1,1,'text',1,1,tstzrange('2000-01-01','2001-01-01');
insert into source
select 2,1,'text',1,1,tstzrange('2000-01-01','2001-01-01');
insert into source
select 1,'text',1,1,tstzrange('2002-01-01','2004-01-01');
insert into target
select * from source;
gives
Error: ERROR: conflicting key value violates exclusion constraint "target_external_data_source_id_external_id_domain_id_inter_excl"
Detail: Key (external_data_source_id, external_id_domain_id, internal_id, external_id, valid_period)=(1, 1, 1, text, ["2000-01-01 00:00:00+01","2001-01-01 00:00:00+01")) conflicts with existing key (external_data_source_id, external_id_domain_id, internal_id, external_id, valid_period)=(1, 1, 1, text, ["2000-01-01 00:00:00+01","2001-01-01 00:00:00+01")).
SQLState: 23P01
ErrorCode: 0
I would like to select the rows in source that fail this exclusion constraint.
You can use condition from the exclusion constraint in an exists query:
select s1.*
from source s1
where exists (select *
from source s2
where (s2.external_data_source_id, s2.external_id_domain_id,
s2.internal_id, s2.external_id)
= (s1.external_data_source_id, s1.external_id_domain_id,
s1.internal_id, s1.external_id)
and s1.valid_period && s2.valid_period
and s1.id <> s2.id
);
Online example: https://rextester.com/PDOE78609

When using COPY FROM statement getting ERROR: null value in column "field_id" violates not-null constraint

I am using the COPY FROM command to load data from a file.
The table is defined with identity column, which is not part of the file.
CREATE TABLE APP2DBMAP (
FIELD_ID integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
FIELD_NAME varchar(128) ,
TABLE_NAME varchar(128) ,
COLUMN_NAME varchar(128) ,
CONSTRAINT PK_APP2DBMAP PRIMARY KEY ( FIELD_ID )
);
I executed the following COPY FROM command, the file contains 3 values in 1 row.
copy app2dbmap (field_name, table_name, column_name) from '/opt/NetMgr/data/templ_db.txt' DELIMITER ',' ;
And I got the following error:
ERROR: null value in column "field_id" violates not-null constraint
DETAIL: Failing row contains (null, 'aaa', 'bbb', 'ccc').
CONTEXT: COPY app2dbmap, line 1: "'aaa','bbb','ccc'"
I tried to change the column description of field_id to serial, and it did work fine.
I don't understand why it doesn't work with the original table definition.
The problem is you have specified the field_id to be a not null value and hence when the file is passing null as a value, your error is there.
If you want an auto increment id, Use,
CREATE TABLE APP2DBMAP (
FIELD_ID smallserial NOT NULL,
FIELD_NAME varchar(128) ,
TABLE_NAME varchar(128) ,
COLUMN_NAME varchar(128) ,
CONSTRAINT PK_APP2DBMAP PRIMARY KEY ( FIELD_ID )
);
You can also use bigserial(int4) instead of smallint(int8)
or you can give a default value,
CREATE TABLE APP2DBMAP (
FIELD_ID integer NOT NULL default 0,
FIELD_NAME varchar(128) ,
TABLE_NAME varchar(128) ,
COLUMN_NAME varchar(128) ,
CONSTRAINT PK_APP2DBMAP PRIMARY KEY ( FIELD_ID )
);
You will have to pass something, you cannot pass null in a not null column

Average MySQL in new table

I have a database about weather that updates every second.
It contains temperature and wind speed.
This is my database:
CREATE TABLE `new_table`.`test` (
`id` INT(10) NOT NULL,
`date` DATETIME() NOT NULL,
`temperature` VARCHAR(25) NOT NULL,
`wind_speed` INT(10) NOT NULL,
`humidity` FLOAT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
I need to find the average temperature every hour.
This is my code:
Select SELECT AVG( temperature ), date
FROM new_table
GROUP BY HOUR ( date )
My coding is working but the problem is that I want to move the value and date of the average to another table.
This is the table:
CREATE TABLE `new_table.`table1` (
`idsea_state` INT(10) NOT NULL,
`dateavg` DATETIME() NOT NULL,
`avg_temperature` VARCHAR(25) NOT NULL,
PRIMARY KEY (`idsea_state`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
Is it possible? Can you give me the coding?
In order to insert new rows into a database based on data you have obtained from another table, you can do this by setting up an INSERT query targeting the destination table, then run a sub-query which will pull the data from the source table and then the result set returned from the sub-query will be used to provide the VALUES used for the INSERT command
Here is the basic structure, note that the VALUES keyword is not used:
INSERT INTO `table1`
(`dateavg`, `avg_temperature`)
SELECT `date` , avg(`temperature`)
FROM `test`;
Its also important to note that the position of the columns returned by result set will be sequentially matched to its respective position in the INSERT fields of the outer query
e.g. if you had a query
INSERT INTO table1 (`foo`, `bar`, `baz`)
SELECT (`a`, `y`, `g`) FROM table2
a would be inserted into foo
y would go into bar
g would go into baz
due to their respective positions
I have made a working demo - http://www.sqlfiddle.com/#!9/ff740/4
I made the below changes to simplify the example and just demonstrate the concept involved.
Here is the DDL changes I made to your original code
CREATE TABLE `test` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`date` DATETIME NOT NULL,
`temperature` FLOAT NOT NULL,
`wind_speed` INT(10),
`humidity` FLOAT ,
PRIMARY KEY (`id`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
CREATE TABLE `table1` (
`idsea_state` INT(10) NOT NULL AUTO_INCREMENT,
`dateavg` VARCHAR(55),
`avg_temperature` VARCHAR(25),
PRIMARY KEY (`idsea_state`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
INSERT INTO `test`
(`date`, `temperature`) VALUES
('2013-05-03', 7.5),
('2013-06-12', 17.5),
('2013-10-12', 37.5);
INSERT INTO `table1`
(`dateavg`, `avg_temperature`)
SELECT `date` , avg(`temperature`)
FROM `test`;

"polymorphism" for FOREIGN KEY constraints

There is this field in a table:
room_id INT NOT NULL CONSTRAINT room_id_ref_room REFERENCES room
I have three 2 tables for two kinds of rooms: standard_room and family_room
How to do something like this:
room_id INT NOT NULL CONSTRAINT room_id_ref_room REFERENCES standard_room or family_room
I mean, room_id should reference either standard_room or family_room.
Is it possible to do so?
Here is the pattern I've been using.
CREATE TABLE room (
room_id serial primary key,
room_type VARCHAR not null,
CHECK CONSTRAINT room_type in ("standard_room","family_room"),
UNIQUE (room_id, room_type)
);
CREATE_TABLE standard_room (
room_id integer primary key,
room_type VARCHAR not null default "standard_room",
FOREIGN KEY (room_id, room_type) REFERENCES room (room_id, room_type),
CHECK CONSTRAINT room_type = "standard_room"
);
CREATE_TABLE family_room (
room_id integer primary key,
room_type VARCHAR not null default "family_room",
FOREIGN KEY (room_id, room_type) REFERENCES room (room_id, room_type),
CHECK CONSTRAINT room_type = "family_room"
);
That is, the 'subclasses' point at the super-class, by way of a type descriminator column (such that the pointed to base class is of the correct type, and that primary key of the super class is the same as the child classes.
Here's the same SQL from the accepted answer that works for PostGres 12.8. There's a few issues not only the CREATE_TABLE syntax mistake:
CREATE TABLE room (
room_id serial primary key,
room_type VARCHAR not null,
CONSTRAINT room_in_scope CHECK (room_type in ('standard_room','family_room')),
CONSTRAINT unique_room_type_combo UNIQUE (room_id, room_type)
);
CREATE TABLE standard_room (
room_id integer primary key,
room_type VARCHAR not null default 'standard_room',
CONSTRAINT roomid_std_roomtype_fk FOREIGN KEY (room_id, room_type) REFERENCES public."room" (room_id, room_type),
CONSTRAINT std_room_constraint CHECK (room_type = 'standard_room')
);
CREATE TABLE family_room (
room_id integer primary key,
room_type VARCHAR not null default 'family_room',
CONSTRAINT roomid_fam_roomtype_fk FOREIGN KEY (room_id, room_type) REFERENCES "room" (room_id, room_type),
CONSTRAINT fam_room_constraint CHECK (room_type = 'family_room')
);
NOTE: The SQL above uses constraints to enforce the child room_type values default to the parent tables' room_type values: 'standard_room' or 'family_room'.
PROBLEM: Since the child tables Primary Key's expect either the standard and family room Primary Key that means you can't insert more than one record in thsee two child tables.
insert into room (room_type) VALUES ('standard_room'); //Works
insert into room (room_type) values ('family_room'); //Works
insert into standard_room (room_id,pictureAttachment) VALUES (1,'Before Paint'); //Works
insert into standard_room (room_id,pictureAttachment) VALUES (1,'After Paint'); //Fails
insert into standard_room (room_id,pictureAttachment) VALUES (1,'With Furniture');
insert into family_room (room_id,pictureAttachment) VALUES (2, 'Beofre Kids'); //Works
insert into family_room (room_id,pictureAttachment) VALUES (2,'With Kids'); //Fails
To make the tables accept > 1 row you have to remove the Primary Keys from the 'standard_room' and 'family_room' tables which is BAD database design.
Despite 26 upvotes I will ping OP about this as I can see the answer was typed free hand.
Alternate Solutions
For smallish tables with less than a handful of variations a simple alterative is a single table with Bool columns for different table Primary Key fields.
Single Table "Room"
Id
IsStandardRoom
IsFamilyRoom
Desc
Dimensions
1
True
False
Double Bed, BIR
3 x 4
2
False
True
3 Set Lounge
5.5 x 7
SELECT * FROM Room WHERE IsStdRoom = true;
At the end of the day, in a relational database it's not very common to be adding Room Types when it involves creating the necessary related database tables using DDL commands (CREATE, ALTER, DROP).
A typical future proof database design allowing for more Tables would look something like this:
Multi Many-To-Many Table "Room"
Id
TableName
TableId
1
Std
8544
2
Fam
236
3
Std
4351
Either Standard or Family:
select * from standard_room sr where sr.room_id in
(select TableId from room where TableName = 'Std');
select * from family_room fr where fr.room_id in
(select id from room where TableName = 'Fam');
Or both:
select * from standard_room sr where sr.room_id in
(select TableId from room where TableName = 'Std')
UNION
select * from family_room fr where fr.room_id in
(select id from room where TableName = 'Fam');
Sample SQL to demo Polymorphic fields:
If you want to have different Data Types in the polymorphic foreign key fields then you can use this solution. Table r1 stores a TEXT column, r2 stores a TEXT[] Array column and r3 a POLYGON column:
CREATE OR REPLACE FUNCTION null_zero(anyelement)
RETURNS INTEGER
LANGUAGE SQL
AS $$
SELECT CASE WHEN $1 IS NULL THEN 0 ELSE 1 END;
$$;
CREATE TABLE r1 (
r1_id SERIAL PRIMARY KEY
, r1_text TEXT
);
INSERT INTO r1 (r1_text)
VALUES ('foo bar'); --TEXT
CREATE TABLE r2 (
r2_id SERIAL PRIMARY KEY
, r2_text_array TEXT[]
);
INSERT INTO r2 (r2_text_array)
VALUES ('{"baz","blurf"}'); --TEXT[] ARRAY
CREATE TABLE r3 (
r3_id SERIAL PRIMARY KEY
, r3_poly POLYGON
);
INSERT INTO r3 (r3_poly)
VALUES ( '((1,2),(3,4),(5,6),(7,8))' ); --POLYGON
CREATE TABLE flex_key_shadow (
flex_key_shadow_id SERIAL PRIMARY KEY
, r1_id INTEGER REFERENCES r1(r1_id)
, r2_id INTEGER REFERENCES r2(r2_id)
, r3_id INTEGER REFERENCES r3(r3_id)
);
ALTER TABLE flex_key_shadow ADD CONSTRAINT only_one_r
CHECK(
null_zero(r1_id)
+ null_zero(r2_id)
+ null_zero(r3_id)
= 1)
;
CREATE VIEW flex_key AS
SELECT
flex_key_shadow_id as Id
, CASE
WHEN r1_id IS NOT NULL THEN 'r1'
WHEN r2_id IS NOT NULL THEN 'r2'
WHEN r3_id IS NOT NULL THEN 'r3'
ELSE 'wtf?!?'
END AS "TableName"
, CASE
WHEN r1_id IS NOT NULL THEN r1_id
WHEN r2_id IS NOT NULL THEN r2_id
WHEN r3_id IS NOT NULL THEN r3_id
ELSE NULL
END AS "TableId"
FROM flex_key_shadow
;
INSERT INTO public.flex_key_shadow (r1_id,r2_id,r3_id) VALUES
(1,NULL,NULL),
(NULL,1,NULL),
(NULL,NULL,1);
SELECT * FROM flex_key;