How to make foreign key by two fields one of which is PK in H2? - foreign-keys

I would like to define the following relation in H2:
So that relation connects two elements, but taking their types into acount: each relation type can connect two elements only of given element type.
Unfortunately, I can't draw FK from Relation to Element by two fields, one of fields is automatically dropped only one field remains
Also I can't define additional key in Elements table with two fields.
Is this possible in H2?
UPDATE
The same is in HSQLDB, but with error message.
Target Element table is
CREATE TABLE ELEM
(
ID INTEGER PRIMARY KEY NOT NULL IDENTITY,
TYP_ID INTEGER NOT NULL,
SPELL VARCHAR(12) NOT NULL,
CONSTRAINT ELEM_TYP_FK FOREIGN KEY (TYP_ID) REFERENCES TYP (ID) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "ELEM_ID_TYP_ID_uindex" ON ELEM (ID, TYP_ID);
CREATE UNIQUE INDEX "ELEM_SPELL_uindex" ON ELEM (SPELL);
As you see, there is an UNIQUE with (ID, TYP_ID)
Current relation table is
CREATE TABLE REL
(
LF_ID INTEGER NOT NULL,
LF_TYP_ID INTEGER NOT NULL,
RT_ID INTEGER NOT NULL,
RT_TYP_ID INTEGER NOT NULL,
TYP_ID INTEGER NOT NULL,
CONSTRAINT REL_LF_ID_LF_TYP_ID_RT_ID_RT_TYP_ID_PK PRIMARY KEY (LF_ID, LF_TYP_ID, RT_ID, RT_TYP_ID)
);
And command to try to relate:
ALTER TABLE REL ADD CONSTRAINT REL_LF_ELEM_TYP_FK FOREIGN KEY (LF_ID, LF_TYP_ID) REFERENCES ELEM (ID, TYP_ID);
Error message just lies:
UNIQUE constraint does not exist on referenced columns: ELEM in
statement [ALTER TABLE REL ADD CONSTRAINT REL_LF_ELEM_TYP_FK FOREIGN
KEY (LF_ID, LF_TYP_ID) REFERENCES ELEM (ID, TYP_ID)]

Related

Duplicate table names in WSO2 API monetization documentation for Postgres DB

I was going through the WSO2 documentation to Monetize an API. In the database configuration section, it has been mentioned that we have to execute the provided database script. If we select Postgres, it displays the script to be executed.
However, all the CREATE TABLE statements have the same table name, even though the sequence names are different. For other databases like MySQL, Oracle, etc, the table names are different as well.
Just to be sure, I even checked with older documentation and it's the same even in older documentation. Script for Postgres database:
CREATE SEQUENCE AM_MONETIZATION START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_POLICY_SUBSCRIPTION (
API_ID INTEGER NOT NULL,
TIER_NAME VARCHAR(512),
STRIPE_PRODUCT_ID VARCHAR(512),
STRIPE_PLAN_ID VARCHAR(512),
FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE
);
CREATE SEQUENCE AM_POLICY_PLAN_MAPPING START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_POLICY_SUBSCRIPTION (
POLICY_ID INTEGER DEFAULT NEXTVAL('AM_POLICY_PLAN_MAPPING'),
POLICY_UUID VARCHAR(256),
PRODUCT_ID VARCHAR(512),
PLAN_ID VARCHAR(512),
FOREIGN KEY (POLICY_UUID) REFERENCES AM_POLICY_SUBSCRIPTION(UUID)
);
CREATE SEQUENCE AM_MONETIZATION_PLATFORM_CUSTOMERS START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_POLICY_SUBSCRIPTION (
POLICY_ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_PLATFORM_CUSTOMERS'),
ID INTEGER NOT NULL AUTO_INCREMENT,
SUBSCRIBER_ID INTEGER NOT NULL,
TENANT_ID INTEGER NOT NULL,
CUSTOMER_ID VARCHAR(256) NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (SUBSCRIBER_ID) REFERENCES AM_SUBSCRIBER(SUBSCRIBER_ID) ON DELETE CASCADE
);
CREATE SEQUENCE AM_MONETIZATION_SHARED_CUSTOMERS START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_POLICY_SUBSCRIPTION (
POLICY_ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_SHARED_CUSTOMERS'),
ID INTEGER NOT NULL AUTO_INCREMENT,
APPLICATION_ID INTEGER NOT NULL,
API_PROVIDER VARCHAR(256) NOT NULL,
TENANT_ID INTEGER NOT NULL,
SHARED_CUSTOMER_ID VARCHAR(256) NOT NULL,
PARENT_CUSTOMER_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (APPLICATION_ID) REFERENCES AM_APPLICATION(APPLICATION_ID) ON DELETE CASCADE,
FOREIGN KEY (PARENT_CUSTOMER_ID) REFERENCES AM_MONETIZATION_PLATFORM_CUSTOMERS(ID) ON DELETE CASCADE
);
CREATE SEQUENCE AM_MONETIZATION_SUBSCRIPTIONS START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_POLICY_SUBSCRIPTION (
POLICY_ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_SUBSCRIPTIONS'),
ID INTEGER NOT NULL AUTO_INCREMENT,
SUBSCRIBED_APPLICATION_ID INTEGER NOT NULL,
SUBSCRIBED_API_ID INTEGER NOT NULL,
TENANT_ID INTEGER NOT NULL,
SUBSCRIPTION_ID VARCHAR(256) NOT NULL,
SHARED_CUSTOMER_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (SUBSCRIBED_APPLICATION_ID) REFERENCES AM_APPLICATION(APPLICATION_ID) ON DELETE CASCADE,
FOREIGN KEY (SUBSCRIBED_API_ID) REFERENCES AM_API(API_ID) ON DELETE CASCADE,
FOREIGN KEY (SHARED_CUSTOMER_ID) REFERENCES AM_MONETIZATION_SHARED_CUSTOMERS(ID) ON DELETE CASCADE
);
I changed the table names based on what is used in MySQL script and created a Monetization policy. While I try to subscribe an API to the monetized policy, I am getting the following error:
ERROR - StripeMonetizationDAO Failed to add Stripe platform customer details for Subscriber : 1
ERROR - APIConsumerImpl Could not execute Workflow
org.wso2.carbon.apimgt.impl.workflow.WorkflowException: Error when inserting stripe customer details of username to Database
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Detail: Failing row contains (3, null, 1, -1234, cus_M7MKkaasfCbdf342SEn).
ERROR - GlobalThrowableMapper Could not execute Workflow
I am not sure if the above errors are due to the table name changes in the script or due to the update in workflow executors. I have added the following in workflow executors:
<SubscriptionCreation executor="<billing-engine-related-SubscriptionCreationWorkflowExecutor>"/>
<SubscriptionDeletion executor="<billing-engine-related-StripeSubscriptionDeletionWorkflowExecutor>"/>
There seems to be several issues with the documented db scripts for postgress and seems like we have missed it. Can you try the following scripts. Please note that i haven't tried it in postgress, but fixed multiple schema issues and this should work.
CREATE TABLE IF NOT EXISTS AM_MONETIZATION (
API_ID INTEGER NOT NULL,
TIER_NAME VARCHAR(512),
STRIPE_PRODUCT_ID VARCHAR(512),
STRIPE_PLAN_ID VARCHAR(512),
FOREIGN KEY (API_ID) REFERENCES AM_API (API_ID) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS AM_POLICY_PLAN_MAPPING (
POLICY_UUID VARCHAR(256),
PRODUCT_ID VARCHAR(512),
PLAN_ID VARCHAR(512),
FOREIGN KEY (POLICY_UUID) REFERENCES AM_POLICY_SUBSCRIPTION(UUID)
);
CREATE SEQUENCE AM_MONETIZATION_PLATFORM_CUSTOMERS_SEQ START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_MONETIZATION_PLATFORM_CUSTOMERS (
ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_PLATFORM_CUSTOMERS_SEQ'),
SUBSCRIBER_ID INTEGER NOT NULL,
TENANT_ID INTEGER NOT NULL,
CUSTOMER_ID VARCHAR(256) NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (SUBSCRIBER_ID) REFERENCES AM_SUBSCRIBER(SUBSCRIBER_ID) ON DELETE CASCADE
);
CREATE SEQUENCE AM_MONETIZATION_SHARED_CUSTOMERS_SEQ START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_MONETIZATION_SHARED_CUSTOMERS (
ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_SHARED_CUSTOMERS_SEQ'),
APPLICATION_ID INTEGER NOT NULL,
API_PROVIDER VARCHAR(256) NOT NULL,
TENANT_ID INTEGER NOT NULL,
SHARED_CUSTOMER_ID VARCHAR(256) NOT NULL,
PARENT_CUSTOMER_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (APPLICATION_ID) REFERENCES AM_APPLICATION(APPLICATION_ID) ON DELETE CASCADE,
FOREIGN KEY (PARENT_CUSTOMER_ID) REFERENCES AM_MONETIZATION_PLATFORM_CUSTOMERS(ID) ON DELETE CASCADE
);
CREATE SEQUENCE AM_MONETIZATION_SUBSCRIPTIONS_SEQ START WITH 1 INCREMENT BY 1;
CREATE TABLE IF NOT EXISTS AM_MONETIZATION_SUBSCRIPTIONS (
ID INTEGER DEFAULT NEXTVAL('AM_MONETIZATION_SUBSCRIPTIONS_SEQ'),
SUBSCRIBED_APPLICATION_ID INTEGER NOT NULL,
SUBSCRIBED_API_ID INTEGER NOT NULL,
TENANT_ID INTEGER NOT NULL,
SUBSCRIPTION_ID VARCHAR(256) NOT NULL,
SHARED_CUSTOMER_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (SUBSCRIBED_APPLICATION_ID) REFERENCES AM_APPLICATION(APPLICATION_ID) ON DELETE CASCADE,
FOREIGN KEY (SUBSCRIBED_API_ID) REFERENCES AM_API(API_ID) ON DELETE CASCADE,
FOREIGN KEY (SHARED_CUSTOMER_ID) REFERENCES AM_MONETIZATION_SHARED_CUSTOMERS(ID) ON DELETE CASCADE
);

Having trouble summing columns in SQL Server joined view

Moi guys, Matt here. I'm having trouble with a relatively complicated view. I have a parts and service table that each have unique identifiers for a given part/service. I'm trying to link these to a service invoice table and subsequent view as a M:N relationship, so I've set up intermediary relational tables, with both the invoice number (invoice primary key) and part/service number (part/service primary key) as the combined primary key. Here's my code for the whole relationship and view:
CREATE TABLE service_invoice
( servinv_Num VARCHAR2(10) CONSTRAINT serv_snum_PK PRIMARY KEY,
servinv_EmpID NUMBER(6) CONSTRAINT serv_empnum_FK REFERENCES employee(empID),
servinv_CustID NUMBER(6) CONSTRAINT serv_custid_FK REFERENCES customer(custID),
servinv_VIN VARCHAR2(25) CONSTRAINT serv_VIN_FK REFERENCES vehicle(vehicle_vin),
servinv_Terms VARCHAR2(6) CONSTRAINT serv_trms_NN NOT NULL,
servinv_Date DATE );
CREATE TABLE Parts
( PartID VARCHAR2(10) CONSTRAINT Part_PartID_PK PRIMARY KEY,
PartDesc VARCHAR2(50) CONSTRAINT Part_PartDesc_NN NOT NULL,
PartCharge NUMBER(4,2) CONSTRAINT Part_PartCharge_NN NOT NULL );
CREATE TABLE Service
( ServiceID VARCHAR2(10) CONSTRAINT Serv_ServID_PK PRIMARY KEY,
ServDesc VARCHAR2(50) CONSTRAINT Serv_ServName_NN NOT NULL,
ServCharge NUMBER(4,2) CONSTRAINT Serv_ServCharge_NN NOT NULL );
CREATE TABLE Serv_SI_Rel
( SI_num VARCHAR2(10) CONSTRAINT ServSI_SInum_FK REFERENCES service_invoice(servinv_Num),
ServiceID VARCHAR2(10) CONSTRAINT ServSI_ServID_FK REFERENCES Service(ServiceID),
CONSTRAINT ServSI_SInum_ServID_PK PRIMARY KEY(SI_num, ServiceID) );
CREATE TABLE Parts_SI_Rel
( SI_num VARCHAR2(10) CONSTRAINT PartSI_SInum_FK REFERENCES service_invoice(servinv_Num),
PartID VARCHAR2(10) CONSTRAINT PartSI_PartID_FK REFERENCES Parts(PartID),
CONSTRAINT PartSI_SInum_PartID_PK PRIMARY KEY(SI_num, PartID) );
CREATE OR REPLACE VIEW ServiceInvoiceDoc
AS
(
SELECT si.servinv_Num, si.servinv_Date, si.servinv_Terms,
es.empName,
sc.custName, sc.custHouse, sc.custCity,
sc.custState, sc.custZIP, sc.custPhone, sc.custEmail,
sv.vehicle_VIN, sv.vehicle_mileage,
srel.ServiceID,
prel.PartID,
s.ServDesc, s.ServCharge,
p.PartDesc, p.PartCharge,
SUM(s.ServCharge) TotalServCharges,
SUM(p.PartCharge) TotalPartsCharges,
( SUM(s.ServCharge)+SUM(p.PartCharge) ) SubTotalCharges,
( SUM(s.ServCharge)+SUM(p.PartCharge) )*0.0825 Taxes,
( SUM(s.ServCharge)+SUM(p.PartCharge) )*1.0825 TotalCharges
FROM service_invoice si
JOIN employee es
ON (es.empID = si.servinv_EmpID)
JOIN customer sc
ON (sc.custID = si.servinv_CustID)
JOIN vehicle sv
ON (sv.vehicle_VIN = si.servinv_VIN)
LEFT OUTER JOIN Serv_SI_Rel srel
ON (srel.SI_Num = si.servinv_Num)
LEFT OUTER JOIN Parts_SI_Rel prel
ON (prel.SI_num = si.servinv_Num)
JOIN Parts p
ON (prel.PartID = p.PartID)
JOIN Service s
ON (srel.ServiceID = s.ServiceID) );
The error I get has to do with summing the individual parts and service charges in the M:N relationship. Here's the error code from the run:
ORA-00937: not a single-group group function
I've tried fixing with a group by command, but the grouping identifier (service invoice) isn't included on the part or service tables, and the joins don't seem to link these up for a group. e.g. I tried calling GROUP BY si.servinv_Num
Can this be resolved at all or is it completely wrong? I have the option of dropping the M:N relationship as a 1:M and simply making a separate invoice for each part/service charge, but I would prefer to keep it compact and professional.
Any help would be greatly appreciated. Thank you so much for your time!
a) wrong tag
b) I'd imagine you would need to list all columns in group by clause that aren't aggregated, as per Oracle
...
group by si.servinv_Num, si.servinv_Date, si.servinv_Terms,
es.empName,
sc.custName, sc.custHouse, sc.custCity,
sc.custState, sc.custZIP, sc.custPhone, sc.custEmail,
sv.vehicle_VIN, sv.vehicle_mileage,
srel.ServiceID,
prel.PartID,
s.ServDesc, s.ServCharge,
p.PartDesc, p.PartCharge

