How to use existing index to create conditional constraint - postgresql

I have following index:
op.create_index(
op.f("ix_order_company_id_email_lower"),
"order",
["company_id", sa.text("lower(email)")],
unique=False,
postgresql_concurrently=True
)
Now I want to create a check constraint that is going to create sort of a 'unique' constraint for only specific type of orders.
op.execute(
"""ALTER TABLE order
ADD CONSTRAINT check_order_company_id_email_lower_type
CHECK (type = 'AH01')
NOT VALID"""
)
How can I add additional check to only apply to records in ix_order_company_id_email_lower?
EDIT: Basically this type of order can only be submitted once per email in a specific company.

You need a partial unique index:
CREATE INDEX ON order (company_id, lower(email))
WHERE type = 'AH01';

Related

Indexing over composite types in Postgres

Given the following, what can I expect of the resulting index?
CREATE TYPE instant AS (
epoch_seconds timezonetz,
nanos integer
);
CREATE TABLE event AS (
label text,
occurrence instant
);
CREATE INDEX idx_event_occurrence ON event (occurrence);
Will postgres automatically create a composite index over all the fields in instant? Would this index then use the left field as the primary and the right as the secondary? Would there be any reason to do the following instead?
CREATE INDEX idx_event_occurrence ON event (
(occurrence).epoch_seconds,
(occurrence).nanos
);

Is posible to get better error message when a domain check fail on postgresql?

I create a domain to catch empty strings:
CREATE DOMAIN TEXTN AS TEXT
CONSTRAINT non_empty CHECK (length(VALUE) > 0);
Then I replace all text/varchars fields on the DB with TEXTN.
However, when I get a error, it not give much info:
DbError { severity: "ERROR", parsed_severity: Some(Error),
code: SqlState("23514"),
message: "value for domain textn violates check constraint \"non_empty\"",
detail: None, hint: None, position: None, where_: None,
schema: Some("libs"),
table: None,
column: None, datatype: Some("textn"),
constraint: Some("non_empty")}
It not even tell me in what table and field the check fail.
If is even possible to print the row to insert better, but at least table and field is possible?
PostgreSQL (I checked version 11) simply does not provide this information as part of the protocol. Consider these statements:
=> CREATE DOMAIN TEXTN AS TEXT CONSTRAINT non_empty CHECK (length(VALUE) > 0);
CREATE DOMAIN
=> CREATE TABLE test_table (test_column textn);
CREATE TABLE
=> INSERT INTO test_table VALUES ('');
ERROR: value for domain textn violates check constraint "non_empty"
The error message on the wire looks like this:
S ERROR
V ERROR
C 23514
M value for domain textn violates check constraint "non_empty\
s public
d textn
n non_empty
F execExprInterp.c
L 3494
R ExecEvalConstraintCheck
There is no trace of test_table or test_column.
If you have some control over how your framework creates tables, it may be possible to use named table constraints instead of domain types, like this:
CREATE TABLE test_table (
test_column text
CONSTRAINT test_column_check CHECK (length(test_column) > 0));
If you make sure that the constraint name uniquely identifies the column, you can use that to recover the problematic column.
Even for a CHECK constraint defined on the column, as in CREATE TABLE test_table (test_column text CHECK (length(test_column) > 0));, PostgreSQL does not report the column name. You only get the name of the constraint, which is autogenerated by PostgreSQL on table creation and usually starts with the column name, but this is not guaranteed.

Unique constraint on single field of a custom type in postgres

I have an entity price in my schema it has an attribute amount which is of a custom type money_with_currency.
The money_with_currency is basically type (amount Big Int, currency char(3)).
The price entity belongs to a product. What I want to do is, create a unique constraint on the combination of product_id(foreign key) + currency . How can I do this?
Referencing a single field of a record type is a bit tricky:
CREATE TYPE money_with_currency AS (amount bigint, currency char(3));
CREATE TABLE product_price
(
product_id integer not null references product,
price money_with_currency not null
);
CREATE UNIQUE INDEX ON product_price(product_id, ((price).currency));

Adding values to a newly inserted column in an existing table in PostgreSQL 9.3

created a table named "collegetable":
create table collegetable (stid integer primary key not null,stname
varchar(50),department varchar(10),dateofjoin date);
provided values for each column:collegetable data
inserted a new column in it named "cgpa" and tried to add values for this column in one shot using the code:
WITH col(stid, cgpa) as
( VALUES((1121,8.01),
(1131,7.12),
(1141,9.86))
)
UPDATE collegetable as colldata
SET cgpa = col.cgpa
FROM col
WHERE colldata.stid = col.stid;
and got error :
ERROR:operator does not exist:integer=record
LINE9:where colldata.stid=col.stid;
HINT:No operator matches the given name and arguement type.you might need to add explicit type casts.
pls help in solving.thanks in advance.
The with clause only defines the names of the columns, not the data types:
with col (stid, cgpa) as (
...
)
update ...;
For details see the tutorial and the full reference

Postgresql constraint : conditional check

I have a table with 3 column : id1,id2,status
I want to have a constraint that match this example:
I can have only one (val_X,val_Y,True)
I can have many (val_X,,val_Y,False)
It must refuse a new row with same values (val_x,val_y) and true, and accept it with false.
I got the answer:
create unique index on table_name (id1,id2, status)
where status = true;
I will have only one (val_x,val_y,True).