Related
I want to use a conditional
ON DUPLICATE KEY UPDATE
Based on the example provided in this question, suppose name is the primary key. We want to execute the following query:
INSERT INTO beautiful (name, age, col3, col 4, ..., col 100)
VALUES
('Helen', 24, ...),
('Katrina', 21, ...),
('Samia', 22, ...),
('Hui Ling', 25, ...),
('Yumie', 29, ...)
ON DUPLICATE KEY UPDATE
age = VALUES(age),
col3= VALUES(col3),
col4= VALUES(col4),
...
col100= VALUES(col100)
And (in MariaDB) I want the update to be done, only when the age of the newly received record is larger than the one already existent in the database.
Is there a way to do this?
UPDATE: Updated to reflect the fact that each record has multiple fields
Seems trivial
MariaDB [sandbox]> create table t(name varchar(20),age int default 0 , primary key(name));
Query OK, 0 rows affected (0.28 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> INSERT INTO t (name, age)
-> VALUES
-> ('Helen', 24),
-> ('Katrina', 21),
-> ('Samia', 22),
-> ('Hui Ling', 25),
-> ('Yumie', 29)
-> ON DUPLICATE KEY UPDATE
-> age = if(VALUES(age) > age,values(age),age);
Query OK, 5 rows affected (0.03 sec)
Records: 5 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t;
+----------+------+
| name | age |
+----------+------+
| Helen | 24 |
| Hui Ling | 25 |
| Katrina | 21 |
| Samia | 22 |
| Yumie | 29 |
+----------+------+
5 rows in set (0.00 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> INSERT INTO t (name, age)
-> VALUES
-> ('Helen', 25),
-> ('Katrina', 21),
-> ('Samia', 22),
-> ('Hui Ling', 25),
-> ('Yumie', 29)
-> ON DUPLICATE KEY UPDATE
-> age = if(VALUES(age) > age,values(age),age);
Query OK, 2 rows affected (0.02 sec)
Records: 5 Duplicates: 1 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t;
+----------+------+
| name | age |
+----------+------+
| Helen | 25 |
| Hui Ling | 25 |
| Katrina | 21 |
| Samia | 22 |
| Yumie | 29 |
+----------+------+
5 rows in set (0.00 sec)
If there are n columns which update when age changes then
drop table if exists t;
create table t(name varchar(20),age int default 0 , col1 int, col2 int,col3 int,primary key(name));
INSERT INTO t (name, age, col1,col2,col3)
VALUES
('Helen', 24,1,1,1),
('Katrina', 21,1,1,1),
('Samia', 22,1,1,1),
('Hui Ling', 25,1,1,1),
('Yumie', 29,1,1,1)
ON DUPLICATE KEY UPDATE
col1 = if(VALUES(age) > age,values(col1),col1),
col2 = if(VALUES(age) > age,values(col2),col2),
col3 = if(VALUES(age) > age,values(col3),col3),
age = if(VALUES(age) > age,values(age),age);
select * from t;
INSERT INTO t (name, age, col1,col2,col3)
VALUES
('Helen', 25,2,2,2),
('Katrina', 21,2,2,2),
('Samia', 22,1,1,1),
('Hui Ling', 25,1,1,1),
('Yumie', 29,1,1,1)
ON DUPLICATE KEY UPDATE
col1 = if(VALUES(age) > age,values(col1),col1),
col2 = if(VALUES(age) > age,values(col2),col2),
col3 = if(VALUES(age) > age,values(col3),col3),
age = if(VALUES(age) > age,values(age),age);
select * from t;
MariaDB [sandbox]> select * from t;
+----------+------+------+------+------+
| name | age | col1 | col2 | col3 |
+----------+------+------+------+------+
| Helen | 25 | 2 | 2 | 2 |
| Hui Ling | 25 | 1 | 1 | 1 |
| Katrina | 21 | 1 | 1 | 1 |
| Samia | 22 | 1 | 1 | 1 |
| Yumie | 29 | 1 | 1 | 1 |
+----------+------+------+------+------+
5 rows in set (0.00 sec)
Note age has to be last updated. There is no shortcut to keying all the updateable columns. If the columns other than age are dynamic then it may be worth looking at dynamic sql. Another approach might be to load the inserts to a staging table with a trigger to update your master table.
I want to insert data into a table in a specific order. This is because I need to give each entry a specific ID. What I am using is a select statement:
select (#i := #i + 1) as id, ...
order by column
The problem I am having is that this does not seem to work. I get the result I want from the select query. However, when I try to insert the data into the table the order by statement is ignored. Is there any way to force the correct order in the insert statement?
What I want is this:
+----+------+-------------+
| id | name | breadcrumbs |
+----+------+-------------+
| 1 | test | 01 |
| 5 | -d | 01,05 |
| 4 | c | 04 |
| 6 | e | 06 |
| 2 | -a | 06,02 |
| 3 | --b | 06,02,03 |
+----+------+-------------+
To become this:
+----+------+-------------+
| id | name | breadcrumbs |
+----+------+-------------+
| 1 | test | 01 |
| 2 | -d | 01,05 |
| 3 | c | 04 |
| 4 | e | 06 |
| 5 | -a | 06,02 |
| 6 | --b | 06,02,03 |
+----+------+-------------+
In a separate temporary table.
I would make certain that #i is initalised see select in from clause below
MariaDB [sandbox]> drop table if exists t;
Query OK, 0 rows affected (0.14 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> create table t(id int, name varchar(10), breadcrumbs varchar(100));
Query OK, 0 rows affected (0.18 sec)
MariaDB [sandbox]> insert into t values
-> ( 1 , 'test' , '01' ),
-> ( 5 , '-d' , '01,05' ),
-> ( 4 , 'c' , '04' ),
-> ( 6 , 'e' , '06' ),
-> ( 2 , '-a' , '06,02' ),
-> ( 3 , '--b' , '06,02,03');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> drop table if exists t1;
Query OK, 0 rows affected (0.13 sec)
MariaDB [sandbox]> create table t1 as
-> select
-> #i:=#i+1 id,
-> t.name,t.breadcrumbs
-> from (select #i:=0) i,
-> t
-> order by breadcrumbs;
Query OK, 6 rows affected (0.22 sec)
Records: 6 Duplicates: 0 Warnings: 0
MariaDB [sandbox]>
MariaDB [sandbox]> select * from t1;
+------+------+-------------+
| id | name | breadcrumbs |
+------+------+-------------+
| 1 | test | 01 |
| 2 | -d | 01,05 |
| 3 | c | 04 |
| 4 | e | 06 |
| 5 | -a | 06,02 |
| 6 | --b | 06,02,03 |
+------+------+-------------+
6 rows in set (0.00 sec)
I want to insert data into a table in a specific order.
There is no internal order to the records in a MySQL database table. Tables are modeled after unordered sets. The only order which exists is the one you apply by using an ORDER BY clause when you query. So moving forward, instead of worrying about the order in which your records are inserted, you should instead make sure that your table has the necessary columns and data to order your result sets the way you want.
The problem is related to autoincrement with mysql. What I'm trying to achieve is to increment an ID value based on the customer number. So basically i insert data sets without any order into a table. Each time a new customer is inserted, i would like the id column to be incremented, but of course kept for every row related to the customer, see the table below. Is there any way to achieve that via sql? I tried my luck with multiple primary keys and also looked into partioning, but was not able to figure it out by myself.
you can use a query like this:
INSERT INTO autoinc (cid,info,customer)
SELECT
COALESCE(max(cid),0) +1
, 'A Customer 1'
, 12345
FROM autoinc
WHERE customer = 12345;
sample
mysql> SELECT * from autoinc;
Empty set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
+----+------+--------------+----------+
1 row in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
+----+------+--------------+----------+
2 rows in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'B Customer 2'
-> , 9876
-> FROM autoinc
-> WHERE customer = 9876;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
| 3 | 1 | B Customer 2 | 9876 |
+----+------+--------------+----------+
3 rows in set (0,00 sec)
mysql> INSERT INTO autoinc (cid,info,customer)
-> SELECT
-> COALESCE(max(cid),0) +1
-> , 'A Customer 1'
-> , 12345
-> FROM autoinc
-> WHERE customer = 12345;
Query OK, 1 row affected (0,00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * from autoinc;
+----+------+--------------+----------+
| id | cid | info | customer |
+----+------+--------------+----------+
| 1 | 1 | A Customer 1 | 12345 |
| 2 | 2 | A Customer 1 | 12345 |
| 3 | 1 | B Customer 2 | 9876 |
| 4 | 3 | A Customer 1 | 12345 |
+----+------+--------------+----------+
4 rows in set (0,00 sec)
mysql>
What you probably need is to have different values for ID for each customer. The easiest way to achieve this is to use an AUTO_INCREMENT column as PK of your table.
It is an implementation detail that for consecutively inserted rows an AUTO_INCREMENT column has consecutive values. And the previous statement is not even true. It just happens some times, it is not guaranteed. If an INSERT statement is enclosed in a transaction that is rolled back, the value generated by that insert is skipped. Also, if an INSERT statements that use ON DUPLICATE KEYS UPDATE tries to insert many rows but some of them already exist in the table then the IDs generated for the duplicate keys are skipped.
What I want to stress out is that there is no point trying to get consecutive values using an AUTO_INCREMENT column and it is not even possible.
Back to your problem, if the column ID is the PK of the table and its type is INT AUTO_INCREMENT then MySQL guarantees there won't be two rows having the same value in the ID column and this also satisfies your need to have different values for ID for all the rows with the same value in customer.
You could procedurally do this using a stored procedure, which I won't elaborate on (unless requested) as it isn't a simple query (as you're asking for).
A hacky solution would be to bulk insert into a new joining table:
CREATE TABLE auto_inc_customer_id (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
customer_id INT UNSIGNED NOT NULL, -- Could/should add a FK constraint
PRIMARY KEY (id)
) ENGINE=innodb;
INSERT INTO auto_inc_customer_id SELECT NULL, DISTINCT(Customer) FROM YourExistingTable;
See: http://dev.mysql.com/doc/refman/5.7/en/ansi-diff-select-into-table.html
I have one table
test
ID text sum
-----------------------
1 1_2_3 0
2 2_3_4_5 0
i want to update this table as
ID text sum
------------------------
1 1_2_3 6
2 2_3_4_5 14
how to write the query or function/procedure.
You should really NORMALIZE your data,but assuming you are forced to work with it:
UPDATE tableName SET sum=SUBSTRING_INDEX(text,'_',1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(text,'_0'),'_',2),'_',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(text,'_0'),'_',3),'_',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(text,'_0'),'_',4),'_',-1) +
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(text,'_0'),'_',5),'_',-1);
Use SUBSTRING _INDEX to isolate each number,CONCAT is used to give a 0 if the number of expressions is larger than the number of values.
The fiddle
Try with this solution...
Hope this will help you....
SELECT SUM(Trim( Left(Name, InStr(Name, "_") - 1)) +
Trim( Mid(Name, InStr(Name, "_") + 1)) +
Trim(Right(Name, InStr(Name, ",") + 1))) as SUM FROM TEST;
Where the table structure is like this:
Id | Name |
1 | 1_2_3 |
2 | 5_8_10 |
It's resulted as
SUM
6
23
The best way to go about this is to make each text field an SQL statement.
First, here is sample data
mysql> drop table if exists prabhu;
Query OK, 0 rows affected (0.27 sec)
mysql> create table prabhu
-> (
-> id int not null auto_increment primary key,
-> text varchar(128),
-> sum int default 0
-> );
Query OK, 0 rows affected (0.56 sec)
mysql> insert into prabhu (text) values ('1_2_3'),('2_3_4_5');
Query OK, 2 rows affected (0.09 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from prabhu;
+----+---------+------+
| id | text | sum |
+----+---------+------+
| 1 | 1_2_3 | 0 |
| 2 | 2_3_4_5 | 0 |
+----+---------+------+
2 rows in set (0.00 sec)
mysql>
Here is a query to make each row produce an SQL statement to update the sum column
mysql> SELECT CONCAT('UPDATE prabhu SET sum=',
-> REPLACE(text,'_','+'),' WHERE id=',id,';') sqlstmt FROM prabhu;
+-------------------------------------------+
| sqlstmt |
+-------------------------------------------+
| UPDATE prabhu SET sum=1+2+3 WHERE id=1; |
| UPDATE prabhu SET sum=2+3+4+5 WHERE id=2; |
+-------------------------------------------+
2 rows in set (0.00 sec)
mysql>
Now, pipe the output of the query back into mysql and execute each line
C:\>mysql -Dtest -ANe"SELECT CONCAT('UPDATE prabhu SET sum=',REPLACE(text,'_','+'),' WHERE id=',id,';') sqlstmt FROM pra
bhu" | mysql -Dtest
C:\>mysql -Dtest -Ae"SELECT * FROM prabhu"
+----+---------+------+
| id | text | sum |
+----+---------+------+
| 1 | 1_2_3 | 6 |
| 2 | 2_3_4_5 | 14 |
+----+---------+------+
C:\>
Give it a Try !!!
I am trying to create an empty VIEW in mySQL with the columns I define.
i.e. I would like a view with columns: age, id, gender, but with 0 rows.
Thanks in advance.
Here's an example for you:
mysql> create or replace view v_test as
-> select 99 as age,
-> 2147483647 as id,
-> 'F' as gender
-> from dual
-> where false;
Query OK, 0 rows affected (0.04 sec)
mysql> desc v_test;
+--------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+-------+
| age | int(2) | NO | | 0 | |
| id | bigint(10) | NO | | 0 | |
| gender | varchar(1) | NO | | | |
+--------+------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
mysql> select * from v_test;
Empty set (0.00 sec)
Why you would ever want to do this is beyond me:
CREATE VIEW foo AS SELECT NULL AS age, NULL AS id, NULL AS gender WHERE FALSE
Try defining your view from this select statement:
SELECT 5 as age, 10 as id, 'M' as gender
WHERE age = 0
This will give you the correct types for the columns