Mysql - Unique constraint on CAST(TIMESTAMP as DATE) - mysql

I have a TIMESTAMP myDate field in my MYSQL Table.
Is there a way I can define a unique string stringForTheDay for every day in myDate?
Something like:
UNIQUE(stringForTheDay, day_in_mydate)
In short, these 2 rows must not be allowed:
2012-11-29 13:35:53 samestring
2012-11-29 20:39:09 samestring

I think your best bet is to copy the date-part into a separate column, and add a unique constraint on it. You can keep the date-part up-to-date by using triggers:
CREATE TRIGGER ins_tablename BEFORE INSERT ON tablename
FOR EACH ROW SET NEW.dateColumn = CAST(NEW.timestampColumn AS DATE);
CREATE TRIGGER upd_tablename BEFORE UPDATE ON tablename
FOR EACH ROW SET NEW.dateColumn = CAST(NEW.timestampColumn AS DATE);
(See ยง18.3 "Using Triggers" in the MySQL 5.6 Reference Manual.)

You can't.
Alternatively, you can create another column which has a data type of DATE only and make a unique compound key with your dateOnly column and the string column,
eg
CREATE TABLE Table1
(
`day_in_mydate` datetime,
`stringForTheDay` varchar(10),
`dateControl` date,
UNIQUE (dateControl, stringForTheDay)
)
a full example was demonstrated here,
SQLFiddle Demo
if you have an existing table with records on it, but you can still alter it. Add a column with DATE datatype, and execute this query
ALTER TABLE tableName ADD CONSTRAINT tb_UQ UNIQUE (dateOnlyColumn, stringColumn)
and update the table with its value from the timestamp field.
UPDATE tableName
SET dateOnlyColumn = DATE(timestampColumn)

Related

MySQL replace into behavior with unique constraint

I have a quick question about MySQL behavior.
Imagine a table with 3(relevant) columns:
id (PK + AI),somedate,someuser,etc...
I have put a unique constraint on (date,user). So when I start with a clean test table and run the following query twice:
REPLACE INTO `testtable` (somedate,someuser) VALUES('2017-01-01','admin');
I expected a row with the 'id' column on 1. but instead everytime I run this query the id goes up because of the auto increment and I can't have that happen (this would corrupt my data relations). Why is this? Can I make it so that I can keep the original primary key when a replace into occurs?
Not with the REPLACE. That's like an INSERT preceded by a DELETE. The behavior you observe with REPLACE is the same as the behavior you would see if you executed these two statements:
DELETE FROM `testtable` WHERE somedate = '2017-01-01' and someuser = 'admin';
INSERT INTO `testtable` (somedate,someuser) VALUES ('2017-01-01','admin');
And that means the auto_increment column on the newly inserted row will have a new value.
Perhaps consider using INSERT ... ON DUPLICATE KEY UPDATE.
Reference: https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
(Note that the attempt to insert a row that gets updated will use an auto_increment value.)
To me looks like you actually wanted an UPDATE statement rather like
update `testtable`
set somedate = '2017-01-01',
someuser = 'admin'
where id = <id of the record> ;

Case WHEN error

this is my query
CASE
WHEN (SELECT COUNT(*) FROM `table` WHERE `ip`= 'myip' )=1
THEN UPDATE `table`
SET `last_active`=".date("Ymd").",`last_time`=".date("His")."
WHERE `ip`= 'myip';
ELSE (INSERT INTO `table`(ip)
VALUES("myip"));
END
but its not woking .the problem should be from here
(SELECT COUNT(*) FROM `table` WHERE `ip`= 'myip' )=1
how can I fix this ? or how to do this another way?
the date("Ymd") function is just the php function to return the date the problem isnt from that
thanks
I think you are trying to do this:
create unique index unq_table_ip on table(ip);
insert into table (ip)
values ('myip')
on duplicate key update last_active = curdate(),
last_time = curtime();
The unique index (or equivalently a unique constraint) guarantees that a given ip only appears once in the table. Let the database do this work for you -- this is called maintaining relational integrity.
Notes:
This assumes that last_active and last_time have default values in the table.
You should use the database time, not the application time for this purpose (after all, different clients could have different time values).
You should probably put the date/time values into a single datetime column, say last_active_datetime.
Define unique constraint on ip column and then use ON DUPLICATE KEY UPDATE:
insert into `table` (ip) values ("myup")
on duplicate key update
`last_active`=".date("Ymd").",`last_time`=".date("His")."

Two autoincrements columns or autoincrement and same value in other column

