PostgreSQL create table statement: auto insert id - sql

I am using PostgreSQL 14. For tenant system, My script
DROP TABLE IF EXISTS tenant;
CREATE TABLE tenant
(
id smallserial primary key,
company_tax_code character varying(14),
period character varying(16), -- 2021070420220705
created timestamp with time zone
);
DROP TABLE IF EXISTS account_default;
CREATE TABLE account_default
(
id smallint,
ref_type smallint not null,
ref_type_name character varying(256),
voucher_type smallint not null,
column_name character varying(64) not null,
column_caption character varying(128) not null,
filter_condition character varying(1024),
default_value character varying(32),
sort_order smallint,
created timestamp with time zone,
created_by character varying(64),
modified timestamp with time zone,
modified_by character varying(64),
tenant_id smallint,
PRIMARY KEY (id, tenant_id),
CONSTRAINT fk_tenant FOREIGN KEY (tenant_id) REFERENCES tenant (id)
);
I am looking something like
DROP TABLE IF EXISTS account_default;
CREATE TABLE account_default
(
id smallint default value (max_value of account_default.id + 1 where tenant_id = account_default.tenant_id,
ref_type smallint not null,
ref_type_name character varying(256),
voucher_type smallint not null,
column_name character varying(64) not null,
column_caption character varying(128) not null,
filter_condition character varying(1024),
default_value character varying(32),
sort_order smallint,
created timestamp with time zone,
created_by character varying(64),
modified timestamp with time zone,
modified_by character varying(64),
tenant_id smallint,
PRIMARY KEY (id, tenant_id),
CONSTRAINT fk_tenant FOREIGN KEY (tenant_id) REFERENCES tenant (id)
);
Help me
DROP TABLE IF EXISTS account_default;
CREATE TABLE account_default
(
id smallint default value (max_value of account_default.id + 1 where tenant_id = account_default.tenant_id
I need composite key
(table_id, tenant_id)
(1, 1)
(2, 1)
(3, 1)
(1, 2)
(2, 2)
(1, 3)
If insert, I need
(4, 1)
explain
4 = (max (table_id) where tenant_id = 1) + 1;
insert like tirgger or automation at database-side.

demo
changed all the character varying to text data type.
changed small int to bigint data type.
removed some not null constraint.
the cost is figure out the new tenant id in the current table account_default or not.
function and trigger.
CREATE OR REPLACE FUNCTION restart_seq ()
RETURNS TRIGGER
AS $$
BEGIN
RAISE NOTICE 'new.tenant_id: %', NEW.tenant_id;
RAISE NOTICE 'all.tenant_id: %', (
SELECT
array_agg(tenant_id)
FROM
tenant);
RAISE NOTICE 'new.tenant_id in : %', (
SELECT
NEW.tenant_id IN (
SELECT
tenant_id
FROM
tenant));
IF (NEW.tenant_id NOT IN (
SELECT
tenant_id
FROM
account_default)) THEN
NEW.acc_id = 1;
ALTER SEQUENCE account_default_acc_id_seq
RESTART WITH 2;
RAISE NOTICE 'currval(''account_default_acc_id_seq''): %', currval('account_default_acc_id_seq');
END IF;
RETURN new;
END;
$$
LANGUAGE plpgsql;
create or replace trigger trg_reset_the_accid
before insert on account_default
for each row execute procedure restart_seq();

Related

Argument of AND must not return a set when used with BETWEEN in a check constraint

I am encountering the error "argument of AND must not return a set" from the AND in the check constraint of the below table.
CREATE TABLE loan (
id SERIAL PRIMARY KEY,
copy_id INTEGER REFERENCES media_copies (copy_id),
account_id INT REFERENCES account (id),
loan_date DATE NOT NULL,
expiry_date DATE NOT NULL,
return_date DATE,
CONSTRAINT max_student_concurrent_loans CHECK(
CurrentStudentLoansCount() BETWEEN 1 AND 7
)
);
The implementation of CurrentStudentLoansCount() is shown below.
CREATE OR REPLACE FUNCTION CurrentStudentLoansCount()
RETURNS TABLE(accid BIGINT) AS $$
BEGIN
RETURN QUERY
SELECT COUNT(*)
FROM loan
WHERE account_id IN (SELECT id FROM student)
AND return_date IS NULL
GROUP BY account_id;
END
$$ LANGUAGE PLPGSQL;
Why am I running into this error and how can I work around it?
For context, the below figure displays my database schema.
Your function returns a table with multiple rows so you can't use that for a BETWEEN condition. Presumably you just want that value for the account_id of that row of the table (not for all account_ids).
So change the function to return a single value by passing it the account_id. And you also don't need PL/pgSQL for this:
CREATE OR REPLACE FUNCTION currentstudentloanscount(p_account_id integer)
RETURNS bigint
as
$$
SELECT COUNT(*)
FROM loan
WHERE account_id = p_account_id
AND return_date IS NULL;
$$ LANGUAGE sql;
And change your table definition to:
CREATE TABLE loan (
id SERIAL PRIMARY KEY,
copy_id INTEGER REFERENCES media_copies (copy_id),
account_id INT REFERENCES account (id),
loan_date DATE NOT NULL,
expiry_date DATE NOT NULL,
return_date DATE,
CONSTRAINT max_student_concurrent_loans
CHECK(currentstudentloanscount(account_id) BETWEEN 1 AND 7)
);

PostgreSQL trigger error: 'column "t" of relation "inventory_product" does not exist'

I am trying to create a trigger that decrements the qty column on the inventory_product table based on the qty that was inserted into account_sale. The trigger works fine with MySQL (with different syntax), but I'm not sure whats wrong with the PostgreSQL version.
When I run an insert on inventory_sale I get:
error: column "t" of relation "inventory_product" does not exist
the trigger:
CREATE OR REPLACE FUNCTION update_inventory()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.product_id IS NOT NULL THEN
UPDATE inventory_product AS t
SET t.qty = t.qty - NEW.qty #error is thrown here
WHERE t.id = NEW.product_id;
END IF;
END; $$ LANGUAGE 'plpgsql';
CREATE TRIGGER after_insert_account_sale
AFTER INSERT ON account_sale
FOR EACH ROW
EXECUTE PROCEDURE update_inventory();
inventory_product:
CREATE TABLE public.inventory_product
(
id integer NOT NULL DEFAULT nextval('inventory_product_id_seq'::regclass),
upc character varying(45) COLLATE pg_catalog."default",
sku character varying(45) COLLATE pg_catalog."default",
asin character varying(45) COLLATE pg_catalog."default",
ebay_sku character varying(45) COLLATE pg_catalog."default",
tcgplayer_sku integer,
qty integer NOT NULL,
opt_qty integer NOT NULL,
reserve integer NOT NULL,
sell_price numeric(10,2) NOT NULL,
buy_price numeric(10,2) NOT NULL,
product_weight_g numeric(12,5) NOT NULL,
dim_x_cm numeric(12,5) NOT NULL,
dim_y_cm numeric(12,5) NOT NULL,
dim_z_cm numeric(12,5) NOT NULL,
stock_image_path character varying(75) COLLATE pg_catalog."default",
CONSTRAINT inventory_product_pkey PRIMARY KEY (id),
CONSTRAINT inventory_product_asin_key UNIQUE (asin)
,
CONSTRAINT inventory_product_ebay_sku_key UNIQUE (ebay_sku)
,
CONSTRAINT inventory_product_stock_image_path_key UNIQUE (stock_image_path)
,
CONSTRAINT inventory_product_tcgplayer_sku_key UNIQUE (tcgplayer_sku)
)
account_sale:
CREATE TABLE public.account_sale
(
id integer NOT NULL DEFAULT nextval('account_sale_id_seq'::regclass),
unit_price numeric(10,2) NOT NULL,
qty integer NOT NULL,
order_id integer NOT NULL,
product_id integer,
CONSTRAINT account_sale_pkey PRIMARY KEY (id),
CONSTRAINT account_sale_order_id_product_id_8c7f2e6a_uniq UNIQUE (order_id, product_id)
,
CONSTRAINT account_sale_order_id_7724b965_fk_account_order_id FOREIGN KEY (order_id)
REFERENCES public.account_order (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT account_sale_product_id_716f2cb2_fk_inventory_product_id FOREIGN KEY (product_id)
REFERENCES public.inventory_product (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED
)
insert:
INSERT INTO account_sale (qty, unit_price, order_id, product_id)
SELECT $1::integer,$2::float,$3::integer,t.id FROM inventory_product
AS t WHERE t.ebay_sku=$4
UNION
SELECT $5::integer,$6::float,$7::integer,t.id FROM inventory_product
AS t WHERE t.ebay_sku=$8
insert params:
[
2, 79.98, 167, '1',
2, 19.98, 167, '2',
2, 79.98, 168, '1',
2, 79.98, 169, '3',
2, 79.98, 170, '4'
]
Note that the insert works fine when I remove the trigger.
Also I am running the insert from a Node.js server (but I don't think that's relevant).
What am I missing here?
Don't use the target's table alias on the left hand side of the SET assignment. It's always clear which table is meant there. Btw: the function language is an identifier and should not be quoted:
CREATE OR REPLACE FUNCTION update_inventory()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.product_id IS NOT NULL THEN
UPDATE inventory_product AS t
SET qty = t.qty - NEW.qty
-- ^ here
WHERE t.id = NEW.product_id;
END IF;
END; $$ LANGUAGE plpgsql;
In fact, you don't need any alias at all in the UPDATE statement:
CREATE OR REPLACE FUNCTION update_inventory()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.product_id IS NOT NULL THEN
UPDATE inventory_product
SET qty = qty - NEW.qty
WHERE id = NEW.product_id;
END IF;
END; $$ LANGUAGE plpgsql;

Receiving endless errors with the insert - statement

I am trying to insert some values into customer and then i get the ora-00904 error.
After i research about this problem, instead of using '' i used "". But now im receiving the ora-00984.
INSERT INTO customer (c_id, name, age)
VALUES (1, 'Carl', 45)
OUTPUT:
SQL-ERROR: ORA-00904: "name": invalid ID
00904. 00000 - "%s: invalid identifier"
then i tried this way.
INSERT INTO customer (c_id, name, age)
VALUES (1, "Carl", 45)
OUTPUT:
00984. 00000 - "column not allowed here"
My DDL - Code:
CREATE TABLE adress (
adress_id INTEGER NOT NULL,
state VARCHAR2(60) NOT NULL,
country VARCHAR2(60) NOT NULL
);
ALTER TABLE adress ADD CONSTRAINT adress_pk PRIMARY KEY ( adress_id );
CREATE TABLE contract (
con_id INTEGER NOT NULL,
length DATE
);
ALTER TABLE contract ADD CONSTRAINT contract_pk PRIMARY KEY ( con_id );
CREATE TABLE customer (
c_id INTEGER NOT NULL,
name VARCHAR2(60) NOT NULL,
age CHAR(2) NOT NULL,
adress_adress_id INTEGER
);
ALTER TABLE customer ADD CONSTRAINT customer_pk PRIMARY KEY ( c_id );
CREATE TABLE relation_1 (
customer_c_id INTEGER NOT NULL,
contract_con_id INTEGER NOT NULL
);
ALTER TABLE relation_1 ADD CONSTRAINT relation_1_pk PRIMARY KEY ( customer_c_id,
contract_con_id);
ALTER TABLE customer
ADD CONSTRAINT customer_adress_fk FOREIGN KEY ( adress_adress_id )
REFERENCES adress ( adress_id );
ALTER TABLE relation_1
ADD CONSTRAINT relation_1_contract_fk FOREIGN KEY ( contract_con_id )
REFERENCES contract ( con_id );
ALTER TABLE relation_1
ADD CONSTRAINT relation_1_customer_fk FOREIGN KEY ( customer_c_id )
REFERENCES customer ( c_id );
The syntax uses VALUES() for the list of values:
INSERT INTO customer (c_id, name, age)
VALUES (1, 'Carl', 45);
You can also use a SELECT:
INSERT INTO customer (c_id, name, age)
SELECT 1, 'Carl', 45
FROM dual;
Note that in both cases, the delimiter for the string is single quotes not double quotes.
In SQL we use single quotes for string literals. Double quotes are used (optionally) for identifiers such as table and column names. You have used double quotes around the value of carl and that's why Oracle hurls ORA-00984.
Why you got ORA-00904 for the first statement is a mystery. Probably there is something awry with your definition of customer but unless you post the table structure we cannot be sure.

Delete rows from several tables

I use these tables to store data.
I would like to delete all data older than 1 month (for example) using one SQL query from all tables.
-- TABLE AGENT_HISTORY
CREATE TABLE AGENT_HISTORY(
EVENT_ID INTEGER NOT NULL,
AGENTID INTEGER NOT NULL,
EVENT_DATE DATE NOT NULL
)
/
CREATE TABLE CPU_HISTORY(
CPU_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
CPU_NAME VARCHAR2(50 ) NOT NULL,
CPU_VALUE NUMBER NOT NULL
)
/
CREATE TABLE CPU_TEMP_HISTORY(
CPU_TEMP_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
CPU_TEMP_NAME VARCHAR2(50 ) NOT NULL,
CPU_TEMP_VALUE NUMBER NOT NULL
)
/
CREATE TABLE MEMORY_HISTORY(
MEMORY_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
MEMORY_NAME VARCHAR2(50 ) NOT NULL,
MEMORY_VALUE NUMBER NOT NULL
)
/
CREATE TABLE DISK_HISTORY(
DISK_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
DISK_NAME VARCHAR2(50 ) NOT NULL,
DISK_VALUE NUMBER NOT NULL
)
/
CREATE TABLE NETWORK_HISTORY(
NETWORK_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
ADAPTER_NAME VARCHAR2(50 ) NOT NULL,
TRANSMITBYTES NUMBER NOT NULL,
TRANSMITSPEED NUMBER,
RECEIVESPEED NUMBER,
RECEIVEBYTES NUMBER
)
/
CREATE TABLE SWAP_HISTORY(
SWAP_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
SWAP_NAME VARCHAR2(50 ) NOT NULL,
SWAP_VALUE NUMBER NOT NULL
)
/
CREATE TABLE CONNECTIONS_HISTORY(
CONNECTIONS_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
CONNECTIONS_NAME VARCHAR2(50 ) NOT NULL,
CONNECTIONS_VALUE NUMBER NOT NULL
)
/
CREATE TABLE PARTITIONS_HISTORY(
PARTITIONS_HISTORY_ID INTEGER NOT NULL,
EVENT_ID INTEGER,
PARTITIONS_NAME VARCHAR2(50 ) NOT NULL,
PARTITIONS_VALUE NUMBER NOT NULL
)
/
Is this possible in Oracle?
I use EVENT_ID as unique key ID in all tables.
As suggested by "a_horse_with_no_name", you can use ON DELETE CASCADE by creating the required relationships.
For example,
ALTER TABLE table_name
ADD CONSTRAINT constraint_name
FOREIGN KEY (column1, column2, ... column_n)
REFERENCES parent_table (column1, column2, ... column_n)
ON DELETE CASCADE;
Bookmark the Database SQL Language Reference and start reading the concepts for better understanding.

PLS-00049: bad bind variable (1)

Someone could help me to find my error ?
CREATE OR REPLACE TRIGGER Assign_Prix
BEFORE INSERT OR UPDATE
ON DetailCommande
FOR EACH ROW
DECLARE
v_NOECHELLE Integer; v_PRIX Integer;
BEGIN
SELECT NOECHELLE INTO v_NOECHELLE
FROM ECHELLE
WHERE ddebut<=:new.ddebut AND dfin>=:new.dfin;
SELECT Min(Prix) INTO v_Prix
FROM DETAILECHELLE
WHERE noechelle = v_Echelle AND qtemin<=:new.qtemin;
:NEW.PRIX:= v_Prix;
END;
CREATE TABLE Echelle
(
NoEchelle NUMBER NOT NULL,
CodeProduit VARCHAR2 (15) NOT NULL ,
DDebut DATE NOT NULL,
DFin DATE NOT NULL
)
;
ALTER TABLE Echelle
ADD CONSTRAINT Echelle_PK PRIMARY KEY ( NoEchelle ) ;
ALTER TABLE Echelle
ADD CONSTRAINT Echelle_FK_Produit FOREIGN KEY (CodeProduit)
REFERENCES Produit(CodeProduit);
CREATE TABLE DetailEchelle
(
NoEchelle NUMBER NOT NULL ,
NoDetail NUMBER NOT NULL ,
QteMin NUMBER NOT NULL ,
Prix NUMBER NOT NULL
)
;
ALTER TABLE DetailEchelle
ADD CONSTRAINT DetailEchelle_PK PRIMARY KEY ( NoEchelle, NoDetail);
ALTER TABLE DetailEchelle
ADD CONSTRAINT DetailEchelle_FK_Echelle FOREIGN KEY (NoEchelle)
REFERENCES Echelle(NoEchelle);
CREATE TABLE Produit
(
CodeProduit VARCHAR2 (15) NOT NULL ,
CodeCategorie VARCHAR2 (5) NOT NULL ,
Nom VARCHAR2 (30) NOT NULL ,
Description VARCHAR2 (100) ,
CoutFixe NUMBER ,
LimiteSupCF NUMBER ,
Delai NUMBER
)
;
ALTER TABLE Produit
ADD CONSTRAINT Produit_PK PRIMARY KEY ( CodeProduit ) ;
ALTER TABLE Produit
ADD CONSTRAINT Produit_FK_Categorie FOREIGN KEY (CodeCategorie)
REFERENCES Categorie(CodeCategorie);
CREATE TABLE DetailCommande
(
NoCommande NUMBER NOT NULL ,
LigneCommande NUMBER NOT NULL ,
Qte NUMBER NOT NULL ,
Message VARCHAR2 (100) NOT NULL,
CodeProduit VARCHAR2 (15) NOT NULL ,
CodeCouleur VARCHAR2 (4) NOT NULL ,
PrixUnitVendu NUMBER,
CFVendu NUMBER
)
;
ALTER TABLE DetailCommande
ADD CONSTRAINT DetailCommande_PK PRIMARY KEY ( LigneCommande, NoCommande ) ;
ALTER TABLE DetailCommande
ADD CONSTRAINT DetailCommande_FK_Commande FOREIGN KEY (NoCommande)
REFERENCES Commande(NoCommande);
ALTER TABLE DetailCommande
ADD CONSTRAINT DetailCommande_FK_Produit FOREIGN KEY (CodeProduit, CodeCouleur)
REFERENCES ProduitCouleur(CodeProduit, CodeCouleur);
Your trigger is defined on the DetailCommande table. This table does not have a column named ddebut, dfin, qtemin or prix. Your trigger, therefore, cannot reference those columns in the :new pseudo-record since they don't exist in the table.
Unfortunately, if those columns don't exist in the DetailCommande table, I'm hard-pressed to guess at what your trigger is supposed to do so I have no idea what the proper syntax would be.