I want to set my id in mysql table to default value say '000001' or'TodaysDate followed by 000001'..and same should be also auto_incremented.
how can we do this?
and also how set default value in TIMESTAMP column not by using 'CURRENT_TIMESTAMP'
such as '2012-04-01' and when update trigger will get fire it should get updated with todays date.
How to do this?
I want to set my id in mysql table to default value say '000001'.
If I were you I will leave it like id int, auto increment and when make the select I'll use the lpad function:
mysql> select lpad('1',6,'0');
+-----------------+
| lpad('1',6,'0') |
+-----------------+
| 000001 |
+-----------------+
1 row in set (0.00 sec)
about the timestamp I'll let that someone else answer, because what I'm thinking is do the same, use the current_timestamp and with mysql function convert to it how you want to:
mysql> select left(now(),10);
+----------------+
| left(now(),10) |
+----------------+
| 2012-06-01 |
+----------------+
1 row in set (0.00 sec)'
EDIT:
mysql> select concat(replace(left(now(),10),'-',''),lpad('1',6,'0'));
+--------------------------------------------------------+
| concat(replace(left(now(),10),'-',''),lpad('1',6,'0')) |
+--------------------------------------------------------+
| 20120601000001 |
+--------------------------------------------------------+
1 row in set (0.00 sec)
It looks like you answered your own question: specifically you want a 'before insert/update' trigger that sets the value for you.
CREATE TRIGGER my_autoinc BEFORE INSERT ON test1
FOR EACH ROW BEGIN
INSERT INTO test1 SET NEW.id_column = concat(today(), <some value>);
END;
Related
I've a column in a table (varchar) with dates in this format
2013-09-05T10:10:02Z
How do I convert this into datetime format and save it in another column, using an update query?
You can use the STR_TO_DATE function:
UPDATE table1 SET col2 = STR_TO_DATE(col1,'%Y-%m-%dT%TZ')
Example:
mysql> select STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ');
+----------------------------------------------------+
| STR_TO_DATE('2013-09-05T10:10:02Z','%Y-%m-%dT%TZ') |
+----------------------------------------------------+
| 2013-09-05 10:10:02 |
+----------------------------------------------------+
1 row in set (0.00 sec)
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
If you want to take care of the timezone just use this query, and use the mysql timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone);
+-------------------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", ##session.time_zone) |
+-------------------------------------------------------------------+
| 2013-09-05 12:10:02 |
+-------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
or any other timezone
mysql> select CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00");
+--------------------------------------------------------+
| CONVERT_TZ("2013-09-05T10:10:02Z", "+00:00", "+03:00") |
+--------------------------------------------------------+
| 2013-09-05 13:10:02 |
+--------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
I tried using the cast method from above but would get the truncated error as describe in the comments.
You can also use CAST('2013-09-05T10:10:02Z' AS DATETIME) which does not require a format definition as in STR_TO_DATE().
I would consistently get: Error: Truncated incorrect datetime value: '2011-10-02T23:25:42Z'
I fixed it by casting the value to an # variable before using it in my query. Here is an example in a Stored Procedure:
CREATE PROCEDURE `new_procedure`(IN p_date VARCHAR(50), p_text VARCHAR(500))
BEGIN
SET #datestring = CAST(p_date AS DATETIME);
-- used for debugging
SELECT #datestring, p_text;
INSERT INTO testtable(timestamp, text) VALUES(#datestring, p_text);
END
I am doing similar INSERT...SELECT query to this
INSERT INTO table (value1, value2)
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM table
WHERE value1='stuff for value1' AND value2='stuff for value2')
LIMIT 1
, where table has auto-genrated id.
And I would like to know if it was inserted or not, of course. I assume the way to do that is to use mysql_insert_id(). It returns 0 if no insertions happen and 1 if insertions happen. Looking more details here.
If an INSERT ... SELECT statement is executed, and NO automatically
generated value is successfully inserted, mysql_insert_id() RETURNS
the ID of the last inserted row.
What does it return if no auto-generated ID was successfully inserted? Is this a doc typo?
UPDATE1
So far I did testing in C and mysql_insert_id() returns always 0 if insertion did not happen even if the last insertion succeeded and mysql_insert_id() returned non-zero result. A paragraphs in the same manual, mentioned above, confirms this behavior by saying:
mysql_insert_id() returns 0 if the previous statement does not use an AUTO_INCREMENT value. ....
The value of mysql_insert_id() is affected only by statements issued within the current client connection. It is not affected by statements issued by other clients.
The LAST_INSERT_ID() SQL function will contain the value of the first automatically generated value that was successfully inserted. LAST_INSERT_ID() is not reset between statements because the value of that function is maintained in the server. ....
And that feels kind of logical otherwise INSERT...SELECT would be useless in many cases, if you cannot know within the code if your insertion worked or not. But it totally contradicts to the statement above. Did anyone have experience with this?
UPDATE2
From MariaDB manual, also suggests that the value should be zero in case of insertion did not happen:
The mysql_insert_id() function returns the ID generated by a query on
a table with a column having the AUTO_INCREMENT attribute or the value
for the last usage of LAST_INSERT_ID(expr). If the last query wasn't
an INSERT or UPDATE statement or if the modified table does not have a
column with the AUTO_INCREMENT attribute and LAST_INSERT_ID was not
used, this function will return zero.
The wording could be more clear, but what it means is that if your INSERT causes an error, mysql_insert_id() (or the SQL function last_insert_id()) continues to report whatever it did based on an earlier successful INSERT.
Here's a demo:
mysql> create table foo( id int auto_increment primary key);
mysql> create table bar( id int primary key);
mysql> insert into bar (id) values (1), (2), (10);
mysql> insert into foo select id from bar;
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 0 |
+------------------+
No new auto-inc values were generated, because my INSERT gave specific values to insert.
Let's generate some new values:
mysql> insert into foo select null from bar;
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 11 |
+------------------+
This is expected, because last_insert_id() will report the first id generated by a batch insert. You have to do the math to figure out how many rows were inserted, so you can know the rest of the id's. The id's generated in this way are guaranteed to be unique and consecutive.
Now let's try inserting some duplicates, which will cause an error:
mysql> insert into foo select id from bar;
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
Now comes the point of the sentence in the documentation: there has been no change in what last_insert_id() reports.
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 11 |
+------------------+
Likewise, even if the INSERTs are successful, but do not cause any new auto-inc values to be generated, there is no change in what last_insert_id() reports.
mysql> insert into foo select id+20 from bar;
Query OK, 3 rows affected (0.02 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 11 |
+------------------+
Many people assume last_insert_id() reports the most recent primary key value inserted, but it doesn't. It only reports values that were generated automatically by the auto-inc feature.
mysql_affected_rows is your friend. It will be greater than 0, if you successfully inserted rows (except when it returns (my_ulonglong)-1, which indicates failure). In your case, since you insert at most 1 row, you just need to check whether it returned 1.
It looks like it will return the id that was last auto-generated:
MariaDB [stackoverflow]> desc a;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| a | varchar(20) | YES | | NULL | |
| b | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
MariaDB [stackoverflow]> insert into a(a,b) values('haha', 'haha');
Query OK, 1 row affected (0.03 sec)
MariaDB [stackoverflow]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 1 |
+------------------+
MariaDB [stackoverflow]> insert into a(a,b) select 'hi', 'hello' from dual;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
MariaDB [stackoverflow]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 2 |
+------------------+
1 row in set (0.00 sec)
MariaDB [stackoverflow]> insert into a(a,b) select 'hi', 'hello' from dual where not exists (select * from a where a='hi' and b='hello') limit 1;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
MariaDB [stackoverflow]> select LAST_INSERT_ID() from dual;
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 2 |
+------------------+
1 row in set (0.00 sec)
I have a fairly large and complex mysql query to blackbox test and this query is time sensitive, it has a lot of conditions based on current_timestamp.
My goal is to make some tests so it always passes or fails. I'm thinking of mocking the value of current_timestamp temporarily to a fixed date before running the query and set it back to original value after the query.
Is it something thats doable?
I cannot modify the query itself (i.e.: find replace current_timestamp to something else)
Thanks
By setting system variable 'timestamp'. To restore it to current timestamp again, set it to DEFAULT.
mysql> SET TIMESTAMP = UNIX_TIMESTAMP('2015-01-01');
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2015-01-01 00:00:00 |
+---------------------+
1 row in set (0.00 sec)
mysql> SET TIMESTAMP = DEFAULT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT NOW();
+---------------------+
| NOW() |
+---------------------+
| 2016-03-08 09:50:16 |
+---------------------+
1 row in set (0.00 sec)
Is there any possibility to use an "after update" trigger only in the case the data has been REALLY changed.
I know of "NEW and OLD". But when using them I'm only able to compare columns.
For example "NEW.count <> OLD.count".
But I want something like: run trigger if "NEW <> OLD"
An Example:
create table foo (a INT, b INT);
create table bar (a INT, b INT);
INSERT INTO foo VALUES(1,1);
INSERT INTO foo VALUES(2,2);
INSERT INTO foo VALUES(3,3);
CREATE TRIGGER ins_sum
AFTER UPDATE ON foo
FOR EACH ROW
INSERT INTO bar VALUES(NEW.a, NEW.b);
UPDATE foo SET b = 3 WHERE a=3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
select * from bar;
+------+------+
| a | b |
+------+------+
| 3 | 3 |
+------+------+
The point is, there was an update, but nothing has changed.
But the trigger ran anyway. IMHO there should be a way it doesn't.
I know that I could have used
IF NOW.b <> OLD.b
for this example.
BUT imagine a large table with changing columns.
You have to compare every column and if the database changes you have to adjust the trigger.
AND it doesn't "feel" good to compare every column of the row hardcoded :)
Addition
As you can see on the line
Rows matched: 1 Changed: 0 Warnings: 0
MySQL knows that the line didn't change. But it doesn't share this knowledge with the trigger.
A trigger like "AFTER REAL UPDATE" or something like this would be cool.
As a workaround, you could use the timestamp (old and new) for checking though, that one is not updated when there are no changes to the row. (Possibly that is the source for confusion? Because that one is also called 'on update' but is not executed when no change occurs)
Changes within one second will then not execute that part of the trigger, but in some cases that could be fine (like when you have an application that rejects fast changes anyway.)
For example, rather than
IF NEW.a <> OLD.a or NEW.b <> OLD.b /* etc, all the way to NEW.z <> OLD.z */
THEN
INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF
you could use
IF NEW.ts <> OLD.ts
THEN
INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b) ;
END IF
Then you don't have to change your trigger every time you update the scheme (the issue you mentioned in the question.)
EDIT: Added full example
create table foo (a INT, b INT, ts TIMESTAMP);
create table bar (a INT, b INT);
INSERT INTO foo (a,b) VALUES(1,1);
INSERT INTO foo (a,b) VALUES(2,2);
INSERT INTO foo (a,b) VALUES(3,3);
DELIMITER ///
CREATE TRIGGER ins_sum AFTER UPDATE ON foo
FOR EACH ROW
BEGIN
IF NEW.ts <> OLD.ts THEN
INSERT INTO bar (a, b) VALUES(NEW.a, NEW.b);
END IF;
END;
///
DELIMITER ;
select * from foo;
+------+------+---------------------+
| a | b | ts |
+------+------+---------------------+
| 1 | 1 | 2011-06-14 09:29:46 |
| 2 | 2 | 2011-06-14 09:29:46 |
| 3 | 3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
3 rows in set (0.00 sec)
-- UPDATE without change
UPDATE foo SET b = 3 WHERE a = 3;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
-- the timestamo didnt change
select * from foo WHERE a = 3;
+------+------+---------------------+
| a | b | ts |
+------+------+---------------------+
| 3 | 3 | 2011-06-14 09:29:46 |
+------+------+---------------------+
1 rows in set (0.00 sec)
-- the trigger didn't run
select * from bar;
Empty set (0.00 sec)
-- UPDATE with change
UPDATE foo SET b = 4 WHERE a=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
-- the timestamp changed
select * from foo;
+------+------+---------------------+
| a | b | ts |
+------+------+---------------------+
| 1 | 1 | 2011-06-14 09:29:46 |
| 2 | 2 | 2011-06-14 09:29:46 |
| 3 | 4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
3 rows in set (0.00 sec)
-- and the trigger ran
select * from bar;
+------+------+---------------------+
| a | b | ts |
+------+------+---------------------+
| 3 | 4 | 2011-06-14 09:34:59 |
+------+------+---------------------+
1 row in set (0.00 sec)
It is working because of mysql's behavior on handling timestamps.
The time stamp is only updated if a change occured in the updates.
Documentation is here:
https://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
desc foo;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------+
| a | int(11) | YES | | NULL | |
| b | int(11) | YES | | NULL | |
| ts | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
BUT imagine a large table with changing columns. You have to compare every column and if the database changes you have to adjust the trigger. AND it doesn't "feel" good to compare every row hardcoded :)
Yeah, but that's the way to proceed.
As a side note, it's also good practice to pre-emptively check before updating:
UPDATE foo SET b = 3 WHERE a=3 and b <> 3;
In your example this would make it update (and thus overwrite) two rows instead of three.
I cant comment, so just beware, that if your column supports NULL values, OLD.x<>NEW.x isnt enough, because
SELECT IF(1<>NULL,1,0)
returns 0 as same as
NULL<>NULL 1<>NULL 0<>NULL 'AAA'<>NULL
So it will not track changes FROM and TO NULL
The correct way in this scenario is
((OLD.x IS NULL AND NEW.x IS NOT NULL) OR (OLD.x IS NOT NULL AND NEW.x IS NULL) OR (OLD.x<>NEW.x))
You can do this by comparing each field using the NULL-safe equals operator <=> and then negating the result using NOT.
The complete trigger would become:
DROP TRIGGER IF EXISTS `my_trigger_name`;
DELIMITER $$
CREATE TRIGGER `my_trigger_name` AFTER UPDATE ON `my_table_name` FOR EACH ROW
BEGIN
/*Add any fields you want to compare here*/
IF !(OLD.a <=> NEW.a AND OLD.b <=> NEW.b) THEN
INSERT INTO `my_other_table` (
`a`,
`b`
) VALUES (
NEW.`a`,
NEW.`b`
);
END IF;
END;$$
DELIMITER ;
(Based on a different answer of mine.)
In here if there any row affect with new insertion Then it will update on different table in the database.
DELIMITER $$
CREATE TRIGGER "give trigger name" AFTER INSERT ON "table name"
FOR EACH ROW
BEGIN
INSERT INTO "give table name you want to add the new insertion on previously given table" (id,name,age) VALUES (10,"sumith",24);
END;
$$
DELIMITER ;
Use the following query to see which rows have changes:
(select * from inserted) except (select * from deleted)
The results of this query should consist of all the new records that are different from the old ones.
MYSQL TRIGGER BEFORE UPDATE IF OLD.a<>NEW.b
USE `pdvsa_ent_aycg`;
DELIMITER $$
CREATE TRIGGER `cisterna_BUPD` BEFORE UPDATE ON `cisterna` FOR EACH ROW
BEGIN
IF OLD.id_cisterna_estado<>NEW.id_cisterna_estado OR OLD.observacion_cisterna_estado<>NEW.observacion_cisterna_estado OR OLD.fecha_cisterna_estado<>NEW.fecha_cisterna_estado
THEN
INSERT INTO cisterna_estado_modificaciones(nro_cisterna_estado, id_cisterna_estado, observacion_cisterna_estado, fecha_cisterna_estado) values (NULL, OLD.id_cisterna_estado, OLD.observacion_cisterna_estado, OLD.fecha_cisterna_estado);
END IF;
END
Here are two interesting dead ends (as of MySQL 5.7)-
The new.* and old.* constructs are invalid, MySQL complains about Unknown table 'new' or syntax to use near '*, which precludes tricks like
select ... from (select (select new.* union select old.*)a having count(*)=2) has_change
The documentation for "ROW_COUNT()" has a useful clue-
For UPDATE statements, the affected-rows value by default is the number of rows actually changed
And indeed, after an update statement, ROW_COUNT() correctly shows the count of rows that had changes from the update. However, during the update, inside the trigger, ROW_COUNT() = 0 always. That function has no useful value in a row-level trigger, and there's no statement-level trigger in MySQL as of this answer.
Hope this "null result" prevents future frustration.
How can I change the data in only one cell of a mysql table.
I have problem with UPDATE because it makes all the parameters in a column change but I want only one changed. How?
You probably need to specify which rows you want to update...
UPDATE
mytable
SET
column1 = value1,
column2 = value2
WHERE
key_value = some_value;
My answer is repeating what others have said before, but I thought I'd add an example, using MySQL, only because the previous answers were a little bit cryptic to me.
The general form of the command you need to use to update a single row's column:
UPDATE my_table SET my_column='new value' WHERE something='some value';
And here's an example.
BEFORE
mysql> select aet,port from ae;
+------------+-------+
| aet | port |
+------------+-------+
| DCM4CHEE01 | 11112 |
| CDRECORD | 10104 |
+------------+-------+
2 rows in set (0.00 sec)
MAKING THE CHANGE
mysql> update ae set port='10105' where aet='CDRECORD';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
AFTER
mysql> select aet,port from ae;
+------------+-------+
| aet | port |
+------------+-------+
| DCM4CHEE01 | 11112 |
| CDRECORD | 10105 |
+------------+-------+
2 rows in set (0.00 sec)
UPDATE will change only the columns you specifically list.
UPDATE some_table
SET field1='Value 1'
WHERE primary_key = 7;
The WHERE clause limits which rows are updated. Generally you'd use this to identify your table's primary key (or ID) value, so that you're updating only one row.
The SET clause tells MySQL which columns to update. You can list as many or as few columns as you'd like. Any that you do not list will not get updated.
UPDATE only changes the values you specify:
UPDATE table SET cell='new_value' WHERE whatever='somevalue'
Try the following:
UPDATE TableName SET ValueName=#parameterName WHERE
IdName=#ParameterIdName
UPDATE TABLE <tablename> SET <COLUMN=VALUE> WHERE <CONDITION>
Example:
UPDATE TABLE teacher SET teacher_name='NSP' WHERE teacher_id='1'
try this.
UPDATE `database_name`.`table_name` SET `column_name`='value' WHERE `id`='1';
Some of the columns in MySQL have an "on update" clause, see:
mysql> SHOW COLUMNS FROM your_table_name;
I'm not sure how to update this but will post an edit when I find out.