Can you use aggregate values within ON DUPLICATE KEY - mysql

I am trying to write a query similar to:
INSERT INTO SomeTable(field1, field2)
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
ON DUPLICATE KEY
UPDATE field1= 'blah', field2 = MAX(AnotherTable.number)
I get Error Code: 1111
Invalid use of group function.
Reading through the MySql documentation:
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html
the lines of interest are:
"In the values part of ON DUPLICATE KEY UPDATE, you can refer to columns in other tables, as long as you do not use GROUP BY in the SELECT part. One side effect is that you must qualify nonunique column names in the values part. "
Is this the problem I am seeing? I am not specifically doing a GROUP BY in the Select statement, but by using an aggregate function (Max), then I may be grouping implicitly.
If anyone knows for sure if I am implicitly doing a GROUP BY or if there is any other way I can get the desired result I would be very greatful.

I know I am answering my own question here but...
This eventually got it working (thanks to: a broken link)
INSERT INTO SomeTable(field1, field2)
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
ON DUPLICATE KEY
UPDATE field2 = values(field2)

Please have a try if this works:
INSERT INTO SomeTable(field1, field2)
SELECT * FROM (
SELECT * FROM (
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
) sq
) sq2
ON DUPLICATE KEY
UPDATE field1= 'blah', field2 = sq2.field2
Not sure if 2 times the subquery is needed. I usually use this to circumvent MySQLs limitation to not be able to update the table with values I read from the same table. Not sure if this works here, too.

Related

MySQL: how to update column using value before change