PSQL asking for Unique constraint?

So I am trying to create the following tables and psql will not let me create these tables unless C_Subject is given a UNIQUE constraint in the Curriculum_Subjects table.
CREATE TABLE IF NOT EXISTS Curriculum(
CID SERIAL NOT NULL,
Curriculum_Name VARCHAR(100),
Classes_Needed INTEGER,
Classes_Total INTEGER,
PRIMARY KEY(CID)
);
CREATE TABLE IF NOT EXISTS Class_Subjects(
C_Subject SERIAL NOT NULL,
Class_Subject VARCHAR(100),
PRIMARY KEY(C_Subject)
);
CREATE TABLE IF NOT EXISTS Curriculum_Subjects(
C_Subject SERIAL UNIQUE NOT NULL REFERENCES Class_Subjects(C_Subject),
CID SERIAL NOT NULL REFERENCES Curriculum(CID),
PRIMARY KEY(C_Subject, CID)
);
However the way I want my database to work is that one C_Subject can be in many curriculum. So below inserting the same C_Subject into two different curriculum should be valid. CID being the identifier for a different curriculum.
INSERT INTO Curriculum_Subjects(C_Subject, CID)
VALUES(2,1);
INSERT INTO Curriculum_Subjects(C_Subject, CID)
VALUES(2,2);
psql won't let this insert happen because C_Subject has a UNIQUE constraint. Why does C_Subject need to be UNIQUE in Curriculum_Subjects if it belongs to the composite key, PRIMARY KEY(C_Subject, CID) ? Can this insert be achievable?