I need two columns in table that would have same value on insert. Is there any way to do it from database side?
So you want to let one column use the auto_increment feature, but make another column in the same table also have the same value?
I can't think of a reason you would need this feature. Perhaps you could explain what you're trying to accomplish, and I can suggest a different solution?
A trigger won't work for this. It's a chicken-and-egg problem:
You can't change any column's value in an AFTER trigger.
But the auto-increment value isn't set yet when a BEFORE trigger executes.
It also won't work to use a MySQL 5.7 GENERATED column:
CREATE TABLE MyTable (
id INT AUTO_INCREMENT PRIMARY KEY,
why_would_you_want_this INT GENERATED ALWAYS AS (id)
);
ERROR 3109 (HY000): Generated column 'why_would_you_want_this'
cannot refer to auto-increment column.
You can't do it in a single SQL statement. You have to INSERT the row, and then immediately do an UPDATE to set your second column to the same value.
CREATE TABLE MyTable (
id INT AUTO_INCREMENT PRIMARY KEY,
why_would_you_want_this INT
);
INSERT INTO MyTable () VALUES ();
UPDATE MyTable SET why_would_you_want_this = LAST_INSERT_ID()
WHERE id = LAST_INSERT_ID();
You could alternatively generate the ID value using some other mechanism besides AUTO_INCREMENT (for example a Memcached incrementing key). Then you could insert the new value in both columns:
INSERT INTO MyTable (id, why_would_you_want_this) VALUES ($gen_id, $gen_id);
Define a before or after insert trigger and assign the value of the 2nd field in the trigger.
If the 1st field is an auto increment column, then you need to use an after insert trigger. If your application assigns value to the 1st field, then you can use a before insert trigger.
However, I would no necessarily duplicate the value on insert. You can leave the 2nd field as null on insert, which would mean that its value is the same as the 1st field's. The only drawback of this approach is that it may be more difficult to create joins on the 2nd field.
You can do this in one query by using the primary key (assumed to be id) and setting your column (assumed to be columnName):
"INSERT INTO tableName SET `columnName` = (SELECT MAX(x.id) FROM tableName x)+1"
This will not work if you have deleted the most recent primary key row however. To get past this, you can insert into the id as well:
"INSERT INTO tableName SET `columnName` = (SELECT MAX(x.id) FROM tableName x)+1, `id`= (SELECT MAX(x.id) FROM tableName x)+1"
However, this solution has the downside (or upside depending on the case) of reusing primary key values that have already been deleted.
suggested way:
To use the actual auto_increment value, you can do this:
"INSERT INTO tableName SET `columnName` = (SELECT `AUTO_INCREMENT` FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'db_name' AND TABLE_NAME = 'table_name')"
Sources that helped me solve this: Prashant Pimpale's answer

How to make insert or delete?

Structure table:
id (int primary key)
name (varchar 100)
date(datetime)
For insert I use query:
INSERT INTO table (name, date) VALUES ('t1','$date');
For delete row I use query:
DELETE FROM table WHERE name = 't1';
I would like want how make 1 query: first insert, if row with it name already exist, than delete row, and insert again.
Tell me please how to make it?
Create a UNIQUE index over your name column:
ALTER TABLE `table` ADD UNIQUE (name);
If you genuinely want to "delete row and insert again", then you can use REPLACE instead of INSERT. As documented:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Therefore, in your case:
REPLACE INTO `table` (name, date) VALUES ('t1','$date');
However, if instead of deleting the existing record and then inserting a new one you merely want to update the existing record, you can use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO `table` (name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE date = VALUES(date);
The most material difference is in the treatment of columns for which you do not provide explicit values (such as id in your example): REPLACE will result in the new record having the default value, whereas INSERT ... ON DUPLICATE KEY UPDATE will result in the old value being retained.
What you want to do is use MySQL's on duplicate update feature.
Can be used like this :
INSERT INTO table (name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE name=VALUES(name),dateVALUES(date);
Of course for that to happen a dupliate violation must occur.
insert into table (name, date) values('t1','$date') on duplicate key update name=values(name), date=values(date)
Are you looking for an update query?
Update will set a value on an already existing row.
UPDATE table SET date = '$newdate' WHERE name = 't1';
The best way to do this is using the mysql methods together with your query.
If you make the 'name' field unique:
id (int primary key)
name (varchar 100) NOT NULL UNIQUE
date(datetime)
And alter the query to:
INSERT INTO table
(name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE date = "$date"

curdate() causes error in trigger

i am using navicat8 for MySQL for writing trigger, bellow is my trigger statement.
insert into two(name,curdate())
select name from one
but it will display error while saving trigger.
insert into two(name, date_col)
select name, curdate()
from one
First you have to name the columns you want to insert into, and then the values. If you want to fill all columns from your table you can leave the column name part and do
insert into two
select name, curdate()
from one
You should specify the name of the column instead of passing CURDATE().
Use the following syntax,
insert into two (name, colName)
select name, CURDATE()
from one
UPDATE 1
So here's what you are going to do.
You need to add UNIQUE constraint on column Name on table two.
To alter the table,
ALTER TABLE tableNamehere ADD CONSTRAINT two_uq UNIQUE(name);
SQLFiddle Demo Link