I am working with MySQL I have made a table which have a TIMESTAMP column, which add current time and date to each row added. But I don't know how to initialize it when I insert data to that table. My SQL Queries are :
TABLE
"CREATE TABLE IF NOT EXISTS messages ( mess_id int PRIMARY KEY AUTO_INCREMENT, mess_from int, mess_to int, mess_txt VARCHAR(20000), mess_time TIMESTAMP, FOREIGN KEY (mess_from) REFERENCES users(id),FOREIGN KEY (mess_to) REFERENCES users(id) )"
INSERTION
"INSERT INTO user_messages (NULL,'"+data.from+"','"+data.to+"','"+data.text+"',DEFAULT)"
The problem is, I don't know how to initialize the timestamp column, I tried NULL and DEFAULT but both show me this error of invalid syntax. I want the timestamp field to be initialized automatically! That's it.
On the table creation, set the default on the timestamp column to CURRENT_TIMESTAMP.
CREATE TABLE IF NOT EXISTS messages (
mess_id int PRIMARY KEY AUTO_INCREMENT,
mess_from int,
mess_to int,
mess_txt VARCHAR(20000),
mess_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (mess_from) REFERENCES users(id),FOREIGN KEY (mess_to) REFERENCES users(id) )
EDIT:
For completeness, this will set the mess_time field to the current timestamp when a new record is inserted and does not contain an explicit value for that field. It will have no effect when an UPDATE on that row occurs. You can set it so that on every update the timestamp will be set to the current timestamp using "ON UPDATE CURRENT_TIMESTAMP"
CREATE TABLE IF NOT EXISTS messages (
mess_id int PRIMARY KEY AUTO_INCREMENT,
mess_from int,
mess_to int,
mess_txt VARCHAR(20000),
mess_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (mess_from) REFERENCES users(id),FOREIGN KEY (mess_to) REFERENCES users(id) )
When doing the INSERT, do not specify the timestamp column:
INSERT INTO user_messages (mess_from,mess_to, mess_text) VALUES (#FromValue,#ToValue,#TextValue)
(The above will work in all cases. There is a system variable that controls whether you can use NULL to insert the current_timestamp. This is not standard and less compatible with other SQL engines, so it is often set to standards mode.
The variable is explicit_defaults_for_timestamp, but it has been deprecated, and these non-standard behaviors are set to be removed in future mysql versions, so I would not recommend using it.)
Try the following:
INSERT INTO user_messages (NULL, '"+data.from+"', '"+data.to+"', '"+data.text+"', now());
Related
I have written an application in Javascript which inserts data into two tables via a connection to a MariaDB server.
There should be a 1:1 correspondance between the rows in these tables when first running the application.
One table stores (simulated) data about properties, the other table stores data about prices. There should be 1 price for each property. At a later date, the price might change, so there could be more than one entry for the price, but this cannot happen when the application is first run. These entries also cannot be in violation of a unique index - but they are.
Perhaps I have misconfigured something in MariaDB? Here is the code which generates the tables.
drop table if exists property_price;
drop table if exists property;
create table property
(
unique_id bigint unsigned not null auto_increment primary key,
web_id bigint unsigned not null,
url varchar(256),
street_address varchar(256),
address_country varchar(64),
property_type varchar(64),
num_bedrooms int,
num_bathrooms int,
created_datetime datetime not null,
modified_datetime datetime not null
);
create table property_price
(
property_unique_id bigint unsigned not null,
price_value decimal(19,2) not null,
price_currency varchar(64) not null,
price_qualifier varchar(64),
added_reduced_ind varchar(64),
added_reduced_date date,
created_datetime datetime not null
);
alter table property_price
add constraint fk_property_unique_id foreign key(property_unique_id)
references property(unique_id);
alter table property
add constraint ui_property_web_id
unique (web_id);
alter table property
add constraint ui_url
unique (url);
alter table property_price
add constraint ui_property_price
unique (property_unique_id, price_value, price_currency, price_qualifier, added_reduced_ind, added_reduced_date);
Below is a screenshot from DBeaver showing that a select statement returns two identical rows.
I don't understand why the unique constraint appears to be violated. The constraint does sometimes work, because if I run my application again, it fails because it attempts to insert a duplicate row which already exists in the DB. (Not the same as the one shown below.)
Can anyone point me in the right direction as to how I might debug this?
MariaDB permits multiple values on columns which form part of a unique constraint.
My solution would be to put the logic for checking for duplicate rows into the application, rather than this being on the database side. Essentially this means the unique constraint is not being used.
I have a table that needs a unique constraint on 3 columns, but, if the "date" column in for that insert transaction is a newer date than the current record's date, then I want to update that record (so the unique constraint is still true for the table).
Postgres has the concept of deferrable constraints, MySQL does not.
I do want to implement it with the SQL object tools available, though.
Here is my table DDL with column names obfuscated:
CREATE TABLE `apixio_results_test_sefath` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`number` varchar(20) DEFAULT NULL,
`insert_date` datetime DEFAULT NULL,
`item_id` int(5) DEFAULT NULL,
`rule` tinyint(4) DEFAULT NULL,
`another_column` varchar(20) DEFAULT NULL,
`another_column1` varchar(20) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `insert_date_index` (`insert_date`),
KEY `number` (`number`),
) ENGINE=InnoDB AUTO_INCREMENT=627393 DEFAULT CHARSET=latin1
and here is the unique constraint statement
Alter Table dbname.table add unique constraint my_unique_constraint (number, item_id, rule);
but I can not add a condition here in this constraint (unless there is a way I'm not aware of?)
The logic I need to run before inserts are blocked by the constraint is to check if the three values: number, item_id, and rule are unique in the table, and if they aren't, then I want to compare the existing record's insert_date with the insert_date from the transaction, and only keep the record with the newest insert_date.
This could be achieved with a trigger I suppose, although I've heard triggers are only to be used if really needed. And on every insert, this trigger would be quite computationally taxing on the DB. Any advice? Any other sql tricks I can use? Or anything to help point me to how to make this trigger?
I tried the unique constraint statement
Alter Table dbname.table add unique constraint my_unique_constraint (number, item_id, rule);
But it will never update with the newer insert_date.
You can do this with an insert statement like:
insert into apixio_results_test_sefath (number, item_id, rule, insert_date, another_column, another_column1)
values (?,?,?,?,?,?)
on duplicate key update
another_column=if(insert_date>values(insert_date),another_column,values(another_column),
another_column1=if(insert_date>values(insert_date),another_column1,values(another_column1),
insert_date=greatest(insert_date,values(insert_date)
for each column besides the unique ones and insert_date, testing to see if the existing insert_date is greater than the value supplied with the insert and conditionally using the existing value or new value for the other column based on that, and ending with updating insert_date only if it is now greater.
mysql 8 has an alternate syntax it prefers to using the values function, but the values function still works.
If you want this to happen automatically for all inserts, you would need to use a trigger.
So I have this table
create table c_order(
order_date date not null,
order_id number,
customer_id number not null,
product_id number not null,
primary key (order_id),
foreign key (customer_id) references Customer(customer_id),
foreign key (product_id) references products(product_id)
);
where customers order for a product.
Now I want it be such that when a data is entered using 'Insert into' then we need not insert the date rather it will be automatically saved to current data. Should I change create table structure for that or use a trigger? What is the syntax then? In trigger is it before/after insert?
https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html
create table c_order(
order_date TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP,
order_id number,
customer_id number not null,
product_id number not null,
primary key (order_id),
foreign key (customer_id) references Customer(customer_id),
foreign key (product_id) references products(product_id)
);
I found my own answer..
Default is not going to work here since the data type is date and functions cannot be used for putting default values in date datatype (for timestamp it can be done).
The answer is trigger. The code is (for oracle.. for mysql sysdate() should be changed to now() )
CREATE or REPLACE TRIGGER auto_insert_date BEFORE INSERT ON c_order
FOR EACH ROW
begin
:NEW.order_date := sysdate();
end;
The MySQL documentation states that when using INSERT ... ON DUPLICATE KEY UPDATE, the affected-rows value will be 1 when a record was inserted, 2 if an existing record was updated.
We're getting an affected-rows value of 3 when a record is updated, although I'm only seeing this when the updates are performed via MySQL calls using Connector-J from Java; when I invoke the stored procedure from the MySQL Workbench, I get the expected result of 2 rows updated.
Does anyone have any idea what this might mean? Is this perhaps a Connector-J annomaly? I'd be inclined to just run with it, but without a reasonable explanation, I'm left with concerns for my data integrity (which is, after all, one of the reasons to check the affected-rows value).
MySQL server version: 5.1.57; Connector-J version: 5.1.7 (Java 1.6)
Additional details:
This is the table being modified:
CREATE TABLE `UserContactProperty` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`UserContactId` int(11) NOT NULL,
`Property` varchar(45) NOT NULL,
`Value` tinytext,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `Contact-Property` (`UserContactId`,`Property`),
KEY `FK_UserContact` (`UserContactId`),
CONSTRAINT `FK_UserContact` FOREIGN KEY (`UserContactId`) REFERENCES `UserContact` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=28685 DEFAULT CHARSET=latin1
The stored procedure performing the insert/update is as follows:
CREATE PROCEDURE `setUserContactProperty`(
UID VARCHAR(50),
CID INT,
Prop VARCHAR(45),
Val TINYTEXT
)
BEGIN
INSERT INTO UserContactProperty ( UserContactId, Property, Value )
VALUES ( CID, Prop, Val )
ON DUPLICATE KEY UPDATE Value = Val, Date = CURRENT_TIMESTAMP;
END
It seems as a bug. please check the following link:
http://bugs.mysql.com/bug.php?id=46675
As reported there, the bug is related to another bug where the generated key list is wrong and the count is wrong too. (the second bug originated from here http://slava-technical.blogspot.co.il/2011/05/mysql-on-duplicate-key-update-breaks.html)
I think you need to find a workaround. probably by querying the database prior to inserting to see if the row with this key exists or not. or insert and catch duplicate key exception and then make the update in that case.
I have two tables. On is a table that contains IP Ranges and their respective country attributions (IPGEO table). The other is a table which simply keeps track of the last country the site was accessed from on a per user basis. The idea is that, if the user suddenly accesses the site from another country, I notify the user about this via email.
Now for the actual tables. I have these two:
The IPGeo table that contains the IP ranges
CREATE TABLE IF NOT EXISTS `politiker_lu`.`IPGeo` (
`IPFrom` INT(11) NOT NULL ,
`IPTo` INT(11) NOT NULL ,
`code2` VARCHAR(2) NOT NULL ,
`code3` VARCHAR(3) NOT NULL ,
`Country` VARCHAR(45) NOT NULL ,
INDEX `index1` (`IPFrom` ASC) ,
INDEX `index2` (`IPTo` ASC) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
Then, there is the user_geo table that tracks the last country from which the user accessed the site.
CREATE TABLE IF NOT EXISTS `politiker_lu`.`user_geo` (
`fi_user` INT(10) UNSIGNED NOT NULL ,
`fi_country` VARCHAR(3) NOT NULL ,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
PRIMARY KEY (`fi_user`) ,
INDEX `fk_user_geo_1` (`fi_user` ASC) ,
CONSTRAINT `fk_user_geo_1`
FOREIGN KEY (`fi_user` )
REFERENCES `politiker_lu`.`user` (`id_user` )
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
These are the tables as they exist. I now want to reference these two tables as follows:
ALTER TABLE `politiker_lu`.`user_geo`
ADD CONSTRAINT `fk_user_geo_IPGeo1`
FOREIGN KEY (`fi_country` )
REFERENCES `politiker_lu`.`IPGeo` (`code3` )
ON DELETE CASCADE
ON UPDATE CASCADE
, ADD INDEX `fk_user_geo_IPGeo1` (`fi_country` ASC) ;
That Statement however fails with errno 150. Both tables are utf8, both columns have the same data-type. Am I missing something vital here?
Notes
The table user exists and has all the references and is actually irrelevant to the problem. I left it so that I didn't need to edit the statement too much.
You need to add a unique index or a primary key on the IPGeo.code3 column in order to reference it with a foreign key.
You can see the error by running show engine innodb status\G and looking under the LATEST FOREIGN KEY ERROR section. The error probably looks something like this:
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
for correct foreign key definition.