How to update and set unit_id to be NULL, unit id is foreign key from unit table

How to update and set unit_id to be NULL, unit id is foreign key and I need to set to be NULL
CREATE TABLE troops
(
id serial NOT NULL,
unit_id integer,
type integer NOT NULL,
level integer NOT NULL,
CONSTRAINT troops_pkey PRIMARY KEY (id),
CONSTRAINT troops_unit_id_fkey FOREIGN KEY (unit_id)
REFERENCES units (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
I have tried to update troops and set unit_id to be NULL ( I put NULL not 0 in pqxx statement in C++ ) but I get error like
insert or update on table "troops" violates foreign key constraint "troops_unit_id_fkey"
DETAIL: Key (unit_id)=(0) is not present in table "units".
When I try from pgadmin I can set unit_id to be NULL in troops but pqxx ( from c++ code I try to update) converts NULL to 0, how to solve this ?

sql Column with multiple values (query implementation in a cpp file )

I am using this link.
I have connected my cpp file with Eclipse to my Database with 3 tables (two simple tables
Person and Item
and a third one PersonItem that connects them). In the third table I use one simple primary and then two foreign keys like that:
CREATE TABLE PersonsItems(PersonsItemsId int not null auto_increment primary key,
Person_Id int not null,
Item_id int not null,
constraint fk_Person_id foreign key (Person_Id) references Person(PersonId),
constraint fk_Item_id foreign key (Item_id) references Items(ItemId));
So, then with embedded sql in c I want a Person to have multiple items.
My code:
mysql_query(connection, \
"INSERT INTO PersonsItems(PersonsItemsId, Person_Id, Item_id) VALUES (1,1,5), (1,1,8);");
printf("%ld PersonsItems Row(s) Updated!\n", (long) mysql_affected_rows(connection));
//SELECT newly inserted record.
mysql_query(connection, \
"SELECT Order_id FROM PersonsItems");
//Resource struct with rows of returned data.
resource = mysql_use_result(connection);
// Fetch multiple results
while((result = mysql_fetch_row(resource))) {
printf("%s %s\n",result[0], result[1]);
}
My result is
-1 PersonsItems Row(s) Updated!
5
but with VALUES (1,1,5), (1,1,8);
I would like that to be
-1 PersonsItems Row(s) Updated!
5 8
Can somone tell me why is this not happening?
Kind regards.
I suspect this is because your first insert is failing with the following error:
Duplicate entry '1' for key 'PRIMARY'
Because you are trying to insert 1 twice into the PersonsItemsId which is the primary key so has to be unique (it is also auto_increment so there is no need to specify a value at all);
This is why rows affected is -1, and why in this line:
printf("%s %s\n",result[0], result[1]);
you are only seeing 5 because the first statement failed after the values (1,1,5) had already been inserted, so there is still one row of data in the table.
I think to get the behaviour you are expecting you need to use the ON DUPLICATE KEY UPDATE syntax:
INSERT INTO PersonsItems(PersonsItemsId, Person_Id, order_id)
VALUES (1,1,5), (1,1,8)
ON DUPLICATE KEY UPDATE Person_id = VALUES(person_Id), Order_ID = VALUES(Order_ID);
Example on SQL Fiddle
Or do not specify the value for personsItemsID and let auto_increment do its thing:
INSERT INTO PersonsItems( Person_Id, order_id)
VALUES (1,5), (1,8);
Example on SQL Fiddle
I think you have a typo or mistake in your two queries.
You are inserting "PersonsItemsId, Person_Id, Item_id"
INSERT INTO PersonsItems(PersonsItemsId, Person_Id, Item_id) VALUES (1,1,5), (1,1,8)
and then your select statement selects "Order_id".
SELECT Order_id FROM PersonsItems
In order to achieve 5, 8 as you request, your second query needs to be:
SELECT Item_id FROM PersonsItems
Edit to add:
Your primary key is autoincrement so you don't need to pass it to your insert statement (in fact it will error as you pass 1 twice).
You only need to insert your other columns:
INSERT INTO PersonsItems(Person_Id, Item_id) VALUES (1,5), (1,8)