I've two tables that has defined as below; From user table, hospitalId and poliklinikId both references table relhospol, and if any row is deleted from relhospol, (if any user is related with it), I want to set the hospitalId and poliklinikId null, DDL says that. When i delete a row from SQLite Manager it nulls the User's hospitalId and PoliklinikId, However when i try to remove a row from application level (Java), it only removes from relhospol, it does not set null (hospitalId, PoliklinikId) What is the missing point ?
JDBC Driver: SQLite-jdbc-3.7.2
CREATE TABLE [USER] (
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[GROUPID] INTEGER CONSTRAINT [FK_USER_GID] REFERENCES [GROUP]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[HOSPITALID] INTEGER,
[POLIKLINIKID] INTEGER,
[NAME] VARCHAR(50) NOT NULL,
[LOGINID] VARCHAR(15) NOT NULL,
[EMAIL] VARCHAR(50) NOT NULL,
[PASSWORD] VARCHAR(32) NOT NULL,
CONSTRAINT [FK_USER_RELHOSPOL] FOREIGN KEY([HOSPITALID], [POLIKLINIKID]) REFERENCES [RELHOSPOL]([HOSPITALID], [POLIKLINIKID]) ON DELETE SET NULL ON UPDATE CASCADE);
CREATE UNIQUE INDEX [AS] ON [USER] ([LOGINID]);
CREATE UNIQUE INDEX [AS1] ON [USER] ([EMAIL]));
CREATE TABLE [RELHOSPOL] (
[HOSPITALID] INTEGER CONSTRAINT [FK_RELHOSPOL_HOS] REFERENCES [HOSPITAL]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[POLIKLINIKID] INTEGER CONSTRAINT [FK_RELHOSPOL_POL] REFERENCES [POLIKLINIK]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT [sqlite_autoindex_RELHOSPOL_1] PRIMARY KEY ([HOSPITALID], [POLIKLINIKID]));
You can't set NULL a primary key:
CREATE TABLE [RELHOSPOL] (
[HOSPITALID] INTEGER CONSTRAINT [FK_RELHOSPOL_HOS] REFERENCES [HOSPITAL]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[POLIKLINIKID] INTEGER CONSTRAINT [FK_RELHOSPOL_POL] REFERENCES [POLIKLINIK]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT [sqlite_autoindex_RELHOSPOL_1] PRIMARY KEY ([HOSPITALID], [POLIKLINIKID]));
You are trying to remove a row from which table? Can you post the DELETE SQL?
Ok I've changed the RELHOSPOL's definition as below; When i delete row from RELHOSPOL from the SQL Manager with executing a DELETE command, it nulls the necessary rows at the USER table. Whenever I delete a row from application with the method written below, it only deletes row from RELHOSPOL, and does not SET NULL the necessary rows at USER table
CREATE TABLE [RELHOSPOL] (
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[HOSPITALID] INTEGER,
[POLIKLINIKID] INTEGER);
CREATE UNIQUE INDEX [UNIQUE_RELHOSPOL] ON [RELHOSPOL] ([HOSPITALID], [POLIKLINIKID]);
Delete Method is :
public void deletePoliklinikFromHospital(int hospitalId, int poliklinikId) throws SQLException{
String query = "DELETE FROM [RELHOSPOL] WHERE (HOSPITALID = ? AND POLIKLINIKID = ?)";
try {
PreparedStatement statement = db.prepareStatement(query);
statement.setInt(1, hospitalId);
statement.setInt(2, poliklinikId);
statement.executeUpdate();
} catch (SQLException e) {
throw new SQLException(e.getMessage());
}
}
It is just a guess, but maybe you are not aware, that you have to enable foreign key support with PRAGMA foreign_keys = ON; everytime you connect to the database? If this is not done, your statements will be parsed, but not enforced. This could explain, why it is working from SQLite Manager.
One should also be aware, that old versions of Sqlite (<3.6.19) will tolerate the syntax but too will not enforce anything.
As sidenote:
As #Neuquino writes the ON DELETE SET NULL statements for table RELHOSPOL don't seem to make sense.
Related
Here is my tables definition
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_name` VARCHAR(1024) NOT NULL,
`store_user` INT NOT NULL,
`store_address` INT NOT NULL,
`store_type` INT NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`store_id`)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
`address_line_1` VARCHAR(1024) NOT NULL,
`address_line_2` VARCHAR(1024) NOT NULL,
`address_line_3` VARCHAR(1024) NULL,
`city` VARCHAR(45) NOT NULL,
`locality` VARCHAR(100) NOT NULL,
`pincode` CHAR(6) NOT NULL,
`latitude` DECIMAL(8,6) NULL,
`longitude` DECIMAL(9,6) NULL,
`state` VARCHAR(45) NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`address_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`address_id`)
REFERENCES `store` (`store_address`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I am trying to have a 1-1 mapping between store and its address. Considering the DDL is ok, while generating JPA entities Store.java look like this:
#Entity
#Table(name="store")
public class Store
{
#Basic
#Column(name="created_date", nullable=false)
private Date createdDate;
#OneToOne(fetch=FetchType.LAZY, mappedBy="store", cascade=CascadeType.MERGE)
private StoreAddress storeAddress;
#Basic
#Column(name="store_address", columnDefinition="INT")
private int storeAddress2;
/////
Why is there a field storeAddress2 in Store.java? I think this is failing my insertion of a store. Any help?
Considering the DDL is ok [...]
The DDL is not OK, it is erroneous. As the tables are presently structured, the foreign key constraint is backward. store_address.address_id is the referenced key; the constrained column -- that is, the foreign key column -- should be store.store_address.
Moreover, be aware that putting the address into its own table and establishing a NOT NULL foreign key referencing it means that every store must have an address recorded, yet a store address does not have to correspond to any store. If you want the address to be optional then make store.store_address nullable, though that still permits addresses to exist that do not correspond to a store.
Alternatively, even though JPA prefers a forward mapping from parent to child such as you have presented, it is possible to map it in the other direction, so that store addresses cannot exist in the DB without a corresponding store, but stores do not have to have addresses recorded. In the DDL, that would correspond to deleting store.store_address, and creating store_address.store_id as a foreign key referencing store.store_id.
Update:
Here is some DDL to clarify my comments about the FK constraint. This is how an FK relationship between store and store_address should be written, given the column definitions as presented in the question:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_address` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_address`)
REFERENCES `store_address` (`address_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
-- ...
PRIMARY KEY (`address_id`)
-- the FK constraint does NOT go here
)
ENGINE = InnoDB;
Note also that as I already wrote, this does not enforce a 1-1 relationship in the DB. If you want that then you could put a UNIQUE constraint on store.store_address, but it might be better to instead link the PKs of store and store_address. That way you can also prevent orphan store_address rows from being allowed. That could look like this:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
-- ... no store_address ...
PRIMARY KEY (`store_id`)
-- ... no FK constraint here ...
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
-- addresses do not have independent IDs:
`store_id` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_id`)
REFERENCES `store` (`store_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
That does permit a store to exist without a corresponding address, which may be sensible, even though you say you don't want that.
Really, though, if a store must not exist without exactly one corresponding address, and a store address must not exist without a store, then why are you mapping these as separate tables? It gains you nothing except, maybe, less manual adjustment to automatically-generated entity classes. It's definitely a loss in the performance and DB complexity arenas.
Note, too, that JPA has annotations for mapping two closely-associated entities to the same table, if you insist that the addresses should be separate entities from their associated stores. Look into the #Embeddable and related annotations.
I am working on a Spring-MVC application for which we are planning to create API's which can be consumed by external users into their own platform. To do so, the user must create an 'app' on our platform and then the accesstoken can be retrieved which can be used to access data by user, and make modifications to it.
Now, to do so, what I am doing is, I have created a table called as 'appdetails'. The user has to authorize the app, by passing in client-id, secret and I am returning an access-token, which can be used to directly work on data-set of the user who owns the app.
But doing a check everytime if the object being requested, belongs to the owner of app is proving more database calls for each request. How can I effectively minimize these calls. Here is how the database looks like. Please note, I am only putting relevant fields and I am using PostgreSQL. Explanation below image.
So, now when an user wants to access/POST a canvas object. I am receiving the canvas object and the access-token. But now I have to verify, if the groupid to which it has to be associated is the same as what the app-owner is admin for. More calls are required in Section, note. Here is the SQL code if anyone wants.
CREATE TABLE appDetails (
appid NUMERIC NOT NULL,
clientsecret VARCHAR NOT NULL,
clientid VARCHAR NOT NULL,
accesstoken VARCHAR NOT NULL,
CONSTRAINT appid PRIMARY KEY (appid)
);
CREATE TABLE person (
id INTEGER NOT NULL,
email VARCHAR NOT NULL,
appid NUMERIC NOT NULL,
CONSTRAINT id PRIMARY KEY (id)
);
CREATE TABLE groupaccount (
groupid INTEGER NOT NULL,
groupname VARCHAR NOT NULL,
id INTEGER NOT NULL,
CONSTRAINT groupid PRIMARY KEY (groupid)
);
CREATE TABLE groupmembers (
memberid INTEGER NOT NULL,
groupid INTEGER NOT NULL,
CONSTRAINT memberid PRIMARY KEY (memberid, groupid)
);
CREATE TABLE canvas (
canvasid VARCHAR NOT NULL,
groupid INTEGER NOT NULL,
memberid INTEGER NOT NULL,
CONSTRAINT canvasid PRIMARY KEY (canvasid)
);
CREATE TABLE section (
sectionid VARCHAR NOT NULL,
canvasid VARCHAR NOT NULL,
CONSTRAINT sectionid PRIMARY KEY (sectionid)
);
CREATE TABLE note (
noteid VARCHAR NOT NULL,
sectionid VARCHAR NOT NULL,
CONSTRAINT noteid PRIMARY KEY (noteid)
);
ALTER TABLE person ADD CONSTRAINT appDetails_person_fk
FOREIGN KEY (appid)
REFERENCES appDetails (appid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE groupaccount ADD CONSTRAINT person_groupaccount_fk
FOREIGN KEY (id)
REFERENCES person (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE groupmembers ADD CONSTRAINT groupaccount_groupmembers_fk
FOREIGN KEY (groupid)
REFERENCES groupaccount (groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE canvas ADD CONSTRAINT groupaccount_canvas_fk
FOREIGN KEY (groupid)
REFERENCES groupaccount (groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE canvas ADD CONSTRAINT groupmembers_canvas_fk
FOREIGN KEY (memberid, groupid)
REFERENCES groupmembers (memberid, groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE section ADD CONSTRAINT canvas_section_fk
FOREIGN KEY (canvasid)
REFERENCES canvas (canvasid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE note ADD CONSTRAINT section_note_fk
FOREIGN KEY (sectionid)
REFERENCES section (sectionid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
Also, are there any technologies I can use to maintain Rate of consumption of API. The simplest I could think of was adding a counter in appdetails. I hope the question is clear, if not, kindly let me know. I will explain further.
I was trying to create a new object and this error appeared:
java.sql.sqlexception failed to read auto-increment value from storage engine
So I went to the phpMyAdmin to create the object there and the same showed up:
MySQL said: Documentation
1467 - Failed to read auto-increment value from storage engine
then I clicked on edit, and it was there:
INSERT INTO `reservation`.`room` (`idroom`, `number`, `floor`, `description`, `characteristics`, `cost`, `status`, `type`) VALUES (NULL, '114', '3', 'ss', 'ss', '550.00', 'Available', 'ss')
(idroom is supposed to be auto-incremented.)
I already read other posts where they say I have to put this:
ALTER TABLE `table_name` AUTO_INCREMENT = 1
but I have no idea where to put that. Is there a better solution?
Your INSERT statement is wrong. Since idroom is AUTO_INCREMENT; you must not include it in the column list on your insert command. Your insert statement should look like below. Notice that I have removed idroom column from insert column list and not passing NULL as well in value list.
INSERT INTO `reservation`.`room` (`number`, `floor`, `description`,
`characteristics`, `cost`, `status`, `type`)
VALUES ('114', '3', 'ss', 'ss', '550.00', 'Available', 'ss')
I also struggled with this problem and searched, and didn't find anything. Then the following worked for me; I guess it might work for your problem. Thx.
1st:
-delete (before backup)->all data from your database.
-try to run your Java program again, or any program you want.
If it fails then go to 2nd.
2nd:
- backup all data from your table
- delete table completely
- create table again; example shown below:
CREATE TABLE `users` (
`id` int(6) NOT NULL,
`f_name` varchar(30) NOT NULL,
`l_name` varchar(30) NOT NULL,
`address` varchar(50) DEFAULT NULL,
`phone_num` varchar(12) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL
);
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
AUTO_INCREMENT for table `users`
ALTER TABLE `users`
MODIFY `id` int(6) NOT NULL AUTO_INCREMENT;
I am using java DB database and NetBeans 8.0 for a desktop application
I am also using a PreparedStatement to query the database.
below is the code for creating the tables.
CREATE TABLE ALUMNUS (
ALUMNUA_ID INT NOT NULL PRIMARY KEY
GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
FIRST_NAME VARCHAR (45),
LAST_NAME VARCHAR (45),
OTHER_NAME VARCHAR (100)
);
CREATE TABLE DUES (
ID INT NOT NULL PRIMARY KEY
GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
PAYMENT_YEAR DATE,
AMOUNT DOUBLE,
ALUMNUS_ID INT
);
--FOREIGN KEY
ALTER TABLE APP.DUES
ADD FOREIGN KEY (ALUMNUS_ID) REFERENCES APP.ALUMNUS(ID);
Now I want to insert, delete and update the foreign key values in APP.DUES table. what is the best option; trigger , stored procedure or the preparedstatement?
An example will be good.
If you want to primarily insert into the DUES table, you would use a sub select in SQL. I havent tested it with Java DB, but it basically looks like:
INSERT INTO DUES(PAYMENT_YEAR, AMOUNT,ALUMNUS_ID)
VALUES(2014, 100.0,
(SELECT ALUMNUA_ID from ALUMNUS where ...));
You need to catch the "not found" error case and prepend a INSERT (and need to catch the duplicate case for that as well).
See also: Insert Data Into Tables Linked by Foreign Key
I have 2 tables Customers & Accounts in my Oracle Database. I have sequence numbers for generating surrogate key values for both tables.
CREATE SEQUENCE customers_seq NOCACHE;
CREATE SEQUENCE accounts_seq NOCACHE;
CREATE TABLE customers
(
customer_surrogate_id NUMBER(10),
customer_id VARCHAR2(8) UNIQUE NOT NULL,
customer_password VARCHAR2(20),
customer_name VARCHAR2(20),
customer_pan VARCHAR2(10) UNIQUE,
customer_email_id VARCHAR2(20) UNIQUE,
CONSTRAINT customer_pk
PRIMARY KEY (customer_surrogate_id)
);
CREATE TABLE accounts
(
accounts_surrogate_id NUMBER(10),
account_id VARCHAR2(10) UNIQUE NOT NULL,
customer_surrogate_id NUMBER(10),
account_type VARCHAR2(10),
account_currency VARCHAR2(20),
account_balance NUMBER(20, 2),
CONSTRAINT accounts_pk
PRIMARY KEY (accounts_surrogate_id),
CONSTRAINT accounts_fk
FOREIGN KEY (customer_surrogate_id)
REFERENCES customers(customer_surrogate_id)
);
I know how to use sequence_name.NEXTVAL & sequence_name.CURRVAL in insert statements to perform the reference
The problem is with using NEXTVAL & CURRVAL is that it assumes that inserts to both tables occur sequentially like
insert into Customers(// use NEXTVAL here)
insert into Accounts(// use CURRVAL here to reference the above row in Customers)
But in my java application, the multiple inserts for the Customers table can occur before even one insert occurs in Accounts table. CURRVAL will return the value of the last inserted row of the Customers table.
When inserting a row into Accounts table, I can get customers_id values in my application. Should the customer_id be used to query the Customers table to get the customer_surrogate_id as shown below?
insert into Customers(// use NEXTVAL here)
...
insert into Accounts(// use the customer_id to query and find customer_surrogate_id)
Is there better way to reference the Customers table in this situation?
Edit: I am using JDBC to access the database.
Simply select the value, and store it in a variable:
long customer1Id = selectNextValueFromSequence("customers_seq");
long customer2Id = selectNextValueFromSequence("customers_seq");
insertCustomerWithId(customer1Id);
insertCustomerWithId(customer2Id);
insertAccountWithCustomerId(customer1Id);
insertAccountWithCustomerId(customer2Id);