There is a table with three column: id, field1, field2.
And there is a row: id=1, field1=1, field2=1.
Run a update SQL: UPDATE my_table SET field1=field2+1, field2=field1+1 WHERE id=1;
I expected the result is: id=1, field1=2, field2=2. But in fact I got: id=1, field1=2, field2=3. Because when calculating field2=field1+1, the value of field1 has changed!
I figure out a SQL to solve this problem:
UPDATE my_table dest, (SELECT * FROM my_table) src
SET dest.field1=src.field2+1, dest.field2=src.field1+1
WHERE dest.id=1;
However I want to insert a record, and if the row was existed then do a update just like above.
INSERT INTO my_table (id, field1, field2) VALUES(1, 1, 1)
ON DUPLICATE KEY UPDATE
field1=field2+1, field2=field1+1;
This SQL has problem same as the first SQL. So how can I do this update using the value before change with ON DUPLICATE KEY UPDATE clause?
Thanks for any help!
Couldn't think of anything else but a temp variable. However, couldn't think of a way to make SQL syntax work, other than this:
set #temp = 0;
update test.test set
f1 = (#temp:=f1),
f1 = f2 + 1,
f2 = #temp + 1
where id = 1;
Hope this helps, and hope even more it helps you find a better way :)
I find a trick way to do this.
Use the IF clause to create temp variable. Field update use temp variable to calculate.
INSERT INTO my_table (id, f1, f2) VALUES(1, 1, 1)
ON DUPLICATE KEY UPDATE
id=IF((#t1:=f1 & #t2:=f2), 1, 1), f1=#t2+1, f2=#t1+1;
There is some point to notice:
The performance is a bit slow. Especially copy TEXT value to temp variable.
If field id need to use IF clause, the expr will be more complicated like:
((#t1:=f1 & #t2:=f2) || TRUE) AND (Your Condition)

Prevent auto increment on duplicate entry

I have seen this issue around (See links at bottom) but I can't seem to figure out an answer. The problem is that I insert data on a table with an auto increment ID that is a primary key, and another field with a UNIQUE index to avoid duplicates. This works, but when that happens the ID is incremented, although no data has been stored.
Would it be better to remove the auto increment, and handle it myself, selecting the max(ID)?
At the moment I have tried several strategies to make it work as is, including INSERT IGNORE and INSERT ... ON DUPLICATE KEY UPDATE
My latest try was using the following query:
INSERT INTO
content(field1, field2)
SELECT(:field1, :field2) FROM DUAL
WHERE NOT EXISTS(
SELECT field1, field2
FROM content
WHERE field1 = :field1
)
Related
In MySQL, when there is a "duplicate entry" error, how do I prevent the primary key from auto incrementing?
SQL Server - How to insert a record and make sure it is unique
Thanks to this question I have been able to fix that error. The problem was that the SELECT(:field1, :field2) shouldn't have the parenthesis. So the query should be:
INSERT INTO
content(field1, field2)
SELECT :field1, :field2 FROM DUAL
WHERE NOT EXISTS(
SELECT field1, field2
FROM content
WHERE field1 = :field1
)
You could just do an ORDER BY :)
UPDATE 'table'
SET column_id = column_id+1
WHERE column_id > [point where you want a un-occupied key]
ORDER BY column_id DESC
mysql executes the where and order by first then your update

Insert data from another table with a loop in mysql

I could solve it with php or some other language but I am keen to learn more SQL.
Is there a way to solve this:
I have two tables (and I can't change the structure), one content with some data and the other content_info with some additional information. They are related that way: content.id = content_info.content_id.
What I would like to do: If there is no dataset in content_info but in content, I would like to copy it over, that at the end there are the same number of datasets in both tables. I tried it that way, but unfortunately it doesn't work:
...
BEGIN
(SELECT id, ordering FROM content;)
cont:LOOP
#cid = SELECT content_id FROM content_info WHERE content_id = (id)
IF #cid != (id) THEN
INSERT INTO content_info SET content_id = (id), ordering = (ordering)
ITERATE cont;
END IF;
END LOOP cont;
END
..
Has someone an idea, or isn't it possible at the end? Thanks in advance!
You can use INSERT IGNORE to insert new rows but do nothing if there's already a row in the table that would cause a duplicate entry error.
INSERT IGNORE INTO jos_content_frontpage (content_id, ordering)
SELECT id, ordering FROM jos_content
Seems like you are looking for the INSERT ... SELECT syntax. Any select can be inserted into a table provide you format the data to match the target table.
Also, your INSERT syntax is incorrect, looks like you are using the UPDATE syntax.
INSERT INTO table (field1, field2, field3) VALUES ('1','2','3');
INSERT INTO table (field1, field2, field3) SELECT field1, field2, field3 FROM ...
I will give example for one field only, the id field. you can add other fields too:
insert into content_info(content_id)
select content.id
from content left outer join content_info
on (content.id=content_info.content_id)
where content_info.content_id is null
another way
insert into content_info(content_id)
select content.id
from content
where not exists (
select *
from content_info
where content_info.content_id = content.id
)

Mysql on duplicate key update + sub query

Using the answer from this question: Need MySQL INSERT - SELECT query for tables with millions of records
new_table
* date
* record_id (pk)
* data_field
INSERT INTO new_table (date,record_id,data_field)
SELECT date, record_id, data_field FROM old_table
ON DUPLICATE KEY UPDATE date=old_table.data, data_field=old_table.data_field;
I need this to work with a group by and join.. so to edit:
INSERT INTO new_table (date,record_id,data_field,value)
SELECT date, record_id, data_field, SUM(other_table.value) as value FROM old_table JOIN other_table USING(record_id) GROUP BY record_id
ON DUPLICATE KEY UPDATE date=old_table.data, data_field=old_table.data_field, value = value;
I can't seem to get the value updated. If I specify old_table.value I get a not defined in field list error.
Per the docs at http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
In the values part of ON DUPLICATE KEY UPDATE, you can refer to columns in other tables, as long as you do not use GROUP BY in the SELECT part. One side effect is that you must qualify nonunique column names in the values part.
So, you cannot use the select query because it has a group by statement. You need to use this trick instead. Basically, this creates a derived table for you to query from. It may not be incredibly efficient, but it works.
INSERT INTO new_table (date,record_id,data_field,value)
SELECT date, record_id, data_field, value
FROM (
SELECT date, record_id, data_field, SUM(other_table.value) as value
FROM old_table
JOIN other_table
USING(record_id)
GROUP BY record_id
) real_query
ON DUPLICATE KEY
UPDATE date=real_query.date, data_field=real_query.data_field, value = real_query.value;
While searching around some more, I found a related question: "MySQL ON DUPLICATE KEY UPDATE with nullable column in unique key".
The answer is that VALUES() can be used to refer to column "value" in the select sub-query.

MySQL: Update all Columns With Values From A Separate Table

Sometimes if I want to quickly copy records from one table to another (that has the same structure) I use a query like this:
INSERT INTO table2 SELECT * FROM
table1 WHERE id = SOME_VALUE
How can I add a ON DUPLICATE KEY UPDATE to this statement? I tried this:
INSERT INTO SELECT * FROM table1 WHERE
id = 1 ON DUPLICATE KEY UPDATE SELECT
* FROM table1 WHERE id = 1
But I get an error. Is there away to accomplish the query above with out individually listing each column in the query?
P.S. Yes, I realize that it is not good practice to have multiple tables with identical structures, but sometimes you just don't get control over everything in the workplace!
The below UPDATES if there is no PK duplication and INSERTs is there is:
REPLACE INTO table2(field1, field2, field3)
SELECT field1, field2,field3 FROM table1
WHERE id=1;
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html Just use the SELECT field_name from the other table like in dnagirls example