Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
583 views146 pages

13

The document discusses the CALL statement in SQL which is used to invoke stored procedures. It describes the syntax of CALL and how it can pass back values. It also provides examples of calling procedures and accessing parameters.

Uploaded by

shahim akram
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
583 views146 pages

13

The document discusses the CALL statement in SQL which is used to invoke stored procedures. It describes the syntax of CALL and how it can pass back values. It also provides examples of calling procedures and accessing parameters.

Uploaded by

shahim akram
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 146

13.2.

1 CALL Syntax
CALL sp_name([parameter[,...]])
CALL sp_name[()]
The CALL statement invokes a stored procedure that was defined previously with CREATE
PROCEDURE.
Stored procedures that take no arguments can be invoked without parentheses. That is, CALL
p() and CALL p are equivalent.
CALL can pass back values to its caller using parameters that are declared
as OUT or INOUT parameters. When the procedure returns, a client program can also obtain the
number of rows affected for the final statement executed within the routine: At the SQL level, call
the ROW_COUNT() function; from the C API, call themysql_affected_rows() function.
To get back a value from a procedure using an OUT or INOUT parameter, pass the parameter by
means of a user variable, and then check the value of the variable after the procedure returns. (If
you are calling the procedure from within another stored procedure or function, you can also pass a
routine parameter or local routine variable as an IN or INOUT parameter.) For an INOUT parameter,
initialize its value before passing it to the procedure. The following procedure has an OUT parameter
that the procedure sets to the current server version, and an INOUT value that the procedure
increments by one from its current value:
CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN
# Set value of OUT parameter
SELECT VERSION() INTO ver_param;
# Increment value of INOUT parameter
SET incr_param = incr_param + 1;
END;
Before calling the procedure, initialize the variable to be passed as the INOUT parameter. After
calling the procedure, the values of the two variables will have been set or modified:
mysql> SET @increment = 10;
mysql> CALL p(@version, @increment);
mysql> SELECT @version, @increment;
+------------------+------------+
| @version | @increment |
+------------------+------------+
| 5.7.20-debug-log | 11 |
+------------------+------------+
In prepared CALL statements used with PREPARE and EXECUTE, placeholders can be used
for IN parameters, OUT, and INOUT parameters. These types of parameters can be used as follows:
mysql> SET @increment = 10;
mysql> PREPARE s FROM 'CALL p(?, ?)';
mysql> EXECUTE s USING @version, @increment;
mysql> SELECT @version, @increment;
+------------------+------------+
| @version | @increment |
+------------------+------------+
| 5.7.20-debug-log | 11 |
+------------------+------------+
To write C programs that use the CALL SQL statement to execute stored procedures that produce
result sets, the CLIENT_MULTI_RESULTS flag must be enabled. This is because each CALL returns a
result to indicate the call status, in addition to any result sets that might be returned by statements
executed within the procedure. CLIENT_MULTI_RESULTS must also be enabled if CALL is used to
execute any stored procedure that contains prepared statements. It cannot be determined when
such a procedure is loaded whether those statements will produce result sets, so it is necessary to
assume that they will.
CLIENT_MULTI_RESULTS can be enabled when you call mysql_real_connect(), either explicitly
by passing the CLIENT_MULTI_RESULTS flag itself, or implicitly by
passing CLIENT_MULTI_STATEMENTS (which also
enables CLIENT_MULTI_RESULTS). CLIENT_MULTI_RESULTS is enabled by default.
To process the result of a CALL statement executed
using mysql_query() or mysql_real_query(), use a loop that calls mysql_next_result() to
determine whether there are more results. For an example, see Section 27.8.16, C API Multiple
Statement Execution Support.
C programs can use the prepared-statement interface to execute CALL statements and
access OUT and INOUT parameters. This is done by processing the result of a CALL statement using
a loop that calls mysql_stmt_next_result() to determine whether there are more results. For an
example, see Section 27.8.18, C API Prepared CALL Statement Support. Languages that provide
a MySQL interface can use prepared CALL statements to directly retrieve OUT and INOUTprocedure
parameters.
Metadata changes to objects referred to by stored programs are detected and cause automatic
reparsing of the affected statements when the program is next executed. For more information,
see Section 8.10.4, Caching of Prepared Statements and Stored Programs.

13.2.2 DELETE Syntax


DELETE is a DML statement that removes rows from a table.
Single-Table Syntax
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
The DELETE statement deletes rows from tbl_name and returns the number of deleted rows. To
check the number of deleted rows, call the ROW_COUNT()function described in Section 12.14,
Information Functions.
Main Clauses
The conditions in the optional WHERE clause identify which rows to delete. With no WHERE clause, all
rows are deleted.
where_condition is an expression that evaluates to true for each row to be deleted. It is specified
as described in Section 13.2.9, SELECT Syntax.
If the ORDER BY clause is specified, the rows are deleted in the order that is specified.
The LIMIT clause places a limit on the number of rows that can be deleted. These clauses apply to
single-table deletes, but not multi-table deletes.
Multiple-Table Syntax
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
tbl_name[.*] [, tbl_name[.*]] ...
FROM table_references
[WHERE where_condition]

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]


FROM tbl_name[.*] [, tbl_name[.*]] ...
USING table_references
[WHERE where_condition]
Privileges
You need the DELETE privilege on a table to delete rows from it. You need only the SELECT privilege
for any columns that are only read, such as those named in the WHERE clause.
Performance
When you do not need to know the number of deleted rows, the TRUNCATE TABLE statement is a
faster way to empty a table than a DELETE statement with noWHERE clause.
Unlike DELETE, TRUNCATE TABLE cannot be used within a transaction or if you have a lock on the
table. See Section 13.1.34, TRUNCATE TABLE Syntax and Section 13.3.5, LOCK TABLES and
UNLOCK TABLES Syntax.
The speed of delete operations may also be affected by factors discussed in Section 8.2.4.3,
Optimizing DELETE Statements.
To ensure that a given DELETE statement does not take too much time, the MySQL-
specific LIMIT row_count clause for DELETE specifies the maximum number of rows to be deleted.
If the number of rows to delete is larger than the limit, repeat the DELETE statement until the number
of affected rows is less than the LIMIT value.
Subqueries
You cannot delete from a table and select from the same table in a subquery.

Partitioned Tables
DELETE supports explicit partition selection using the PARTITION option, which takes a list of the
comma-separated names of one or more partitions or subpartitions (or both) from which to select
rows to be dropped. Partitions not included in the list are ignored. Given a partitioned table t with a
partition named p0, executing the statement DELETE FROM t PARTITION (p0) has the same
effect on the table as executing ALTER TABLE t TRUNCATE PARTITION (p0); in both cases, all
rows in partition p0 are dropped.
PARTITION can be used along with a WHERE condition, in which case the condition is tested only on
rows in the listed partitions. For example, DELETE FROM t PARTITION (p0) WHERE c <
5 deletes rows only from partition p0 for which the condition c < 5 is true; rows in any other
partitions are not checked and thus not affected by the DELETE.
The PARTITION option can also be used in multiple-table DELETE statements. You can use up to
one such option per table named in the FROM option.
For more information and examples, see Section 22.5, Partition Selection.
Auto-Increment Columns
If you delete the row containing the maximum value for an AUTO_INCREMENT column, the value is
not reused for a MyISAM or InnoDB table. If you delete all rows in the table with DELETE
FROM tbl_name (without a WHERE clause) in autocommit mode, the sequence starts over for all
storage engines except InnoDB and MyISAM. There are some exceptions to this behavior
for InnoDB tables, as discussed in Section 14.8.1.5, AUTO_INCREMENT Handling in InnoDB.
For MyISAM tables, you can specify an AUTO_INCREMENT secondary column in a multiple-column
key. In this case, reuse of values deleted from the top of the sequence occurs even
for MyISAM tables. See Section 3.6.9, Using AUTO_INCREMENT.
Modifiers
The DELETE statement supports the following modifiers:
If you specify LOW_PRIORITY, the server delays execution of the DELETE until no other clients
are reading from the table. This affects only storage engines that use only table-level locking
(such as MyISAM, MEMORY, and MERGE).
For MyISAM tables, if you use the QUICK modifier, the storage engine does not merge index
leaves during delete, which may speed up some kinds of delete operations.
The IGNORE modifier causes MySQL to ignore errors during the process of deleting rows.
(Errors encountered during the parsing stage are processed in the usual manner.) Errors that
are ignored due to the use of IGNORE are returned as warnings. For more information,
see Comparison of the IGNORE Keyword and Strict SQL Mode.
Order of Deletion
If the DELETE statement includes an ORDER BY clause, rows are deleted in the order specified by the
clause. This is useful primarily in conjunction with LIMIT. For example, the following statement finds
rows matching the WHERE clause, sorts them by timestamp_column, and deletes the first (oldest)
one:
DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;
ORDER BY also helps to delete rows in an order required to avoid referential integrity violations.
InnoDB Tables
If you are deleting many rows from a large table, you may exceed the lock table size for
an InnoDB table. To avoid this problem, or simply to minimize the time that the table remains locked,
the following strategy (which does not use DELETE at all) might be helpful:
1. Select the rows not to be deleted into an empty table that has the same structure as the original
table:
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
2. Use RENAME TABLE to atomically move the original table out of the way and rename the copy to
the original name:
RENAME TABLE t TO t_old, t_copy TO t;
3. Drop the original table:

DROP TABLE t_old;


No other sessions can access the tables involved while RENAME TABLE executes, so the rename
operation is not subject to concurrency problems. SeeSection 13.1.33, RENAME TABLE Syntax.
MyISAM Tables
In MyISAM tables, deleted rows are maintained in a linked list and subsequent INSERT operations
reuse old row positions. To reclaim unused space and reduce file sizes, use the OPTIMIZE
TABLE statement or the myisamchk utility to reorganize tables. OPTIMIZE TABLE is easier to use,
but myisamchk is faster. SeeSection 13.7.2.4, OPTIMIZE TABLE Syntax, and Section 4.6.3,
myisamchk MyISAM Table-Maintenance Utility.
The QUICK modifier affects whether index leaves are merged for delete operations. DELETE
QUICK is most useful for applications where index values for deleted rows are replaced by similar
index values from rows inserted later. In this case, the holes left by deleted values are reused.
DELETE QUICK is not useful when deleted values lead to underfilled index blocks spanning a range
of index values for which new inserts occur again. In this case, use of QUICK can lead to wasted
space in the index that remains unreclaimed. Here is an example of such a scenario:
1. Create a table that contains an indexed AUTO_INCREMENT column.
2. Insert many rows into the table. Each insert results in an index value that is added to the high
end of the index.

3. Delete a block of rows at the low end of the column range using DELETE QUICK.
In this scenario, the index blocks associated with the deleted index values become underfilled but
are not merged with other index blocks due to the use of QUICK. They remain underfilled when new
inserts occur, because new rows do not have index values in the deleted range. Furthermore, they
remain underfilled even if you later use DELETE without QUICK, unless some of the deleted index
values happen to lie in index blocks within or adjacent to the underfilled blocks. To reclaim unused
index space under these circumstances, use OPTIMIZE TABLE.
If you are going to delete many rows from a table, it might be faster to use DELETE QUICK followed
by OPTIMIZE TABLE. This rebuilds the index rather than performing many index block merge
operations.
Multi-Table Deletes
You can specify multiple tables in a DELETE statement to delete rows from one or more tables
depending on the condition in the WHERE clause. You cannot use ORDER BY or LIMIT in a multiple-
table DELETE. The table_references clause lists the tables involved in the join, as described
in Section 13.2.9.2, JOIN Syntax.
For the first multiple-table syntax, only matching rows from the tables listed before the FROM clause
are deleted. For the second multiple-table syntax, only matching rows from the tables listed in
the FROM clause (before the USING clause) are deleted. The effect is that you can delete rows from
many tables at the same time and have additional tables that are used only for searching:
DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;
Or:

DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3


WHERE t1.id=t2.id AND t2.id=t3.id;
These statements use all three tables when searching for rows to delete, but delete matching rows
only from tables t1 and t2.
The preceding examples use INNER JOIN, but multiple-table DELETE statements can use other
types of join permitted in SELECT statements, such as LEFT JOIN. For example, to delete rows that
exist in t1 that have no match in t2, use a LEFT JOIN:
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
The syntax permits .* after each tbl_name for compatibility with Access.
If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key
constraints, the MySQL optimizer might process tables in an order that differs from that of their
parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete
from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other
tables to be modified accordingly.
Note
If you declare an alias for a table, you must use the alias when referring to the table:

DELETE t1 FROM test AS t1, test2 WHERE ...


Table aliases in a multiple-table DELETE should be declared only in the table_references part of
the statement. Elsewhere, alias references are permitted but not alias declarations.
Correct:

DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2


WHERE a1.id=a2.id;

DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2


WHERE a1.id=a2.id;
Incorrect:

DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2


WHERE a1.id=a2.id;

DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2


WHERE a1.id=a2.id;
PREV HOME UP NEXT

User Comments
Posted by Chris Rywalt on January 29, 2004

I spent an hour or so working out how to delete rows matching a specific SELECT statement which was mildly
complex:

SELECT A.* FROM table1 AS A, table1 AS B


WHERE A.username LIKE '%2'
AND A.ID = B.ID
AND A.username <> B.username

(Basically, I had accidentally created two usernames for each ID, the extra username ending in 2. But there
were some valid usernames ending in 2 which I didn't want to delete.)

I tried several different approaches to crafting a delete statement to get rid of these, all to no avail. I tried
DELETE...WHERE IN...SELECT and DELETE...WHERE...= ANY...SELECT, WHERE EXISTS, and several
other variations, all of which looked like they should work according to the manual, but none of which did.

Finally -- hence this comment, so you don't have to jump through my hoops -- my DBA wife and I put together
this solution:

CREATE TEMPORARY TABLE tmptable


SELECT A.* FROM table1 AS A, table1 AS B
WHERE A.username LIKE '%2'
AND A.ID = B.ID
AND A.username <> B.username;

DELETE table1 FROM table1


INNER JOIN tmptable
ON table1.username = tmptable.username;

Maybe this isn't the best way to do this, but it worked for me. Hope it helps someone else.

Posted by Kevin Nelson on April 18, 2008

- Deleting Duplicate Entries -

I had a many-to-many relational table that joined users and events. Some users might save the same event
more than once...so I wanted to know a way to delete duplicate entries. The table has a primary key "ueventID"
(auto-increment) and two foreign keys "userID" and "eventID". In order to delete duplicate entries, I found that
this solution worked quite well for me.

DELETE t1 FROM tbl_name t1, tbl_name t2 WHERE t1.userID=t2.userID AND t1.eventID=t2.eventID AND
t1.ueventID < t2.ueventID

This will delete all but the very last entry of the duplicates. If there are any better ways to do this, feel free to let
me know. I'll try to remember to check back later.

Honestly, though, while I wanted to know how to do this...officially, I just check to see if it's a duplicate entry
BEFORE I insert it so that I don't have to hassle with this :-P

Posted by Linus Lvholm on September 1, 2005

Regarding deleting duplicate entries:


I have found two other much more robust ways of doing this, which will accomplish the task even for rows that
are complete duplicates.

1) SELECT DISTINCT INTO ...


Perform a select distinct into a new table. Drop the old table. Rename the new table if you want to.

2) Use ALTER IGNORE TABLE and add an index for the duplicate column(s). Given this table (without primary
key):

+---+
| a |
+---+
| 1 |
| 1 |
| 2 |
| 2 |
| 3 |
+---+
Do this:

ALTER IGNORE TABLE table1 ADD PRIMARY KEY(a);

Naturally, you can use a UNIQUE index instead of a primary key.

Posted by on December 1, 2005

While it is documented in these pages, it takes a bit of hunting to confirm this incompatible change in v3.23 to
v4.1:

If you delete all rows from a table with DELETE FROM tablename, then add some new rows with INSERT
INTO tablename, an AUTO_INCREMENT field would start again from 1 using MySQL v3.23.

However, with MyISAM tables with MySQL v4.1, the auto increment counter isn't reset back to 1 - even if you
do OPTIMIZE tablename. You have to do TRUNCATE tablename to delete all rows in order to reset the auto
increment counter.

This can cause problems because your auto increment counter gets higher and higher each time you do a
DELETE all/INSERT new data cycle.

Posted by Radek Maciaszek on August 21, 2006

It's probably worth to mention that DELETE FROM doesn't use the same isolation level in transaction as
SELECT. Even if you set isolation level as REPEATABLE READ it doesn't change DELETE behaviour which
work as READ COMMITTED. (it affects InnoDB engine in MySQL4 and MySQL5)

Here is an example:

| User A User B
|
| SET AUTOCOMMIT=0; SET AUTOCOMMIT=0;
|
| SELECT * FROM t;
| empty set
| INSERT INTO t VALUES (1, 2);
|
| SELECT * FROM t;
| empty set
| COMMIT;
|
| SELECT * FROM t;
| empty set
|
| SELECT * FROM t;
| ---------------------
| | 1 | 2 |
| ---------------------
| 1 row in set
|
| DELETE FROM t;
| Query OK,
| 1 row affected
|// ^ it delets rows from
|// outside it's transaction
|
| COMMIT;
|
| SELECT * FROM t;
| empty set

Posted by Luciano Fantuzzi on April 16, 2007

Keywords: ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails...

I think this is a good practice to do when you're designing a database that has lots of foreign keys. If you have
tables with ON DELETE CASCADE option which are linked with other field to other tables, the delete cascade
option will fail (because mysql could not delete in the same order you create the tables) with the "ERROR 1452
(23000)". A solution for this case is to declare a clause ON DELETE SET NULL in the others foreign keys. An
example:

|-------------------------------------------------------
| mysql> CREATE TABLE a(
| -> id INT AUTO_INCREMENT, user VARCHAR(20), PRIMARY KEY(id)) ENGINE=InnoDB;
| Query OK, 0 rows affected (0.08 sec)
|
| mysql> CREATE TABLE b(
| -> id INT AUTO_INCREMENT, id_a INT, name VARCHAR(20), PRIMARY KEY(id),
| -> FOREIGN KEY(id_a) REFERENCES a(id) ON DELETE CASCADE) ENGINE=InnoDB;
| Query OK, 0 rows affected (0.08 sec)
|
| mysql> CREATE TABLE c(
| -> id INT AUTO_INCREMENT, id_a INT, id_b INT, lastName VARCHAR(20), PRIMARY
KEY(id),
| -> FOREIGN KEY(id_a) REFERENCES a(id) ON DELETE CASCADE,
| -> FOREIGN KEY(id_b) REFERENCES b(id)) ENGINE=InnoDB;
| Query OK, 0 rows affected (0.08 sec)
|
| mysql> INSERT INTO a(user) VALUES('zerocool');
| Query OK, 1 row affected (0.06 sec)
|
| mysql> INSERT INTO b(id_a,name) VALUES(1,'carl');
| Query OK, 1 row affected (0.06 sec)
|
| mysql> INSERT INTO c(id_a,id_b,lastName) VALUES(1,1,'anderson');
| Query OK, 1 row affected (0.06 sec)
|
| mysql> DELETE FROM a WHERE user='zerocool';
| ERROR 1451 (23000): Cannot delete or update a parent row:
| a foreign key constraint fails (`apk_zupca/c`, CONSTRAINT
| `c_ibfk_2` FOREIGN KEY (`id_b`) REFERENCES `b` (`id`))
At this point, the ON DELETE CASCADE is failing because the child table (b) has another FOREIGN KEY (c is
linked with b, so row in b can't be deleted). We have created the tables in the correct order, but mysql is trying
to delete rows in the order we've created the tables and it's the wrong way. A solution could be the ON
DELETE SET NULL. We should add this clause during the creation of the table (or ALTER, if the table is
already created):

| mysql> CREATE TABLE c(


| -> id INT AUTO_INCREMENT, id_a INT, id_b INT, lastName VARCHAR(20), PRIMARY
KEY(id),
| -> FOREIGN KEY(id_a) REFERENCES a(id) ON DELETE CASCADE,
| -> FOREIGN KEY(id_b) REFERENCES b(id) ON DELETE SET NULL) ENGINE=InnoDB;
| Query OK, 0 rows affected (0.08 sec)
And repeating last steps...

| mysql> INSERT INTO c(id_a,id_b,lastName) VALUES(1,1,'anderson');


| Query OK, 1 row affected (0.06 sec)
|
| mysql> DELETE FROM a WHERE user='zerocool';
| Query OK, 1 row affected (0.06 sec)
|-------------------------------------------------------

Hope be helpful

Posted by Martin Kobele on July 4, 2008

I found a fast way to delete a small subset of rows in a very big table (hundreds of thousands or millions):

You will need the to be deleted IDs in a temporary table which you might already have and you want to delete
only those IDs:

A naive way would be to do

DELETE FROM LargeTable WHERE ID IN (SELECT ID FROM TemporarySmallTable);

Given that LargeTable contains maybe 300,000-500,000 and


TemporarySmallTable ca 3,000-6,000 rows, this can take ca 300ms.

Instead, try this:

DELETE FROM LargeTable USING LargeTable INNER JOIN TemporarySmallTable ON LargeTable.ID =


TemporarySmallTable.ID;

This DELETE takes on the same database 1ms.

The trick is, that INNER JOIN will 'shrink' the LargeTable down to the size of the TemporarySmallTable and the
delete will operate on that smaller set only, since USING will reference to the joined table.

Posted by Omer Faruk EREN on March 10, 2009

I experienced a similiar situation today. I tried this statement:

delete m from members m where membersid in


(
select m.membersid from users u, members m, groups g
WHERE m.usersid=u.usersid AND m.groupsid=g.groupsid and g.groupsname='PARTI' and exists
( SELECT m2.membersid FROM users u2, members m2, groups g2
WHERE m2.usersid=u2.usersid AND m2.groupsid=g2.groupsid and g2.groupsname='MATRAX' and
u.usersid=u2.usersid)
);

The Error code was 1093 and explanation was "You can't specify target table 'm' for update in FROM clause".
The problem was that members(alias m) table is both the table that i wanted to delete and exists in inner
statement. I fund the solution with the temporary table.

Posted by Deepu vs on January 18, 2010

Delete all values in a table including auto increment values using following example

mysql>truncate tablename;

by

Deepu Surendran VS
OCS Technopark

Posted by Jim Leek on September 8, 2010

Deleting an individual duplicate entry.


===========================
Say you have a table with two identical entries:

+----------------+---------------------------+
| project_number | description |
+----------------+---------------------------+
| 06/XC/083 | Membrane Bioreactors |
| 06/XC/083 | Membrane bioreactors |
+----------------+---------------------------+

Obviously the following SQL will delete both entries:

DELETE FROM tbl_projects WHERE project_number = '06/XC/083' AND description = 'Membrane


Bioreactors';

Instead, to just delete a single entry and leave the other use the LIMIT clause:

DELETE FROM tbl_projects WHERE project_number = '06/XC/083' AND description = 'Membrane Bioreactors'
LIMIT 1;

Posted by Josh Mellicker on April 23, 2011

This worked for me, thanks to Omer above:

DELETE FROM sessionEventLog WHERE sessionEventLog.sessionID IN


(SELECT sessions.sessionID FROM sessions WHERE sessions.sourceID = 6);

Posted by Aleksey Midenkov on November 1, 2012

"The IGNORE keyword causes MySQL to ignore all errors during the process of deleting rows. (Errors
encountered during the parsing stage are processed in the usual manner.) Errors that are ignored due to the
use of IGNORE are returned as warnings."

That's not true for ERROR 1451. On foreign key constraint DELETE IGNORE blocks (in 5.0).
Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.3 DO Syntax
DO expr [, expr] ...
DO executes the expressions but does not return any results. In most respects, DO is shorthand
for SELECT expr, ..., but has the advantage that it is slightly faster when you do not care about
the result.
DO is useful primarily with functions that have side effects, such as RELEASE_LOCK().
Example: This SELECT statement pauses, but also produces a result set:
mysql> SELECT SLEEP(5);
+----------+
| SLEEP(5) |
+----------+
| 0 |
+----------+
1 row in set (5.02 sec)
DO, on the other hand, pauses without producing a result set.:
mysql> DO SLEEP(5);
Query OK, 0 rows affected (4.99 sec)
This could be useful, for example in a stored function or trigger, which prohibit statements that
produce result sets.

DO only executes expressions. It cannot be used in all cases where SELECT can be used. For
example, DO id FROM t1 is invalid because it references a table.

13.2.4 HANDLER Syntax


HANDLER tbl_name OPEN [ [AS] alias]

HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)


[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]

HANDLER tbl_name CLOSE


The HANDLER statement provides direct access to table storage engine interfaces. It is available
for InnoDB and MyISAM tables.
The HANDLER ... OPEN statement opens a table, making it accessible using subsequent HANDLER
... READ statements. This table object is not shared by other sessions and is not closed until the
session calls HANDLER ... CLOSE or the session terminates.
If you open the table using an alias, further references to the open table with
other HANDLER statements must use the alias rather than the table name. If you do not use an alias,
but open the table using a table name qualified by the database name, further references must use
the unqualified table name. For example, for a table opened using mydb.mytable, further
references must use mytable.
The first HANDLER ... READ syntax fetches a row where the index specified satisfies the given
values and the WHERE condition is met. If you have a multiple-column index, specify the index
column values as a comma-separated list. Either specify values for all the columns in the index, or
specify values for a leftmost prefix of the index columns. Suppose that an index my_idx includes
three columns named col_a, col_b, and col_c, in that order. The HANDLER statement can specify
values for all three columns in the index, or for the columns in a leftmost prefix. For example:
HANDLER ... READ my_idx = (col_a_val,col_b_val,col_c_val) ...
HANDLER ... READ my_idx = (col_a_val,col_b_val) ...
HANDLER ... READ my_idx = (col_a_val) ...
To employ the HANDLER interface to refer to a table's PRIMARY KEY, use the quoted
identifier `PRIMARY`:
HANDLER tbl_name READ `PRIMARY` ...
The second HANDLER ... READ syntax fetches a row from the table in index order that matches
the WHERE condition.
The third HANDLER ... READ syntax fetches a row from the table in natural row order that matches
the WHERE condition. It is faster than HANDLER tbl_nameREAD index_name when a full table scan is
desired. Natural row order is the order in which rows are stored in a MyISAM table data file. This
statement works for InnoDB tables as well, but there is no such concept because there is no
separate data file.
Without a LIMIT clause, all forms of HANDLER ... READ fetch a single row if one is available. To
return a specific number of rows, include a LIMIT clause. It has the same syntax as for
the SELECT statement. See Section 13.2.9, SELECT Syntax.
HANDLER ... CLOSE closes a table that was opened with HANDLER ... OPEN.
There are several reasons to use the HANDLER interface instead of normal SELECT statements:
HANDLER is faster than SELECT:
A designated storage engine handler object is allocated for the HANDLER ... OPEN. The
object is reused for subsequent HANDLER statements for that table; it need not be
reinitialized for each one.
There is less parsing involved.

There is no optimizer or query-checking overhead.

The handler interface does not have to provide a consistent look of the data (for
example, dirty reads are permitted), so the storage engine can use optimizations
that SELECT does not normally permit.
HANDLER makes it easier to port to MySQL applications that use a low-level ISAM-like interface.
(See Section 14.20, InnoDB memcached Plugin for an alternative way to adapt applications
that use the key-value store paradigm.)
HANDLER enables you to traverse a database in a manner that is difficult (or even impossible) to
accomplish with SELECT. The HANDLER interface is a more natural way to look at data when
working with applications that provide an interactive user interface to the database.
HANDLER is a somewhat low-level statement. For example, it does not provide consistency. That
is, HANDLER ... OPEN does not take a snapshot of the table, and does not lock the table. This
means that after a HANDLER ... OPEN statement is issued, table data can be modified (by the
current session or other sessions) and these modifications might be only partially visible to HANDLER
... NEXT or HANDLER ... PREV scans.
An open handler can be closed and marked for reopen, in which case the handler loses its position
in the table. This occurs when both of the following circumstances are true:

Any session executes FLUSH TABLES or DDL statements on the handler's table.
The session in which the handler is open executes non-HANDLER statements that use tables.
TRUNCATE TABLE for a table closes all handlers for the table that were opened with HANDLER OPEN.
If a table is flushed with FLUSH TABLES tbl_name WITH READ LOCK was opened with HANDLER,
the handler is implicitly flushed and loses its position.

13.2.5 INSERT Syntax


13.2.5.1 INSERT ... SELECT Syntax
13.2.5.2 INSERT ... ON DUPLICATE KEY UPDATE Syntax
13.2.5.3 INSERT DELAYED Syntax
INSERT [LOW_PRIORITY | DELAYED |
HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
[(col_name [, col_name] ...)]
{VALUES | VALUE} (value_list)
[, (value_list)] ...
[ON DUPLICATE KEY UPDATE
assignment_list]

INSERT [LOW_PRIORITY | DELAYED |


HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
SET assignment_list
[ON DUPLICATE KEY UPDATE
assignment_list]

INSERT [LOW_PRIORITY |
HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...
[ON DUPLICATE KEY UPDATE
assignment_list]

value:
{expr | DEFAULT}

value_list:
value [, value] ...

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...
INSERT inserts new rows into an existing table. The INSERT ... VALUES and INSERT ...
SET forms of the statement insert rows based on explicitly specified values. The INSERT ...
SELECT form inserts rows selected from another table or tables. INSERT with an ON DUPLICATE
KEY UPDATE clause enables existing rows to be updated if a row to be inserted would cause a
duplicate value in a UNIQUE index or PRIMARY KEY.
For additional information about INSERT ... SELECT and INSERT ... ON DUPLICATE KEY
UPDATE, see Section 13.2.5.1, INSERT ... SELECT Syntax, andSection 13.2.5.2, INSERT ... ON
DUPLICATE KEY UPDATE Syntax.
In MySQL 5.7, the DELAYED keyword is accepted but ignored by the server. For the reasons for this,
see Section 13.2.5.3, INSERT DELAYED Syntax,
Inserting into a table requires the INSERT privilege for the table. If the ON DUPLICATE KEY
UPDATE clause is used and a duplicate key causes an UPDATE to be performed instead, the
statement requires the UPDATE privilege for the columns to be updated. For columns that are read
but not modified you need only the SELECT privilege (such as for a column referenced only on the
right hand side of an col_name=expr assignment in an ON DUPLICATE KEY UPDATE clause).
When inserting into a partitioned table, you can control which partitions and subpartitions accept new
rows. The PARTITION option takes a list of the comma-separated names of one or more partitions or
subpartitions (or both) of the table. If any of the rows to be inserted by a given INSERT statement do
not match one of the partitions listed, the INSERT statement fails with the error Found a row not
matching the given partition set. For more information and examples, see Section 22.5,
Partition Selection.
You can use REPLACE instead of INSERT to overwrite old rows. REPLACE is the counterpart
to INSERT IGNORE in the treatment of new rows that contain unique key values that duplicate old
rows: The new rows replace the old rows rather than being discarded. See Section 13.2.8,
REPLACE Syntax.
tbl_name is the table into which rows should be inserted. Specify the columns for which the
statement provides values as follows:
Provide a parenthesized list of comma-
separated column names following the
table name. In this case, a value for
each named column must be provided
by the VALUES list or
the SELECT statement.
If you do not specify a list of column
names for INSERT ...
VALUES or INSERT ... SELECT,
values for every column in the table
must be provided by the VALUES list or
the SELECT statement. If you do not
know the order of the columns in the
table, use DESCRIBE tbl_name to find
out.
A SET clause indicates columns
explicitly by name, together with the
value to assign each one.
Column values can be given in several ways:

If strict SQL mode is not enabled, any


column not explicitly given a value is
set to its default (explicit or implicit)
value. For example, if you specify a
column list that does not name all the
columns in the table, unnamed
columns are set to their default values.
Default value assignment is described
in Section 11.7, Data Type Default
Values. See also Section 1.8.3.3,
Constraints on Invalid Data.
If strict SQL mode is enabled,
an INSERT statement generates an
error if it does not specify an explicit
value for every column that has no
default value. SeeSection 5.1.8,
Server SQL Modes.
If both the column list and
the VALUES list are
empty, INSERT creates a row with
each column set to its default value:
INSERT INTO tbl_name ()
VALUES();
If strict mode is not enabled, MySQL
uses the implicit default value for any
column that has no explicitly defined
default. If strict mode is enabled, an
error occurs if any column has no
default value.

Use the keyword DEFAULT to set a


column explicitly to its default value.
This makes it easier to
write INSERT statements that assign
values to all but a few columns,
because it enables you to avoid writing
an incomplete VALUES list that does
not include a value for each column in
the table. Otherwise, you must provide
the list of column names corresponding
to each value in the VALUES list.
If a generated column is inserted into
explicitly, the only permitted value
is DEFAULT. For information about
generated columns,
see Section 13.1.18.8, CREATE
TABLE and Generated Columns.
In expressions, you can
use DEFAULT(col_name) to produce
the default value for column col_name.
Type conversion of an
expression expr that provides a
column value might occur if the
expression data type does not match
the column data type. Conversion of a
given value can result in different
inserted values depending on the
column type. For example, inserting
the string '1999.0e-2' into
an INT, FLOAT, DECIMAL(10,6),
or YEAR column inserts the
value 1999, 19.9921, 19.992100,
or 1999, respectively. The value stored
in the INT and YEARcolumns
is 1999 because the string-to-number
conversion looks only at as much of
the initial part of the string as may be
considered a valid integer or year. For
the FLOAT and DECIMAL columns, the
string-to-number conversion considers
the entire string a valid numeric value.
An expression expr can refer to any
column that was set earlier in a value
list. For example, you can do this
because the value for col2 refers
to col1, which has previously been
assigned:
INSERT INTO tbl_name
(col1,col2)
VALUES(15,col1*2);
But the following is not legal, because
the value for col1 refers to col2,
which is assigned after col1:
INSERT INTO tbl_name
(col1,col2)
VALUES(col2*2,15);
An exception occurs for columns that
contain AUTO_INCREMENT values.
Because AUTO_INCREMENT values are
generated after other value
assignments, any reference to
an AUTO_INCREMENT column in the
assignment returns a 0.
INSERT statements that use VALUES syntax can insert multiple rows. To do this, include multiple lists
of comma-separated column values, with lists enclosed within parentheses and separated by
commas. Example:
INSERT INTO tbl_name (a,b,c)
VALUES(1,2,3),(4,5,6),(7,8,9);
Each values list must contain exactly as many values as are to be inserted per row. The following
statement is invalid because it contains one list of nine values, rather than three lists of three values
each:

INSERT INTO tbl_name (a,b,c)


VALUES(1,2,3,4,5,6,7,8,9);
VALUE is a synonym for VALUES in this context. Neither implies anything about the number of values
lists, nor about the number of values per list. Either may be used whether there is a single values list
or multiple lists, and regardless of the number of values per list.
The affected-rows value for an INSERT can be obtained using the ROW_COUNT() SQL function or
the mysql_affected_rows() C API function. See Section 12.14, Information Functions,
and Section 27.8.7.1, mysql_affected_rows().
If you use an INSERT ... VALUES statement with multiple value lists or INSERT ... SELECT, the
statement returns an information string in this format:
Records: N1 Duplicates: N2
Warnings: N3
If you are using the C API, the information string can be obtained by invoking
the mysql_info() function. See Section 27.8.7.36, mysql_info().
Records indicates the number of rows processed by the statement. (This is not necessarily the
number of rows actually inserted because Duplicates can be nonzero.) Duplicates indicates the
number of rows that could not be inserted because they would duplicate some existing unique index
value. Warningsindicates the number of attempts to insert column values that were problematic in
some way. Warnings can occur under any of the following conditions:
Inserting NULL into a column that has
been declared NOT NULL. For multiple-
row INSERT statements or INSERT
INTO ... SELECT statements, the
column is set to the implicit default
value for the column data type. This
is 0 for numeric types, the empty string
('') for string types, and
the zero value for date and time
types. INSERT INTO ...
SELECT statements are handled the
same way as multiple-row inserts
because the server does not examine
the result set from the SELECT to see
whether it returns a single row. (For a
single-row INSERT, no warning occurs
when NULL is inserted into a NOT
NULL column. Instead, the statement
fails with an error.)
Setting a numeric column to a value
that lies outside the column's range.
The value is clipped to the closest
endpoint of the range.

Assigning a value such as '10.34


a' to a numeric column. The trailing
nonnumeric text is stripped off and the
remaining numeric part is inserted. If
the string value has no leading numeric
part, the column is set to 0.
Inserting a string into a string column
(CHAR, VARCHAR, TEXT, or BLOB) that
exceeds the column's maximum
length. The value is truncated to the
column's maximum length.
Inserting a value into a date or time
column that is illegal for the data type.
The column is set to the appropriate
zero value for the type.

If INSERT inserts a row into a table that has an AUTO_INCREMENT column, you can find the value
used for that column by using the LAST_INSERT_ID() SQL function or the mysql_insert_id() C
API function.
Note
These two functions do not always behave identically. The behavior of INSERT statements with
respect to AUTO_INCREMENT columns is discussed further in Section 12.14, Information Functions,
and Section 27.8.7.38, mysql_insert_id().
The INSERT statement supports the following modifiers:
If you use the LOW_PRIORITY modifier,
execution of the INSERT is delayed
until no other clients are reading from
the table. This includes other clients
that began reading while existing
clients are reading, and while
the INSERT LOW_PRIORITY statement
is waiting. It is possible, therefore, for a
client that issues an INSERT
LOW_PRIORITY statement to wait for a
very long time.
LOW_PRIORITY affects only storage
engines that use only table-level
locking (such as MyISAM, MEMORY,
and MERGE).
Note
LOW_PRIORITY should
normally not be used
with MyISAM tables because
doing so disables concurrent
inserts. See Section 8.11.3,
Concurrent Inserts.
If you specify HIGH_PRIORITY, it
overrides the effect of the --low-
priority-updates option if the
server was started with that option. It
also causes concurrent inserts not to
be used. See Section 8.11.3,
Concurrent Inserts.
HIGH_PRIORITY affects only storage
engines that use only table-level
locking (such as MyISAM, MEMORY,
and MERGE).
If you use the IGNORE modifier, errors
that occur while executing
the INSERT statement are ignored. For
example, without IGNORE, a row that
duplicates an existing UNIQUE index
or PRIMARY KEY value in the table
causes a duplicate-key error and the
statement is aborted. With IGNORE, the
row is discarded and no error occurs.
Ignored errors generate warnings
instead.
IGNORE has a similar effect on inserts
into partitioned tables where no
partition matching a given value is
found. Without IGNORE,
such INSERT statements are aborted
with an error. When INSERT
IGNORE is used, the insert operation
fails silently for rows containing the
unmatched value, but inserts rows that
are matched. For an example,
see Section 22.2.2, LIST Partitioning.
Data conversions that would trigger
errors abort the statement if IGNORE is
not specified. With IGNORE, invalid
values are adjusted to the closest
values and inserted; warnings are
produced but the statement does not
abort. You can determine with
the mysql_info() C API function how
many rows were actually inserted into
the table.
For more information, see Comparison
of the IGNORE Keyword and Strict
SQL Mode.
If you specify ON DUPLICATE KEY
UPDATE, and a row is inserted that
would cause a duplicate value in
a UNIQUE index or PRIMARY KEY,
an UPDATE of the old row occurs. The
affected-rows value per row is 1 if the
row is inserted as a new row, 2 if an
existing row is updated, and 0 if an
existing row is set to its current values.
If you specify
the CLIENT_FOUND_ROWS flag to
the mysql_real_connect() C API
function when connecting to mysqld,
the affected-rows value is 1 (not 0) if
an existing row is set to its current
values. See Section 13.2.5.2, INSERT
... ON DUPLICATE KEY UPDATE
Syntax.
INSERT DELAYED was deprecated in
MySQL 5.6, and is scheduled for
eventual removal. In MySQL 5.7,
the DELAYED modifier is accepted but
ignored.
Use INSERT (without DELAYED)
instead. See Section 13.2.5.3,
INSERT DELAYED Syntax.
An INSERT statement affecting a partitioned table using a storage engine such as MyISAM that
employs table-level locks locks only those partitions into which rows are actually inserted. (For
storage engines such as InnoDB that employ row-level locking, no locking of partitions takes place.)
For more information, seeSection 22.6.4, Partitioning and Locking.

PREV HOME UP NEXT


User Comments
Posted by Yakov on July 8, 2003
To insert special characters, like the "apostrophe" read the section on string
syntax: http://www.mysql.com/doc/en/String_syntax.html

Here's an example:
insert into Citylist (cityname) VALUES ('St. John\'s')

Posted by Csongor Fagyal on September 8, 2004


Please note: "INSERT... ON DUPLICATE KEY UPDATE..." can also use a compound (unique) key to check for
duplication. This is very userful. For example:
If you have a log table to log hits to different websites daily, with "site_id"-s and "time" fields, where neither of
them are primary keys, but togethether they are unique, then you can create a key on them, and then use
"...ON DUPLICATE KEY..."

Table logs:
id: INT(11) auto_increment primary key
site_id: INT(11)
time: DATE
hits: INT(11)

Then:
CREATE UNIQUE INDEX comp ON logs (`site_id`, `time`);

And then you can:


INSERT INTO logs (`site_id`, `time`,`hits`) VALUES (1,"2004-08-09", 15) ON DUPLICATE KEY UPDATE
hits=hits+15;

Excellent feature, and it is much faster and briefer then using first a select, then issuing either an update or an
insert depending on the value of the select. You also get rid of the probably necessary table-lock during this
action.

Posted by Jason McManus on October 16, 2004


When using the INSERT ... ON DUPLICATE KEY UPDATE statement, the returned value is as follows:

1 for each successful INSERT.


2 for each successful UPDATE.

For example, if you insert 5 rows with this syntax, and 3 of them were inserted while 2 were updated, the return
value would be 7:
((3 inserts * 1) + (2 updates * 2)) = 7.

The return value may at first appear worrisome, as only 5 rows in the table were actually modified, but actually
provides more information, because you can determine the quantities of each query type performed from the
return value.

For further information, see:


http://bugs.mysql.com/bug.php?id=2709

Posted by Dark Lady on January 10, 2005


Fusion des fiches / How to make a file fusion and save it in a new table?

Le code suivant permet de crer une nouvelle table appele "fusion" avec les champs partition en, classe,
segment, F tot, F loc et indice specif.

CREATE TABLE `fusion` (


`partition en` VARCHAR( 11 ) NOT NULL,
`classe` VARCHAR( 11 ) NOT NULL,
`segment` TEXT NOT NULL ,
`F tot` INT NOT NULL ,
`F loc` INT NOT NULL ,
`indice specif` INT NOT NULL
);

On peut mettre la suite de ce code, le code suivant autant de fois que voulu qui permet de fusionner les
tables dans la nouvelle table "fusion":

INSERT INTO l4stal13prema00.`fusion` ( `partition en` ,


`classe` ,
`segment` ,
`F tot` ,
`F loc` ,
`indice specif` )
SELECT *
FROM f3p1
WHERE 1;

INSERT INTO l4stal13prema00.`fusion` ( `partition en` ,


`classe` ,
`segment` ,
`F tot` ,
`F loc` ,
`indice specif` )
SELECT *
FROM f3p2
WHERE 1;

Posted by Dark Lady on January 10, 2005


Eviter les rptitions grce count(Segment)/ How to avoid REPETITIONS and save it in a new table with
COUNT and INSERT ?

http://dev.mysql.com/doc/mysql/en/Counting_rows.html

If you know another way when inserting several files with almost the same data (cat dog turtle + cat dog parrot=
cat dog turtle parrot) and avoid repetition, tell it please?

Posted by Rolf Kleef on January 27, 2005


Perhaps it's good to add a reference in the part on the ON DUPLICATE KEY feature to the older REPLACE
function, which does a DELETE+INSERT instead of an UPDATE in case of existing key/unique values.

Posted by Andr Somplatzki on March 22, 2005


If you do an "INSERT ... ON DUPLICATE KEY UPDATE ..." and neither an insert is possible (because of
duplicate keys) nor an update is necessary (because of identical values) you get "2 affected rows" anyway.

Posted by Allen Morris on August 14, 2006


If you need plan to get the LAST_INSERT_ID() from a INSERT ... ON DUPLICATE KEY. use ``insert into ... on
duplicate key id = LAST_INSERT_ID(id), ...;''

If you do this then SELECT LAST_INSERT_ID() will return either the inserted id or the updated id.

Posted by Jun-Dai Bates-Kobashigawa on August 18, 2005


I haven't seen this mentioned elsewhere on this page, but you can use a SELECT statement as a single value
if it returns a single value. For example, if we have two tables, t1 and t2:

CREATE TABLE t1 (
a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b VARCHAR(10)) TYPE=InnoDB;

INSERT INTO t1 (b) VALUES ('Spike'), ('Chip'), ('John');

CREATE TABLE t2 (
a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b INT NOT NULL,
FOREIGN KEY (b) REFERENCES t1 (a),
c VARCHAR(15)) TYPE=InnoDB;

We can INSERT rows into t2 that populate the foreign key column based on a SELECT statement on t1:

INSERT INTO t2 (b, c)


VALUES ((SELECT a FROM t1 WHERE b='Chip'), 'shoulder'),
((SELECT a FROM t1 WHERE b='Chip'), 'old block'),
((SELECT a FROM t1 WHERE b='John'), 'toilet'),
((SELECT a FROM t1 WHERE b='John'), 'long,silver'),
((SELECT a FROM t1 WHERE b='John'), 'li''l');

Then we get:
mysql> SELECT * FROM t2;

+---+---+-------------+
| a | b | c |
+---+---+-------------+
| 1 | 2 | shoulder |
| 2 | 2 | old block |
| 3 | 3 | toilet |
| 4 | 3 | long,silver |
| 5 | 3 | li'l |
+---+---+-------------+
5 rows in set (0.00 sec)

This is especially useful if you don't want to specify the ids for your rows (because they may differ from
database to database, due to their being based on AUTO_INCREMENTs), but you want to refer to the values
of other tables.

I haven't tested this to determine the version of MySQL this was introduced into, or whether it is necessary that
the tables be InnoDB, but it works on my boxes (MySQL 4.1.12)

Posted by Laurent Sarlette on April 28, 2006


If you want to add to a tableA a column existing in a tableB:

1) Create an empty column in the tableA:

ALTER TABLE tableA ADD color CHAR(20);

2) If you don't have an auto-incrementation in the two tables (tableB for exemple):
ALTER TABLE tableB ADD (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id));

3) Fill the columns with the values:

UPDATE tableA,tableB SET tableA.color=tableB.color WHERE tableA.id=tableB.id;

Posted by Jan Jdrzejczyk on October 10, 2006


If you want to combine insert..select with setting an explicit value for a column - you can use join:

INSERT INTO TargetTable (col1, col2, col3)


SELECT col1,col2,col3
FROM SourceTable JOIN (SELECT 'ExplicitValue' AS col3) AS AnyAlias

This looks quite simple but it took me several hours to understand that there's no need for a special statement
to handle such cases.

Regards!

Posted by Diego d'Ippolito on December 15, 2006


To Jan Jdrzejczyk:

> INSERT INTO TargetTable (col1, col2, col3)


> SELECT col1,col2,col3
> FROM SourceTable
> JOIN (SELECT 'ExplicitValue' AS col3) AS AnyAlias

You could easily do the same thing just by using:

INSERT INTO TargetTable (col1, col2, col3)


SELECT col1,col2, 'ExplicitValue'
FROM SourceTable

hth,

Lokar

Posted by Justin Sheckler on July 11, 2007


I've just discovered that the UPDATE part of the INSERT ... ON DUPLICATE KEY UPDATE syntax doesn't
replicate to my slave servers. REPLACE works OK and is only slightly slower. This is with server version
5.0.36sp1-enterprise-gpl-log. I wouldn't recommend anyone use the INSERT ... UPDATE syntax in a replication
environment.

Posted by aleem latif on July 30, 2008


If you want to INSERT multiple records using single statement in MS SQL Server, then the syntax for MySQL
wont work. But you can use this insert command to accomplish the same:

INSERT INTO tbl_test (FirstName)


SELECT 'Aleem'
UNION ALL
SELECT 'Latif'
UNION ALL
SELECT 'Mughal'

Posted by Allan Kelly on March 11, 2010


With PHP, I use affected_rows to detect the success of an INSERT IGNORE. This is useful if you need to know
whether an INSERT occurred, and is necessary because IGNORE suppresses errors.
PHP code below outputs:
r==1
r==0

Cheers, al.

<?php
$myi = new mysqli("localhost", "user", "pass", "dbname");
$myi->query( <<<SQL_CREATE
create temporary table test_warnings
(
`id_` int(11) NOT NULL,
`num_` int(11) default NULL,
PRIMARY KEY (`id_`)
);
SQL_CREATE
);
$sth=$myi-
>prepare("insert ignore into test_warnings (id_, num_) values (?,?)");
$id = 9;
$num = 1;
for( $i=0; $i<2; $i++ )
{
$sth->bind_param( "ii", $id, $num );
$sth->execute();
$r = $myi->affected_rows;
print "r==$r\n<br>";
$sth->reset;
}
$sth->close();
?>

Posted by Randy Amos on March 5, 2010


I love the examples here from the community, here's what I used to add some recovered backup records to an
existing prod table (making sure the old records in prod were deleted first!):

INSERT INTO prod_table


(col1,
col2,
col3
)
SELECT * FROM bkup_table;

Hope this helps somebody.

Posted by Devang Modi on August 30, 2011


Combine queries for Insert and Select always obeys Innodb locking rules
if one of the source table is based on Innodb engine.
It is also possible that the INSERT activity applicable to TEMPORARY
table which is not InnoDB engine. It is also possible that in SELECT
section with INNODB, some other TEMPORARY Tables are used.
Devang Modi
Posted by Elliot Greene on September 28, 2011
I find this way is good to avoid Duplicated rows when inserting rows.

INSERT INTO users VALUES (userid='billgates', password='someword', name='Bill Gates', telephone='480-


456-9344') ON DUPLICATE KEY UPDATE userid='billgates';

This record will not be inserted as the username is already in the database other fields can be used.

Regards,
Elliot
http://www.sioure.com

Posted by William Ward on February 7, 2012


One major caveat may come up for those who wish to use NDB Cluster databases with Insert-Select
statements and an auto-incrementing ID: if the auto-incrementing ID needs to be processed in serial order, you
may have 32 row holes in the table that are backfilled out of order. This can be especially vexing if you are
doing processing the data in near real-time and using the auto-incrementing IDs for a High Water Mark.

For example, take these tables:

CREATE TABLE t1 (
a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b INT NOT NULL,
c VARCHAR(15)) ENGINE=ndbluster;

CREATE TABLE t2 (
a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b INT NOT NULL,
c VARCHAR(15)) ENGINE=ndbluster;

And this psuedocode running on NDB node 3:


int b=0;
while (b<1000) {
INSERT INTO t1 (b,c) VALUES ($b,Node 3);
b++;
sleep(1);
}

This psuedocode running on NDB node 4:

int b=0;
while (b<1000) {
for (int x=0;x<10; x++) {
INSERT INTO t2(b,c) VALUES ($b,Node 4);
b++;
sleep(1);
}
INSERT INTO t1(b,c) SELECT (b,c) FROM t2;
DELETE FROM t2;
}

This will result in holes that are backfilled in t1. After a run, this would be the first 100 rows of
SELECT * FROM t1 ORDER BY a;
---------------------------------

| a |b |c |
---------------------------------
|0 |0 |Node 3 |
|1 |1 |Node 3 |
|2 |2 |Node 3 |
|3 |3 |Node 3 |
|4 |4 |Node 3 |
|5 |5 |Node 3 |
|6 |6 |Node 3 |
|7 |7 |Node 3 |
|8 |8 |Node 3 |
|9 |9 |Node 3 |
|10 |0 |Node 4 |
|11 |1 |Node 4 |
| 12 |2 |Node 4 |
|13 |3 |Node 4 |
|14 |4 |Node 4 |
|15 |5 |Node 4 |
|16 |6 |Node 4 |
|17 |7 |Node 4 |
|18 |8 |Node 4 |
|19 |9 |Node 4 |
|20 |10 |Node 4 |
|21 |11 |Node 4 |
|22 |12 |Node 4 |
|23 |13 |Node 4 |
|24 |14 |Node 4 |
|25 |15 |Node 4 |
|26 |16 |Node 4 |
|27 |17 |Node 4 |
|28 |18 |Node 4 |
|29 |19 |Node 4 |
|30 |20 |Node 4 |
|31 |21 |Node 4 |
|32 |22 |Node 4 |
|33 |23 |Node 4 |
|34 |24 |Node 4 |
|35 |25 |Node 4 |
|36 |26 |Node 4 |
|37 |27 |Node 4 |
|38 |28 |Node 4 |
|39 |29 |Node 4 |
|40 |30 |Node 4 |
|41 |31 |Node 4 |
|42 |10 |Node 3 |
|43 |11 |Node 3 |
|44 |12 |Node 3 |
|45 |13 |Node 3 |
|46 |14 |Node 3 |
|47 |15 |Node 3 |
|48 |16 |Node 3 |
|49 |17 |Node 3 |
|50 |18 |Node 3 |
|51 |19 |Node 3 |
|52 |20 |Node 3 |
|53 |21 |Node 3 |
|54 |22 |Node 3 |
|55 |23 |Node 3 |
|56 |24 |Node 3 |
|57 |25 |Node 3 |
|58 |26 |Node 3 |
|59 |27 |Node 3 |
|60 |28 |Node 3 |
|61 |29 |Node 3 |
|62 |30 |Node 3 |
|63 |31 |Node 3 |
|64 |32 |Node 3 |
|65 |33 |Node 3 |
|66 |34 |Node 3 |
|67 |35 |Node 3 |
|68 |36 |Node 3 |
|69 |37 |Node 3 |
|70 |38 |Node 3 |
|71 |39 |Node 3 |
|72 |32 |Node 4 |
|73 |33 |Node 4 |
|74 |34 |Node 4 |
|75 |35 |Node 4 |
|76 |36 |Node 4 |
|77 |37 |Node 4 |
|78 |38 |Node 4 |
|79 |39 |Node 4 |
|80 |40 |Node 4 |
|81 |41 |Node 4 |
|82 |42 |Node 4 |
|83 |43 |Node 4 |
|84 |44 |Node 4 |
|85 |45 |Node 4 |
|86 |46 |Node 4 |
|87 |47 |Node 4 |
|88 |48 |Node 4 |
|89 |49 |Node 4 |
|90 |50 |Node 4 |
|91 |51 |Node 4 |
|92 |52 |Node 4 |
|93 |53 |Node 4 |
|94 |54 |Node 4 |
|95 |55 |Node 4 |
|96 |56 |Node 4 |
|97 |57 |Node 4 |
|98 |58 |Node 4 |
|99 |59 |Node 4 |

SELECT MAX(a) FROM t1;

will return 2008 as the highest in use a value, even though the table would have only 2000 actual results.

This has serious implications for using a as a High Water Mark; because node 4 backfilled t1 (node 3 jumped
from inserting into a=9 to a=42 above, and from a=71 to a=104), the HWM will miss node4 values. This is a
direct result of behavior modified for bug 31956:

ndb_autoincrement_prefetch_sz to specify prefetch between statements, changed default to1 (with internal
prefetch to at least 32 inside a statement), added handling of updates of pk/unique key with auto_increment

Becasue an Insert-Select does not know how many rows will be returned, 32 rows will be allocated, and will
continue to be used until exhausted, regardless of if 10 rows at a time are moved, or 1 (if x had only been
allowed to grow to 1, for example, a=1 would have had 'Node 4' while the second 'Node 3' row would have
been a=33). Therefore, it is NOT recommended to use Insert-Select statements with Cluster databases if the
auto-incrementing ID is meant to imply an absolute order on the timing of insertion into a table. The developer
will need to explicitly pull out each row from t2 and insert them individually into t1 for the desired effect.

Posted by Jon Vance on November 1, 2012


I have discovered something that can be VERY important if you don't know about it. When using INSERT
IGNORE, insert triggers are STILL FIRED when a duplicate key constraint prevents new rows from being
inserted.

Posted by Ben Lin on March 12, 2014


A note about "Insert Ignore":

If one column of the unique key is null, then no duplicate-error is catch, and duplicate entry can be inserted.

For example, you have a unique key (`id`, `second`), but the `second` is null when inserted:

drop table if exists import_temp.test;


create table import_temp.test(
`id` int(11) NOT NULL,
`second` int DEFAULT NULL,
UNIQUE KEY `i` (`id`, `second`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into import_temp.test(id, second)


values(1, null);
insert ignore into import_temp.test(id, second)
values(1, null);

then you have 2 entries of (1, null) in the table, opposing to the unique key of (`id`, `second`).

Posted by Nathan Neulinger on April 18, 2015


Should note that this warning about inserts and nulls

"For multiple-row INSERT statements or INSERT INTO ... SELECT statements, the column is set to the implicit
default value for the column data type. This is 0 for numeric types, the empty string ('') for string types, and the
zero value for date and time types."

also appears to apply to a single row "replace into" query, which can be very confusing to debug when it
appears to not obey the table constraints and just turns nulls/missing columns into empty strings. This can
particularly be a problem if you have a unique constraint on one of those columns.

Posted by James Jensen on July 28, 2015


In the first comment, @Yakov posted a now-outdated link to string syntax. Here is the current link FWIW:

http://dev.mysql.com/doc/refman/5.1/en/string-literals.html

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

3.2.6 LOAD DATA INFILE Syntax


LOAD DATA [LOW_PRIORITY |
CONCURRENT] [LOCAL] INFILE
'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY
'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES |
ROWS}]
[(col_name_or_user_var
[, col_name_or_user_var]
...)]
[SET col_name={expr |
DEFAULT},
[, col_name={expr |
DEFAULT}] ...]
The LOAD DATA INFILE statement reads rows from a text file into a table at a very high
speed. LOAD DATA INFILE is the complement of SELECT ... INTO OUTFILE.
(See Section 13.2.9.1, SELECT ... INTO Syntax.) To write data from a table to a file, use SELECT
... INTO OUTFILE. To read the file back into a table, use LOAD DATA INFILE. The syntax of
the FIELDS and LINES clauses is the same for both statements. Both clauses are optional,
but FIELDS must precede LINES if both are specified.
You can also load data files by using the mysqlimport utility; it operates by sending a LOAD DATA
INFILE statement to the server. The --local option causesmysqlimport to read data files from the
client host. You can specify the --compress option to get better performance over slow networks if
the client and server support the compressed protocol. See Section 4.5.5, mysqlimport A Data
Import Program.
For more information about the efficiency of INSERT versus LOAD DATA INFILE and speeding
up LOAD DATA INFILE, see Section 8.2.4.1, Optimizing INSERT Statements.
The file name must be given as a literal string. On Windows, specify backslashes in path names as
forward slashes or doubled backslashes. Thecharacter_set_filesystem system variable
controls the interpretation of the file name.
LOAD DATA supports explicit partition selection using the PARTITION option with a list of one or
more comma-separated names of partitions, subpartitions, or both. When this option is used, if any
rows from the file cannot be inserted into any of the partitions or subpartitions named in the list, the
statement fails with the error Found a row not matching the given partition set. For
more information and examples, see Section 22.5, Partition Selection.
For partitioned tables using storage engines that employ table locks, such as MyISAM, LOAD
DATA cannot prune any partition locks. This does not apply to tables using storage engines which
employ row-level locking, such as InnoDB. For more information, see Section 22.6.4, Partitioning
and Locking.
The server uses the character set indicated by the character_set_database system variable to
interpret the information in the file. SET NAMES and the setting of character_set_client do not
affect interpretation of input. If the contents of the input file use a character set that differs from the
default, it is usually preferable to specify the character set of the file by using the CHARACTER
SET clause. A character set of binary specifies no conversion.
LOAD DATA INFILE interprets all fields in the file as having the same character set, regardless of
the data types of the columns into which field values are loaded. For proper interpretation of file
contents, you must ensure that it was written with the correct character set. For example, if you write
a data file withmysqldump -T or by issuing a SELECT ... INTO OUTFILE statement in mysql, be
sure to use a --default-character-set option so that output is written in the character set to be
used when the file is loaded with LOAD DATA INFILE.
Note
It is not possible to load data files that use the ucs2, utf16, utf16le, or utf32 character set.
If you use LOW_PRIORITY, execution of the LOAD DATA statement is delayed until no other clients
are reading from the table. This affects only storage engines that use only table-level locking (such
as MyISAM, MEMORY, and MERGE).
If you specify CONCURRENT with a MyISAM table that satisfies the condition for concurrent inserts
(that is, it contains no free blocks in the middle), other threads can retrieve data from the table
while LOAD DATA is executing. This option affects the performance of LOAD DATA a bit, even if no
other thread is using the table at the same time.
With row-based replication, CONCURRENT is replicated regardless of MySQL version. With statement-
based replication CONCURRENT is not replicated prior to MySQL 5.5.1 (see Bug #34628). For more
information, see Section 16.4.1.18, Replication and LOAD DATA INFILE.
The LOCAL keyword affects expected location of the file and error handling, as described
later. LOCAL works only if your server and your client both have been configured to permit it. For
example, if mysqld was started with the local_infile system variable disabled, LOCAL does not
work. See Section 6.1.6, Security Issues with LOAD DATA LOCAL.
The LOCAL keyword affects where the file is expected to be found:
If LOCAL is specified, the file is read by
the client program on the client host
and sent to the server. The file can be
given as a full path name to specify its
exact location. If given as a relative
path name, the name is interpreted
relative to the directory in which the
client program was started.
When using LOCAL with LOAD DATA, a
copy of the file is created in the
server's temporary directory. This
is not the directory determined by the
value
of tmpdir or slave_load_tmpdir,
but rather the operating system's
temporary directory, and is not
configurable in the MySQL Server.
(Typically the system temporary
directory is /tmp on Linux systems
and C:\WINDOWS\TEMP on Windows.)
Lack of sufficient space for the copy in
this directory can cause the LOAD
DATA LOCAL statement to fail.
If LOCAL is not specified, the file must
be located on the server host and is
read directly by the server. The server
uses the following rules to locate the
file:
If the file name is an absolute path
name, the server uses it as given.
If the file name is a relative path
name with one or more leading
components, the server searches
for the file relative to the server's
data directory.

If a file name with no leading


components is given, the server
looks for the file in the database
directory of the default database.

In the non-LOCAL case, these rules mean that a file named as ./myfile.txt is read from the
server's data directory, whereas the file named as myfile.txt is read from the database directory
of the default database. For example, if db1 is the default database, the following LOAD
DATA statement reads the filedata.txt from the database directory for db1, even though the
statement explicitly loads the file into a table in the db2 database:
LOAD DATA INFILE 'data.txt' INTO
TABLE db2.my_table;
Non-LOCAL load operations read text files located on the server. For security reasons, such
operations require that you have the FILE privilege. See Section 6.2.1, Privileges Provided by
MySQL. Also, non-LOCAL load operations are subject to the secure_file_priv system variable
setting. If the variable value is a nonempty directory name, the file to be loaded must be located in
that directory. If the variable value is empty (which is insecure), the file need only be readable by the
server.
Using LOCAL is a bit slower than letting the server access the files directly, because the contents of
the file must be sent over the connection by the client to the server. On the other hand, you do not
need the FILE privilege to load local files.
LOCAL also affects error handling:
With LOAD DATA INFILE, data-
interpretation and duplicate-key errors
terminate the operation.
With LOAD DATA LOCAL INFILE,
data-interpretation and duplicate-key
errors become warnings and the
operation continues because the
server has no way to stop transmission
of the file in the middle of the
operation. For duplicate-key errors, this
is the same as if IGNORE is
specified. IGNORE is explained further
later in this section.
The REPLACE and IGNORE keywords control handling of input rows that duplicate existing rows on
unique key values:
If you specify REPLACE, input rows
replace existing rows. In other words,
rows that have the same value for a
primary key or unique index as an
existing row. See Section 13.2.8,
REPLACE Syntax.
If you specify IGNORE, rows that
duplicate an existing row on a unique
key value are discarded. For more
information, see Comparison of the
IGNORE Keyword and Strict SQL
Mode.
If you do not specify either option, the
behavior depends on whether
the LOCAL keyword is specified.
Without LOCAL, an error occurs when a
duplicate key value is found, and the
rest of the text file is ignored.
With LOCAL, the default behavior is the
same as if IGNORE is specified; this is
because the server has no way to stop
transmission of the file in the middle of
the operation.
To ignore foreign key constraints during the load operation, issue a SET foreign_key_checks =
0 statement before executing LOAD DATA.
If you use LOAD DATA INFILE on an empty MyISAM table, all nonunique indexes are created in a
separate batch (as for REPAIR TABLE). Normally, this makesLOAD DATA INFILE much faster when
you have many indexes. In some extreme cases, you can create the indexes even faster by turning
them off with ALTER TABLE ... DISABLE KEYS before loading the file into the table and
using ALTER TABLE ... ENABLE KEYS to re-create the indexes after loading the file.
See Section 8.2.4.1, Optimizing INSERT Statements.
For both the LOAD DATA INFILE and SELECT ... INTO OUTFILE statements, the syntax of
the FIELDS and LINES clauses is the same. Both clauses are optional, but FIELDS must
precede LINES if both are specified.
If you specify a FIELDS clause, each of its subclauses (TERMINATED BY, [OPTIONALLY] ENCLOSED
BY, and ESCAPED BY) is also optional, except that you must specify at least one of them.
If you specify no FIELDS or LINES clause, the defaults are the same as if you had written this:
FIELDS TERMINATED BY '\t'
ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING
BY ''
(Backslash is the MySQL escape character within strings in SQL statements, so to specify a literal
backslash, you must specify two backslashes for the value to be interpreted as a single backslash.
The escape sequences '\t' and '\n' specify tab and newline characters, respectively.)
In other words, the defaults cause LOAD DATA INFILE to act as follows when reading input:
Look for line boundaries at newlines.

Do not skip over any line prefix.

Break lines into fields at tabs.

Do not expect fields to be enclosed


within any quoting characters.

Interpret characters preceded by the


escape character \ as escape
sequences. For example, \t, \n,
and \\ signify tab, newline, and
backslash, respectively. See the
discussion of FIELDS ESCAPED
BY later for the full list of escape
sequences.
Conversely, the defaults cause SELECT ... INTO OUTFILE to act as follows when writing output:
Write tabs between fields.

Do not enclose fields within any


quoting characters.

Use \ to escape instances of tab,


newline, or \ that occur within field
values.
Write newlines at the ends of lines.

Note
If you have generated the text file on a Windows system, you might have to use LINES TERMINATED
BY '\r\n' to read the file properly, because Windows programs typically use two characters as a
line terminator. Some programs, such as WordPad, might use \r as a line terminator when writing
files. To read such files, use LINES TERMINATED BY '\r'.
If all the lines you want to read in have a common prefix that you want to ignore, you can use LINES
STARTING BY 'prefix_string' to skip over the prefix, and anything before it. If a line does not
include the prefix, the entire line is skipped. Suppose that you issue the following statement:
LOAD DATA INFILE '/tmp/test.txt'
INTO TABLE test
FIELDS TERMINATED BY ',' LINES
STARTING BY 'xxx';
If the data file looks like this:

xxx"abc",1
something xxx"def",2
"ghi",3
The resulting rows will be ("abc",1) and ("def",2). The third row in the file is skipped because it
does not contain the prefix.
The IGNORE number LINES option can be used to ignore lines at the start of the file. For example,
you can use IGNORE 1 LINES to skip over an initial header line containing column names:
LOAD DATA INFILE '/tmp/test.txt'
INTO TABLE test IGNORE 1 LINES;
When you use SELECT ... INTO OUTFILE in tandem with LOAD DATA INFILE to write data from
a database into a file and then read the file back into the database later, the field- and line-handling
options for both statements must match. Otherwise, LOAD DATA INFILE will not interpret the
contents of the file properly. Suppose that you use SELECT ... INTO OUTFILE to write a file with
fields delimited by commas:
SELECT * INTO OUTFILE 'data.txt'
FIELDS TERMINATED BY ','
FROM table2;
To read the comma-delimited file back in, the correct statement would be:

LOAD DATA INFILE 'data.txt' INTO


TABLE table2
FIELDS TERMINATED BY ',';
If instead you tried to read in the file with the statement shown following, it wouldn't work because it
instructs LOAD DATA INFILE to look for tabs between fields:
LOAD DATA INFILE 'data.txt' INTO
TABLE table2
FIELDS TERMINATED BY '\t';
The likely result is that each input line would be interpreted as a single field.

LOAD DATA INFILE can be used to read files obtained from external sources. For example, many
programs can export data in comma-separated values (CSV) format, such that lines have fields
separated by commas and enclosed within double quotation marks, with an initial line of column
names. If the lines in such a file are terminated by carriage return/newline pairs, the statement
shown here illustrates the field- and line-handling options you would use to load the file:
LOAD DATA INFILE 'data.txt' INTO
TABLE tbl_name
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES;
If the input values are not necessarily enclosed within quotation marks, use OPTIONALLY before
the ENCLOSED BY keywords.
Any of the field- or line-handling options can specify an empty string (''). If not empty, the FIELDS
[OPTIONALLY] ENCLOSED BY and FIELDS ESCAPED BYvalues must be a single character.
The FIELDS TERMINATED BY, LINES STARTING BY, and LINES TERMINATED BY values can be
more than one character. For example, to write lines that are terminated by carriage return/linefeed
pairs, or to read a file containing such lines, specify a LINES TERMINATED BY '\r\n'clause.
To read a file containing jokes that are separated by lines consisting of %%, you can do this
CREATE TABLE jokes
(a INT NOT NULL AUTO_INCREMENT
PRIMARY KEY,
joke TEXT NOT NULL);
LOAD DATA INFILE '/tmp/jokes.txt'
INTO TABLE jokes
FIELDS TERMINATED BY ''
LINES TERMINATED BY '\n%%\n'
(joke);
FIELDS [OPTIONALLY] ENCLOSED BY controls quoting of fields. For output (SELECT ... INTO
OUTFILE), if you omit the word OPTIONALLY, all fields are enclosed by the ENCLOSED BY character.
An example of such output (using a comma as the field delimiter) is shown here:
"1","a string","100.20"
"2","a string containing a ,
comma","102.20"
"3","a string containing a \"
quote","102.20"
"4","a string containing a \",
quote and comma","102.20"
If you specify OPTIONALLY, the ENCLOSED BY character is used only to enclose values from
columns that have a string data type (such as CHAR, BINARY, TEXT, orENUM):
1,"a string",100.20
2,"a string containing a ,
comma",102.20
3,"a string containing a \"
quote",102.20
4,"a string containing a \",
quote and comma",102.20
Occurrences of the ENCLOSED BY character within a field value are escaped by prefixing them with
the ESCAPED BY character. Also, if you specify an empty ESCAPED BY value, it is possible to
inadvertently generate output that cannot be read properly by LOAD DATA INFILE. For example, the
preceding output just shown would appear as follows if the escape character is empty. Observe that
the second field in the fourth line contains a comma following the quote, which (erroneously)
appears to terminate the field:
1,"a string",100.20
2,"a string containing a ,
comma",102.20
3,"a string containing a "
quote",102.20
4,"a string containing a ", quote
and comma",102.20
For input, the ENCLOSED BY character, if present, is stripped from the ends of field values. (This is
true regardless of whether OPTIONALLY is specified;OPTIONALLY has no effect on input
interpretation.) Occurrences of the ENCLOSED BY character preceded by the ESCAPED BY character
are interpreted as part of the current field value.
If the field begins with the ENCLOSED BY character, instances of that character are recognized as
terminating a field value only if followed by the field or lineTERMINATED BY sequence. To avoid
ambiguity, occurrences of the ENCLOSED BY character within a field value can be doubled and are
interpreted as a single instance of the character. For example, if ENCLOSED BY '"' is specified,
quotation marks are handled as shown here:
"The ""BIG"" boss" -> The "BIG"
boss
The "BIG" boss -> The "BIG"
boss
The ""BIG"" boss -> The
""BIG"" boss
FIELDS ESCAPED BY controls how to read or write special characters:
For input, if the FIELDS ESCAPED
BY character is not empty, occurrences
of that character are stripped and the
following character is taken literally as
part of a field value. Some two-
character sequences that are
exceptions, where the first character is
the escape character. These
sequences are shown in the following
table (using \ for the escape
character). The rules for NULL handling
are described later in this section.
Character Escape Sequence
\0 An ASCII NUL (X'00') character
\b A backspace character
\n A newline (linefeed) character
\r A carriage return character
\t A tab character.
\Z ASCII 26 (Control+Z)
\N NULL
For more information about \-escape
syntax, see Section 9.1.1, String
Literals.
If the FIELDS ESCAPED BY character
is empty, escape-sequence
interpretation does not occur.
For output, if the FIELDS ESCAPED
BY character is not empty, it is used to
prefix the following characters on
output:
The FIELDS ESCAPED
BY character
The FIELDS [OPTIONALLY]
ENCLOSED BY character
The first character of the FIELDS
TERMINATED BY and LINES
TERMINATED BY values
ASCII 0 (what is actually written
following the escape character is
ASCII 0, not a zero-valued byte)
If the FIELDS ESCAPED BY character
is empty, no characters are escaped
and NULL is output as NULL, not \N. It
is probably not a good idea to specify
an empty escape character,
particularly if field values in your data
contain any of the characters in the list
just given.
In certain cases, field- and line-handling options interact:

If LINES TERMINATED BY is an empty


string and FIELDS TERMINATED BY is
nonempty, lines are also terminated
with FIELDS TERMINATED BY.
If the FIELDS TERMINATED
BY and FIELDS ENCLOSED BY values
are both empty (''), a fixed-row
(nondelimited) format is used. With
fixed-row format, no delimiters are
used between fields (but you can still
have a line terminator). Instead,
column values are read and written
using a field width wide enough to hold
all values in the field.
For TINYINT, SMALLINT, MEDIUMINT,
INT, and BIGINT, the field widths are
4, 6, 8, 11, and 20, respectively, no
matter what the declared display width
is.
LINES TERMINATED BY is still used to
separate lines. If a line does not
contain all fields, the rest of the
columns are set to their default values.
If you do not have a line terminator,
you should set this to ''. In this case,
the text file must contain all fields for
each row.
Fixed-row format also affects handling
of NULL values, as described later.
Note
Fixed-size format does not
work if you are using a
multibyte character set.
Handling of NULL values varies according to the FIELDS and LINES options in use:
For the
default FIELDS and LINES values, NUL
L is written as a field value of \N for
output, and a field value of \N is read
as NULL for input (assuming that
the ESCAPED BY character is \).
If FIELDS ENCLOSED BY is not empty,
a field containing the literal
word NULL as its value is read as
a NULL value. This differs from the
word NULL enclosed within FIELDS
ENCLOSED BY characters, which is
read as the string 'NULL'.
If FIELDS ESCAPED BY is
empty, NULL is written as the
word NULL.
With fixed-row format (which is used
when FIELDS TERMINATED
BY and FIELDS ENCLOSED BY are
both empty), NULL is written as an
empty string. This causes
both NULL values and empty strings in
the table to be indistinguishable when
written to the file because both are
written as empty strings. If you need to
be able to tell the two apart when
reading the file back in, you should not
use fixed-row format.
An attempt to load NULL into a NOT NULL column causes assignment of the implicit default value for
the column's data type and a warning, or an error in strict SQL mode. Implicit default values are
discussed in Section 11.7, Data Type Default Values.
Some cases are not supported by LOAD DATA INFILE:
Fixed-size rows (FIELDS TERMINATED
BY and FIELDS ENCLOSED BY both
empty) and BLOB or TEXT columns.
If you specify one separator that is the
same as or a prefix of another, LOAD
DATA INFILE cannot interpret the
input properly. For example, the
following FIELDS clause would cause
problems:
FIELDS TERMINATED BY '"'
ENCLOSED BY '"'

If FIELDS ESCAPED BY is empty, a
field value that contains an occurrence
of FIELDS ENCLOSED BY or LINES
TERMINATED BY followed by
the FIELDS TERMINATED BY value
causes LOAD DATA INFILE to stop
reading a field or line too early. This
happens because LOAD DATA
INFILE cannot properly determine
where the field or line value ends.
The following example loads all columns of the persondata table:
LOAD DATA INFILE 'persondata.txt'
INTO TABLE persondata;
By default, when no column list is provided at the end of the LOAD DATA INFILE statement, input
lines are expected to contain a field for each table column. If you want to load only some of a table's
columns, specify a column list:
LOAD DATA INFILE 'persondata.txt'
INTO TABLE persondata
(col1,col2,...);
You must also specify a column list if the order of the fields in the input file differs from the order of
the columns in the table. Otherwise, MySQL cannot tell how to match input fields with table columns.

The column list can contain either column names or user variables. With user variables,
the SET clause enables you to perform transformations on their values before assigning the result to
columns.
User variables in the SET clause can be used in several ways. The following example uses the first
input column directly for the value of t1.column1, and assigns the second input column to a user
variable that is subjected to a division operation before being used for the value of t1.column2:
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @var1)
SET column2 = @var1/100;
The SET clause can be used to supply values not derived from the input file. The following statement
sets column3 to the current date and time:
LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, column2)
SET column3 =
CURRENT_TIMESTAMP;
You can also discard an input value by assigning it to a user variable and not assigning the variable
to a table column:

LOAD DATA INFILE 'file.txt'


INTO TABLE t1
(column1, @dummy, column2,
@dummy, column3);
Use of the column/variable list and SET clause is subject to the following restrictions:
Assignments in the SET clause should
have only column names on the left
hand side of assignment operators.
You can use subqueries in the right
hand side of SET assignments. A
subquery that returns a value to be
assigned to a column may be a scalar
subquery only. Also, you cannot use a
subquery to select from the table that
is being loaded.
Lines ignored by an IGNORE clause are
not processed for the column/variable
list or SET clause.
User variables cannot be used when
loading data with fixed-row format
because user variables do not have a
display width.

When processing an input line, LOAD DATA splits it into fields and uses the values according to the
column/variable list and the SET clause, if they are present. Then the resulting row is inserted into
the table. If there are BEFORE INSERT or AFTER INSERT triggers for the table, they are activated
before or after inserting the row, respectively.
If an input line has too many fields, the extra fields are ignored and the number of warnings is
incremented.

If an input line has too few fields, the table columns for which input fields are missing are set to their
default values. Default value assignment is described inSection 11.7, Data Type Default Values.
An empty field value is interpreted different from a missing field:

For string types, the column is set to


the empty string.

For numeric types, the column is set


to 0.
For date and time types, the column is
set to the appropriate zero value for
the type. See Section 11.3, Date and
Time Types.
These are the same values that result if you assign an empty string explicitly to a string, numeric, or
date or time type explicitly in an INSERT or UPDATEstatement.
Treatment of empty or incorrect field values differs from that just described if the SQL mode is set to
a restrictive value. For example, if sql_mode is set toTRADITIONAL, conversion of an empty value or
a value such as 'x' for a numeric column results in an error, not conversion to 0.
(With LOCAL or IGNORE, warnings occur rather than errors, even with a restrictive sql_mode value,
and the row is inserted using the same closest-value behavior used for nonrestrictive SQL modes.
This occurs because the server has no way to stop transmission of the file in the middle of the
operation.)
TIMESTAMP columns are set to the current date and time only if there is a NULL value for the column
(that is, \N) and the column is not declared to permit NULLvalues, or if the TIMESTAMP column's
default value is the current timestamp and it is omitted from the field list when a field list is specified.
LOAD DATA INFILE regards all input as strings, so you cannot use numeric values
for ENUM or SET columns the way you can with INSERT statements. All ENUMand SET values must be
specified as strings.
BIT values cannot be loaded directly using binary notation (for example, b'011010'). To work
around this, use the SET clause to strip off the leading b' and trailing ' and perform a base-2 to
base-10 conversion so that MySQL loads the values into the BIT column properly:
shell> cat /tmp/bit_test.txt
b'10'
b'1111111'
shell> mysql test
mysql> LOAD DATA INFILE
'/tmp/bit_test.txt'
INTO TABLE bit_test
(@var1)
SET b =
CAST(CONV(MID(@var1, 3,
LENGTH(@var1)-3), 2, 10) AS
UNSIGNED);
Query OK, 2 rows affected (0.00
sec)
Records: 2 Deleted: 0 Skipped:
0 Warnings: 0

mysql> SELECT BIN(b+0) FROM


bit_test;
+----------+
| BIN(b+0) |
+----------+
| 10 |
| 1111111 |
+----------+
2 rows in set (0.00 sec)
For BIT values in 0b binary notation (for example, 0b011010), use this SET clause instead to strip
off the leading 0b:
SET b = CAST(CONV(MID(@var1, 3,
LENGTH(@var1)-2), 2, 10) AS
UNSIGNED)
On Unix, if you need LOAD DATA to read from a pipe, you can use the following technique (the
example loads a listing of the / directory into the table db1.t1):
mkfifo /mysql/data/db1/ls.dat
chmod 666 /mysql/data/db1/ls.dat
find / -ls >
/mysql/data/db1/ls.dat &
mysql -e "LOAD DATA INFILE
'ls.dat' INTO TABLE t1" db1
Here you must run the command that generates the data to be loaded and the mysql commands
either on separate terminals, or run the data generation process in the background (as shown in the
preceding example). If you do not do this, the pipe will block until data is read by the mysql process.
When the LOAD DATA INFILE statement finishes, it returns an information string in the following
format:
Records: 1 Deleted: 0 Skipped:
0 Warnings: 0
Warnings occur under the same circumstances as when values are inserted using
the INSERT statement (see Section 13.2.5, INSERT Syntax), except that LOAD DATA INFILE also
generates warnings when there are too few or too many fields in the input row.
You can use SHOW WARNINGS to get a list of the first max_error_count warnings as information
about what went wrong. See Section 13.7.5.40, SHOW WARNINGS Syntax.
If you are using the C API, you can get information about the statement by calling
the mysql_info() function. See Section 27.8.7.36, mysql_info().

PREV HOME UP NEXT


User Comments
Posted by Ramam Pullella on August 20, 2007
Converting strings into dates while loading data using LOAD DATA INFILE:

In the following example, we are trying to convert the data in the file for date columns col3, col4 in formats
'mm/dd/yyyy', 'dd/mm/yyyy' into MySQL standard YYYY-mm-dd respectively.

load data infile '/tmp/xxx.dat'


into table xxx
fields terminated by '|'
lines terminated by '\n'
(col1,
col2,
@col3,
@col4,
col5)
set
col3 = str_to_date(@col3, '%m/%d/%Y'),
col4 = str_to_date(@col4, '%d/%m/%Y')
;

You could convert into any format you want by using the date_format function around the str_to_date().

Example:
...
set col2 = date_format(str_to_date(@col2, 'format'), 'your format')

Posted by Jeremy Krieg on December 4, 2007


I just ran into the same problem that the first two posters (Nathan Nuebner and Robert Lee) had with fixed-
width imports. I suspect that the reason for this behaviour derives from the following statement from the above
documentation:

'...column values are read and written using a field width wide enough to hold all values in the field.'

If you have a VARCHAR(20) column in a multi-byte character set (eg, UTF8), then the "field width wide enough
to hold all values" in this field, measured in bytes, will actually be somewhat greater than 20. The two
workarounds above worked because they both specified character sets which allocate one byte per character
(latin1 and binary).

Specifying the character set in the LOAD DATA INFILE statement does not seem to work around the problem -
that seems only to affect the incoming conversion from bytes to characters, it doesn't affect the number of
bytes read.

The Latin1/binary examples above worked because they weren't trying to load multi-byte characters, however
for someone who was trying to import multi-byte characters (or more specifically, to import character sets like
UTF8 that use variable-width encoding for the characters) it would not work. There doesn't appear to be an
easy workaround that I can see except to write an import utility in another programming language like Perl,
Java or C.

Posted by Ryan Neve on July 18, 2008


To load a text file with fixed width columns, I used the form:
LOAD DATA LOCAL INFILE '<file name>' INTO TABLE <table>
(@var1)
SET Date=str_to_date(SUBSTR(@var1,3,10),'%m/%d/%Y'),
Time=SUBSTR(@var1,14,8),
WindVelocity=SUBSTR(@var1,26,5),
WindDirection=SUBSTR(@var1,33,3),
WindCompass=SUBSTR(@var1,38,3),
WindNorth=SUBSTR(@var1,43,6),
WindEast=SUBSTR(@var1,51,6),
WindSamples=SUBSTR(@var1,61,4);

Posted by lvaro G. Vicario on January 28, 2013


Importing floating point numbers that use comma as decimal separator requires the same trick than dates:

LOAD DATA LOCAL INFILE 'C:/path/to/mytable.txt' IGNORE


INTO TABLE mytable
FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'
(int_col, @float_col)
SET float_col = replace(@float_col, ',', '.');

MySQL casts the value into the column type when it reads it from the file, *before* applying the transformations
described in the SET clause. If you instruct it to read it into a variable the value is handled as string from the
beginning.

Posted by Clive le Roux on February 2, 2009


If you get "Skipped records" using "LOAD DATA LOCAL INFILE" copy the data file to the actual database
server and do the load without the "LOCAL" keyword.
This will then stop when an error occurs, 9 times out of 10 it will be index issues and you will know why there
are skipped records.

e.g. LOAD DATA LOCAL INFILE 'myinfile.txt';


Query OK, 288168 rows affected (1 min 44.49 sec)
Records: 494522 Deleted: 0 Skipped: 206354 Warnings: 0

LOAD DATA INFILE '/data/input/myinfile.txt';


Query OK, 252243 rows affected (0.02 sec)
ERROR 1062 (23000): Duplicate entry '5935009001-2008-08-03 04:19:18' for key 1

Posted by Mattias Andersson on April 7, 2009


I've looked for a way to conditionally ignore rows in an INFILE for a long time. There may be an obvious way to
do this but I have never seen one.
Today I discovered a very neat way to achieve this.
Assume that you are have an INFILE Containing names and genders of people. In my case, the INFILE has
fixed fields. The first column is either 1 (=Male) or 2 (=Female) and column 2-18 contains the name of the
person.

Now, if you would want to load the males (row[0] == 1) only, create the following table.

CREATE TABLE Names


(
name varchar(255),
gender tinyint
)
PARTITION BY LIST (gender)
(
PARTITION Male VALUES IN (1)
#,PARTITION Female VALUES IN (2)
);

Note that the Female partition is commented out.


Now load the data normally, but be sure to specify the IGNORE keyword.

LOAD DATA INFILE '/tmp/names.dmp' IGNORE INTO TABLE Names (@var)


SET
Name=Trim(SUBSTR(@var,2,17)),
Gender=SUBSTR(@var,1,1)
;

The IGNORE prevents mysql to abort the import mid-file due to the missing partition.
Hope this is helpful to someone.

Posted by Adrian Singer on April 7, 2009


Here's a great way to use LOAD DATA for UPDATEs, reaping the performance benefits of the super fast LOAD
DATA when doing massive data updates:

http://www.softwareprojects.com/resources/programming/t-how-to-use-mysql-fast-load-data-for-updates-
1753.html

Posted by Chris Johnson on February 15, 2010


When the situation warrants, I will use load data infile because of its speed. In other situations I'll resort to using
another method to load the data. I wish load data had the ability to output a .bad file. Without this, I must resort
to writing code (PHP) to output bad records to a file.
I prefer PHP's MySQLi prepared statements because of the lack of .bad files.

Posted by Mike H on April 26, 2010


It seems you need to remove the byte order mark (BOM) from unicode input files for some reason.

Posted by Patrick Zahra on April 29, 2010


You can load a CSV file on a hosted server where you have no write access.

First, create a temporary table with one LongText field.

INSERT your CSV into that table as one single cell.

Then do a SELECT INTO DUMPFILE to save the file somewhere on the server accessible to MySQL.

LOAD DATA INFILE will now be able to find your CSV.

You will likely be unable to delete this file, so it is best to overwrite it with another DUMPFILE query, this time
giving it an empty string to erase its contents, and you can reuse it again later.

Posted by Aissam Bazzaoui on September 20, 2010


for people who had encoding problem will loading a file, try convert the file to different encoding.

i used a tool called enca on my linux box (apt-get install enca) and converted the file to latin :

# enca import.csv
Universal transformation format 8 bits; UTF-8

just to check for the file encoding

# enconv -x latin1 import.csv

to convert it to latin1
and runned the following query to populate my table (encoded in utf8_general_ci)

SET CHARACTER SET 'utf8';


SET collation_connection = 'utf8_general_ci'

load data local infile '/home/aissam/Documents/data/import.csv' INTO Table cscripts FIELDS TERMINATED
BY ';';

good luck

Posted by Aaron Cohen on October 1, 2010


Further to Mattias Andersson's comment, above, there *is* a convenient way to restrict the rows that end up in
your table *if* your table has a unique index on a column of interest.

In my particular case, I have a CSV of all US Zipcodes. A number of entries in the CSV duplicate other entries.
But, only one entry is marked as the "Preferred" entry, and that's the canonical entry that I want to have end up
in my table. Unfortunately, that entry could appear anywhere in the file - not necessarily first (so I could use
IGNORE) or last (so I could use REPLACE).

Since my table has a unique index on zip, the following allowed me to exclude all non-preferred rows from
being imported:

LOAD DATA INFILE '#{DATA_FILE_NAME}' IGNORE


INTO TABLE zipcodes
FIELDS TERMINATED BY ','
ENCLOSED BY '\"'
LINES TERMINATED BY '\\n'
(city, state_code, @zip, area_code, county_fips, county_name, @preferred, timezone, dst, lat,
lon, msa, pmsa, @city_abbreviation, ma, zip_type)
SET allow_registrations = 1, zip = IF(@preferred='P', @zip, NULL)

(Note that the above is a string in a Ruby script that is programmatically executed.)

Since the IGNORE keyword is specified, when zip is set to NULL the row is ignored *assuming* the DBMS is
configured to not auto-convert NULL to the empty string.

If instead the DBMS is configured to auto-convert NULL to the empty string, the single junk row must be
deleted after the above completes.

DELETE FROM zipcodes WHERE zip = '';

Posted by Mike Laird on October 13, 2010


Loading utf8 character encoded files that are comma separated into MySQL is a technology mine field for many
people. The steps below are very specific to transferring data from Excel 2007 to MySQL in a 1 for 1 way, i.e.,
4 columns in Excel 2007 into 4 fields in MySQL in the same column order. Other transfers are possible, but
require fiddling with step h. below via information in the Help tab of MySQL Query Browser. This is not the only
way to do it, but it works and the load is extremely fast.
a. Before starting the csv transformation and transfer, make sure the source data is cleaned up, including:
sort by the first column and remove duplicate rows/tuples, remove all hyperlinks from copying from web sites,
etc. Only use Excel 2007 (or later) because earlier Excel versions do not save data in utf8 character encoding.
Some Microsoft manager of updates who is "standards resistant" says 'gotcha' every time you use an earlier
version of Excel and try to get data into MySQL.
b. Get or make a filename.xlsx file in Excel 2007. This will store the text in utf8 character encoding. Do not have
field name headings at the top of the columns.
c. Upload the filename.xlsx to Google Documents as a spreadsheet. If asked, check the box to put the
spreadsheet into Googles format.
d. Open the file in Google Documents. Check in the Google Docs spreadsheet that only text and/or numbers
are in each cell (no hyperlinks, etc.). In the File command, download/export the file and select .csv as the file
type. Download it to your own PC. Google Docs magically cleans up Microsofts mess.
e. Save the filename.csv file on your own PC. Then change the file type to .txt You may change the filename, if
you want to.
f. Move this new file, e.g., filename.txt, into the MySQL data directory that has the target schema of interest. An
example is: MySQL Server 5.1/data/schema_name
g. Open MySQL Query Browser from Tools in the command bar in MySQL Administrator. MySQL Query
Browser is in the MySQL Tools directory. Navigate to your schema_name
h. Enter the following commands into the top command entry bar or double click the Data Manipulation
Statements in the lower right corner, and double click LOAD DATA INFILE; then delete unnecessary lines and
all square brackets [ ]. The numbers below should not be entered.
i. LOAD DATA INFILE filename.txt
ii. REPLACE (this will eliminate duplicates in the new data)
iii. INTO TABLE schema_name.table
iv. CHARACTER SET utf8 (optional, if your table is configured for utf8. Your data is already utf8; but it wont
hurt to do)
v. FIELDS TERMINATED BY ,
vi. ESCAPED BY (handles phrases with commas , )
vii. LINES TERMINATED BY \n
i. Press the Execute button. You may get a message saying no result set returned. This is OK, if there is no
error statement and number.
j. Drag the table icon into the command entry bar, and a SELECT statement appears. Execute it. The data
table will appear.
k. Compare the SELECT result set to the original Excel 2007 data file to find errors, e.g., erroneous fields that
you didnt catch up front.
l. Use the MySQL Query Browser to remove row/tuple errors
i. Indicate row by clicking on it
ii. Click Edit at the bottom
iii. Right click and select delete row
iv. Click Apply Changes

Posted by M Locherer on May 5, 2011


Given:
ItemCount|Status|ExtractTime
1|Proposed|2011-02-10 00:00:00
1|Scoped|2011-02-10 00:00:00
1|Proposed|2011-02-10 00:00:00
1|Scoped Out|2011-02-10 00:00:00
1|Proposed|2011-02-10 00:15:00

load data infile '/home/milo/ISExtract.txt'


into table ISExtract
fields terminated by '|'
lines terminated by '\r\n'
ignore 1 lines
(@ic, Status, @et)
set
ItemCount = convert(@IC, signed),
ExtractTime = str_to_date(@et, '%Y-%m-%d %H:%i:%s');

Don't forget apparmor if you are running Ubuntu - edit /etc/apparmor.d/usr.sbin.mysqld and add /home/milo to
the accessible paths for the mysqld process.
lines terminated by '\r\n' --> because the file comes from a Windows source
Hope that helps!
http://www.corporate-insyte.com/Blogs/MilosBlog.aspx
Posted by John Swapceinski on September 5, 2011
Create a table using the .csv file's header:

#!/bin/sh
# pass in the file name as an argument: ./mktable filename.csv
echo "create table $1 ( "
head -1 $1 | sed -e 's/,/ varchar(255),\n/g'
echo " varchar(255) );"

Posted by Marc MAURICE on November 13, 2011


A little script I made to import CSV to MySQL. Thanks to John's comment.

http://en.positon.org/post/Import-CSV-file-to-MySQL

Posted by Barbara Snyder on October 16, 2012


After only about two frustrating hours (I am a total novice), I FINALLY got this to work on Mac by saving as
comma-delimited CSV. The trick was to use

LINES TERMINATED BY '\r'

along with (of course)

FIELDS TERMINATED BY ','

Posted by Tamara Bookal on October 29, 2012


A sample use of LOAD DATA INFILE to parse and load data into MYSQL database table using php script:

"LOAD DATA INFILE '$myFile'" .


" INTO TABLE test FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n'
(@col1,@col2,@col3,@col4,@col5,@col6,@col7,@col8,@col9,@col10,@col11,@col12,@col13,@col14,@col
15,@col16)

SET sdate = STR_TO_DATE(@col1,'%m/%d/%Y'),


acq = @col2,
iss = @col3,
tdate = STR_TO_DATE(@col4,'%m/%d/%Y'),
msg = @col5,
rsp = @col6,
rev = @col7,
tid = @col8,
trace = @col9,
ldate = STR_TO_DATE(@col10,'%m/%d/%Y'),
ltime = @col11,
Cnum = @col12,
amount = REPLACE(REPLACE(TRIM(@col13), '$', ''), ',','') ,
txn = @col14,
code = @col15,
anum = @col16,
upload_date = Now(),
upload_source = '".$_FILES['filename']['name']."'");

This is a combination of different samples pieced together. The @col represents the data elements in the file
'$myfile' the table fields are assigned to these variables.

Hope this is useful to someone else.


Posted by Wilzon Marino Bueno on April 8, 2015
Given:
name,price,status,category
product 01,15,active,fruit
product 02,10,active,fruit
product 03,11,active,vegetables
product 04,15,active,fruit
product 05,19,active,fruit

LOAD DATA INFILE '/var/home/wilzonmb/data/product.csv'


INTO TABLE product
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(product_name, product_price, product_status, category);

In this case, only inserted in fields mentioned, omitting such as ID, stock, etc.

Posted by gere dses on October 11, 2015


name,price,status,category
product 01,15,active,fruit
product 02,10,active,fruit
product 03,11,active,vegetables
product 04,15,active,fruit
product 05,19,active,fruit

You can use LOAD DATA INFILE command to import csv file into table.

Check this link MySQL - LOAD DATA INFILE.

LOAD DATA LOCAL INFILE 'abc.csv' INTO TABLE abc


FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
(col1, col2, col3, col4, col5...)

enter image description here


CREATE TABLE USING FOLLOWING QUERY :

CREATE TABLE IF NOT EXISTS `survey` (


`projectId` bigint(20) NOT NULL,
`surveyId` bigint(20) NOT NULL,
`views` bigint(20) NOT NULL,
`dateTime` datetime NOT NULL
);
YOUR CSV FILE MUST BE PROPERLY FORMATTED FOR EXAMPLE SEE FOLLOWING ATTACHED
IMAGE :
enter image description here

If every thing is fine.. Please execute following query to LOAD DATA FROM CSV FILE :

NOTE : Please add absolute path of your CSV file


LOAD DATA INFILE '/var/www/csv/data.csv'
INTO TABLE survey
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
If everything has done. you have exported data from CSV to table successfully

Posted by Alexey Zhukov on October 6, 2016


If you are running LOAD DATA LOCAL INFILE from the windows shell and you need to use OPTIONALLY
ENCLOSED BY '"', you will have to do something like this in order to escape characters properly
"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysql" -u root --password=%password% -e "LOAD DATA
LOCAL INFILE '!file!' INTO TABLE !table! FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"^""'
LINES TERMINATED BY '\n' IGNORE 1 LINES" --verbose --show-warnings > mysql_!fname!.out

Posted by salar mohiuddin on December 1, 2016


If your input file has a date column and values contain the format like m/d/yyyy then check the below the load
statement

LOAD DATA LOCAL INFILE '/home/cloudera/Desktop/DataSets/2012POS_InvoiceDetails.csv' INTO TABLE


InvoiceDetails FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (Invnum,
@TransDt,TransTime,CustName,EmpName,Service,Amount) set TransDt=STR_TO_DATE(@TransDt,
'%m/%d/%Y');

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.7 LOAD XML Syntax


LOAD XML [LOW_PRIORITY |
CONCURRENT] [LOCAL] INFILE
'file_name'
[REPLACE | IGNORE]
INTO TABLE [db_name.]tbl_name
[CHARACTER SET charset_name]
[ROWS IDENTIFIED BY
'<tagname>']
[IGNORE number {LINES |
ROWS}]
[(field_name_or_user_var
[,
field_name_or_user_var] ...)]
[SET col_name={expr |
DEFAULT},
[, col_name={expr |
DEFAULT}] ...]
The LOAD XML statement reads data from an XML file into a table. The file_name must be given as
a literal string. The tagname in the optional ROWS IDENTIFIED BY clause must also be given as a
literal string, and must be surrounded by angle brackets (< and >).
LOAD XML acts as the complement of running the mysql client in XML output mode (that is, starting
the client with the --xml option). To write data from a table to an XML file, you can invoke
the mysql client with the --xml and -e options from the system shell, as shown here:
shell> mysql --xml -e 'SELECT *
FROM mydb.mytable' > file.xml
To read the file back into a table, use LOAD XML INFILE. By default, the <row> element is
considered to be the equivalent of a database table row; this can be changed using the ROWS
IDENTIFIED BY clause.
This statement supports three different XML formats:
Column names as attributes and
column values as attribute values:

<row column1="value1"
column2="value2" .../>
Column names as tags and column
values as the content of these tags:

<row>
<column1>value1</column1>
<column2>value2</column2>
</row>
Column names are the name attributes
of <field> tags, and values are the
contents of these tags:
<row>
<field
name='column1'>value1</field>
<field
name='column2'>value2</field>
</row>
This is the format used by other
MySQL tools, such as mysqldump.
All three formats can be used in the same XML file; the import routine automatically detects the
format for each row and interprets it correctly. Tags are matched based on the tag or attribute name
and the column name.

The following clauses work essentially the same way for LOAD XML as they do for LOAD DATA:
LOW_PRIORITY or CONCURRENT
LOCAL
REPLACE or IGNORE
CHARACTER SET
SET
See Section 13.2.6, LOAD DATA INFILE Syntax, for more information about these clauses.
(field_name_or_user_var, ...) is a list of one or more comma-separated XML fields or user
variables. The name of a user variable used for this purpose must match the name of a field from the
XML file, prefixed with @. You can use field names to select only desired fields. User variables can
be employed to store the corresponding field values for subsequent re-use.
The IGNORE number LINES or IGNORE number ROWS clause causes the first number rows in the
XML file to be skipped. It is analogous to the LOAD DATAstatement's IGNORE ... LINES clause.
Suppose that we have a table named person, created as shown here:
USE test;

CREATE TABLE person (


person_id INT NOT NULL
PRIMARY KEY,
fname VARCHAR(40) NULL,
lname VARCHAR(40) NULL,
created TIMESTAMP
);
Suppose further that this table is initially empty.

Now suppose that we have a simple XML file person.xml, whose contents are as shown here:
<list>
<person person_id="1"
fname="Kapek"
lname="Sainnouine"/>
<person person_id="2"
fname="Sajon" lname="Rondela"/>
<person
person_id="3"><fname>Likame</fnam
e><lname>rrtmons</lname></person
>
<person
person_id="4"><fname>Slar</fname>
<lname>Manlanth</lname></person>
<person><field
name="person_id">5</field><field
name="fname">Stoma</field>
<field
name="lname">Milu</field></person
>
<person><field
name="person_id">6</field><field
name="fname">Nirtam</field>
<field
name="lname">Skld</field></perso
n>
<person
person_id="7"><fname>Sungam</fnam
e><lname>Dulbd</lname></person>
<person person_id="8"
fname="Sraref" lname="Encmelt"/>
</list>
Each of the permissible XML formats discussed previously is represented in this example file.

To import the data in person.xml into the person table, you can use this statement:
mysql> LOAD XML LOCAL INFILE
'person.xml'
-> INTO TABLE person
-> ROWS IDENTIFIED BY
'<person>';

Query OK, 8 rows affected (0.00


sec)
Records: 8 Deleted: 0 Skipped:
0 Warnings: 0
Here, we assume that person.xml is located in the MySQL data directory. If the file cannot be
found, the following error results:
ERROR 2 (HY000): File
'/person.xml' not found (Errcode:
2)
The ROWS IDENTIFIED BY '<person>' clause means that each <person> element in the XML
file is considered equivalent to a row in the table into which the data is to be imported. In this case,
this is the person table in the test database.
As can be seen by the response from the server, 8 rows were imported into the test.person table.
This can be verified by a simple SELECT statement:
mysql> SELECT * FROM person;
+-----------+--------+-----------
-+---------------------+
| person_id | fname | lname
| created |
+-----------+--------+-----------
-+---------------------+
| 1 | Kapek | Sainnouine
| 2007-07-13 16:18:47 |
| 2 | Sajon | Rondela
| 2007-07-13 16:18:47 |
| 3 | Likame | rrtmons
| 2007-07-13 16:18:47 |
| 4 | Slar | Manlanth
| 2007-07-13 16:18:47 |
| 5 | Stoma | Nilu
| 2007-07-13 16:18:47 |
| 6 | Nirtam | Skld
| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbd
| 2007-07-13 16:18:47 |
| 8 | Sreraf | Encmelt
| 2007-07-13 16:18:47 |
+-----------+--------+-----------
-+---------------------+
8 rows in set (0.00 sec)
This shows, as stated earlier in this section, that any or all of the 3 permitted XML formats may
appear in a single file and be read in using LOAD XML.
The inverse of the import operation just shownthat is, dumping MySQL table data into an XML
filecan be accomplished using the mysql client from the system shell, as shown here:

shell> mysql --xml -e "SELECT *


FROM test.person" > person-
dump.xml

shell> cat person-dump.xml

<?xml version="1.0"?>

<resultset statement="SELECT *
FROM test.person"
xmlns:xsi="http://www.w3.org/2001
/XMLSchema-instance">
<row>
<field
name="person_id">1</field>
<field
name="fname">Kapek</field>
<field
name="lname">Sainnouine</field>
</row>

<row>
<field
name="person_id">2</field>
<field
name="fname">Sajon</field>
<field
name="lname">Rondela</field>
</row>

<row>
<field
name="person_id">3</field>
<field
name="fname">Likema</field>
<field
name="lname">rrtmons</field>
</row>

<row>
<field
name="person_id">4</field>
<field
name="fname">Slar</field>
<field
name="lname">Manlanth</field>
</row>

<row>
<field
name="person_id">5</field>
<field
name="fname">Stoma</field>
<field
name="lname">Nilu</field>
</row>

<row>
<field
name="person_id">6</field>
<field
name="fname">Nirtam</field>
<field
name="lname">Skld</field>
</row>

<row>
<field
name="person_id">7</field>
<field
name="fname">Sungam</field>
<field
name="lname">Dulbd</field>
</row>

<row>
<field
name="person_id">8</field>
<field
name="fname">Sreraf</field>
<field
name="lname">Encmelt</field>
</row>
</resultset>
Note
The --xml option causes the mysql client to use XML formatting for its output; the -e option causes
the client to execute the SQL statement immediately following the option. See Section 4.5.1,
mysql The MySQL Command-Line Tool.
You can verify that the dump is valid by creating a copy of the person table and importing the dump
file into the new table, like this:
mysql> USE test;
mysql> CREATE TABLE person2 LIKE
person;
Query OK, 0 rows affected (0.00
sec)

mysql> LOAD XML LOCAL INFILE


'person-dump.xml'
-> INTO TABLE person2;
Query OK, 8 rows affected (0.01
sec)
Records: 8 Deleted: 0 Skipped:
0 Warnings: 0

mysql> SELECT * FROM person2;


+-----------+--------+-----------
-+---------------------+
| person_id | fname | lname
| created |
+-----------+--------+-----------
-+---------------------+
| 1 | Kapek | Sainnouine
| 2007-07-13 16:18:47 |
| 2 | Sajon | Rondela
| 2007-07-13 16:18:47 |
| 3 | Likema | rrtmons
| 2007-07-13 16:18:47 |
| 4 | Slar | Manlanth
| 2007-07-13 16:18:47 |
| 5 | Stoma | Nilu
| 2007-07-13 16:18:47 |
| 6 | Nirtam | Skld
| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbd
| 2007-07-13 16:18:47 |
| 8 | Sreraf | Encmelt
| 2007-07-13 16:18:47 |
+-----------+--------+-----------
-+---------------------+
8 rows in set (0.00 sec)
There is no requirement that every field in the XML file be matched with a column in the
corresponding table. Fields which have no corresponding columns are skipped. You can see this by
first emptying the person2 table and dropping the created column, then using the same LOAD
XML statement we just employed previously, like this:
mysql> TRUNCATE person2;
Query OK, 8 rows affected (0.26
sec)
mysql> ALTER TABLE person2 DROP
COLUMN created;
Query OK, 0 rows affected (0.52
sec)
Records: 0 Duplicates: 0
Warnings: 0

mysql> SHOW CREATE TABLE


person2\G
*************************** 1.
row ***************************
Table: person2
Create Table: CREATE TABLE
`person2` (
`person_id` int(11) NOT NULL,
`fname` varchar(40) DEFAULT
NULL,
`lname` varchar(40) DEFAULT
NULL,
PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT
CHARSET=utf8
1 row in set (0.00 sec)

mysql> LOAD XML LOCAL INFILE


'person-dump.xml'
-> INTO TABLE person2;
Query OK, 8 rows affected (0.01
sec)
Records: 8 Deleted: 0 Skipped:
0 Warnings: 0

mysql> SELECT * FROM person2;


+-----------+--------+-----------
-+
| person_id | fname | lname
|
+-----------+--------+-----------
-+
| 1 | Kapek | Sainnouine
|
| 2 | Sajon | Rondela
|
| 3 | Likema | rrtmons
|
| 4 | Slar | Manlanth
|
| 5 | Stoma | Nilu
|
| 6 | Nirtam | Skld
|
| 7 | Sungam | Dulbd
|
| 8 | Sreraf | Encmelt
|
+-----------+--------+-----------
-+
8 rows in set (0.00 sec)
The order in which the fields are given within each row of the XML file does not affect the operation
of LOAD XML; the field order can vary from row to row, and is not required to be in the same order as
the corresponding columns in the table.
As mentioned previously, you can use a (field_name_or_user_var, ...) list of one or more XML
fields (to select desired fields only) or user variables (to store the corresponding field values for later
use). User variables can be especially useful when you want to insert data from an XML file into
table columns whose names do not match those of the XML fields. To see how this works, we first
create a table named individual whose structure matches that of the persontable, but whose
columns are named differently:
mysql> CREATE TABLE individual (
-> individual_id INT NOT
NULL PRIMARY KEY,
-> name1 VARCHAR(40)
NULL,
-> name2 VARCHAR(40)
NULL,
-> made TIMESTAMP
-> );
Query OK, 0 rows affected (0.42
sec)
In this case, you cannot simply load the XML file directly into the table, because the field and column
names do not match:

mysql> LOAD XML INFILE


'../bin/person-dump.xml' INTO
TABLE test.individual;
ERROR 1263 (22004): Column set to
default value; NULL supplied to
NOT NULL column 'individual_id'
at row 1
This happens because the MySQL server looks for field names matching the column names of the
target table. You can work around this problem by selecting the field values into user variables, then
setting the target table's columns equal to the values of those variables using SET. You can perform
both of these operations in a single statement, as shown here:
mysql> LOAD XML INFILE
'../bin/person-dump.xml'
-> INTO TABLE
test.individual (@person_id,
@fname, @lname, @created)
-> SET
individual_id=@person_id,
name1=@fname, name2=@lname,
made=@created;
Query OK, 8 rows affected (0.05
sec)
Records: 8 Deleted: 0 Skipped:
0 Warnings: 0

mysql> SELECT * FROM individual;


+---------------+--------+-------
-----+---------------------+
| individual_id | name1 | name2
| made |
+---------------+--------+-------
-----+---------------------+
| 1 | Kapek |
Sainnouine | 2007-07-13 16:18:47
|
| 2 | Sajon |
Rondela | 2007-07-13 16:18:47
|
| 3 | Likema |
rrtmons | 2007-07-13 16:18:47
|
| 4 | Slar |
Manlanth | 2007-07-13 16:18:47
|
| 5 | Stoma | Nilu
| 2007-07-13 16:18:47 |
| 6 | Nirtam | Skld
| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbd
| 2007-07-13 16:18:47 |
| 8 | Srraf |
Encmelt | 2007-07-13 16:18:47
|
+---------------+--------+-------
-----+---------------------+
8 rows in set (0.00 sec)
The names of the user variables must match those of the corresponding fields from the XML file,
with the addition of the required @ prefix to indicate that they are variables. The user variables need
not be listed or assigned in the same order as the corresponding fields.
Using a ROWS IDENTIFIED BY '<tagname>' clause, it is possible to import data from the same
XML file into database tables with different definitions. For this example, suppose that you have a file
named address.xml which contains the following XML:
<?xml version="1.0"?>

<list>
<person person_id="1">
<fname>Robert</fname>
<lname>Jones</lname>
<address address_id="1"
street="Mill Creek Road"
zip="45365" city="Sidney"/>
<address address_id="2"
street="Main Street" zip="28681"
city="Taylorsville"/>
</person>

<person person_id="2">
<fname>Mary</fname>
<lname>Smith</lname>
<address address_id="3"
street="River Road" zip="80239"
city="Denver"/>
<!-- <address address_id="4"
street="North Street" zip="37920"
city="Knoxville"/> -->
</person>

</list>
You can again use the test.person table as defined previously in this section, after clearing all the
existing records from the table and then showing its structure as shown here:
mysql< TRUNCATE person;
Query OK, 0 rows affected (0.04
sec)

mysql< SHOW CREATE TABLE person\G


*************************** 1.
row ***************************
Table: person
Create Table: CREATE TABLE
`person` (
`person_id` int(11) NOT NULL,
`fname` varchar(40) DEFAULT
NULL,
`lname` varchar(40) DEFAULT
NULL,
`created` timestamp NOT NULL
DEFAULT CURRENT_TIMESTAMP ON
UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`person_id`)
) ENGINE=MyISAM DEFAULT
CHARSET=latin1
1 row in set (0.00 sec)
Now create an address table in the test database using the following CREATE TABLE statement:
CREATE TABLE address (
address_id INT NOT NULL
PRIMARY KEY,
person_id INT NULL,
street VARCHAR(40) NULL,
zip INT NULL,
city VARCHAR(40) NULL,
created TIMESTAMP
);
To import the data from the XML file into the person table, execute the following LOAD
XML statement, which specifies that rows are to be specified by the<person> element, as shown
here;
mysql> LOAD XML LOCAL INFILE
'address.xml'
-> INTO TABLE person
-> ROWS IDENTIFIED BY
'<person>';
Query OK, 2 rows affected (0.00
sec)
Records: 2 Deleted: 0 Skipped:
0 Warnings: 0
You can verify that the records were imported using a SELECT statement:
mysql> SELECT * FROM person;
+-----------+--------+-------+---
------------------+
| person_id | fname | lname |
created |
+-----------+--------+-------+---
------------------+
| 1 | Robert | Jones |
2007-07-24 17:37:06 |
| 2 | Mary | Smith |
2007-07-24 17:37:06 |
+-----------+--------+-------+---
------------------+
2 rows in set (0.00 sec)
Since the <address> elements in the XML file have no corresponding columns in the person table,
they are skipped.
To import the data from the <address> elements into the address table, use the LOAD
XML statement shown here:
mysql> LOAD XML LOCAL INFILE
'address.xml'
-> INTO TABLE address
-> ROWS IDENTIFIED BY
'<address>';
Query OK, 3 rows affected (0.00
sec)
Records: 3 Deleted: 0 Skipped:
0 Warnings: 0
You can see that the data was imported using a SELECT statement such as this one:
mysql> SELECT * FROM address;
+------------+-----------+-------
----------+-------+--------------
+---------------------+
| address_id | person_id | street
| zip | city | created
|
+------------+-----------+-------
----------+-------+--------------
+---------------------+
| 1 | 1 | Mill
Creek Road | 45365 | Sidney
| 2007-07-24 17:37:37 |
| 2 | 1 | Main
Street | 28681 | Taylorsville
| 2007-07-24 17:37:37 |
| 3 | 2 | River
Road | 80239 | Denver
| 2007-07-24 17:37:37 |
+------------+-----------+-------
----------+-------+--------------
+---------------------+
3 rows in set (0.00 sec)
The data from the <address> element that is enclosed in XML comments is not imported. However,
since there is a person_id column in the address table, the value of the person_id attribute from
the parent <person> element for each <address> is imported into the address table.
Security Considerations. As with the LOAD DATA statement, the transfer of the XML file from the
client host to the server host is initiated by the MySQL server. In theory, a patched server could be
built that would tell the client program to transfer a file of the server's choosing rather than the file
named by the client in the LOAD XML statement. Such a server could access any file on the client
host to which the client user has read access.
In a Web environment, clients usually connect to MySQL from a Web server. A user that can run any
command against the MySQL server can use LOAD XML LOCAL to read any files to which the Web
server process has read access. In this environment, the client with respect to the MySQL server is
actually the Web server, not the remote program being run by the user who connects to the Web
server.
You can disable loading of XML files from clients by starting the server with --local-
infile=0 or --local-infile=OFF. This option can also be used when starting the mysql client to
disable LOAD XML for the duration of the client session.
To prevent a client from loading XML files from the server, do not grant the FILE privilege to the
corresponding MySQL user account, or revoke this privilege if the client user account already has it.
Important
Revoking the FILE privilege (or not granting it in the first place) keeps the user only from executing
the LOAD XML INFILE statement (as well as the LOAD_FILE() function; it does not prevent the
user from executing LOAD XML LOCAL INFILE. To disallow this statement, you must start the
server or the client with --local-infile=OFF.
In other words, the FILE privilege affects only whether the client can read files on the server; it has
no bearing on whether the client can read files on the local file system.
For partitioned tables using storage engines that employ table locks, such as MyISAM, any locks
caused by LOAD XML perform locks on all partitions of the table. This does not apply to tables using
storage engines which employ row-level locking, such as InnoDB. For more information,
see Section 22.6.4, Partitioning and Locking.

PREV HOME UP NEXT


User Comments
Posted by Harald Groven on January 3, 2013
If your are using MySQL 5.1 or earlier, you can fake the LOAD XML functions by using using a few steps
involving LOAD DATA INFILE, CONCAT and SUBSTRING_INDEX. In this example, we assume that we want
to create one record for each occurrence of a tag <program> .... </program>

-- 1st create a table to hold the XML-data


CREATE TABLE IF NOT EXISTS myxmltable (
xmldata longtext NOT NULL
) DEFAULT CHARSET=utf8 ;

-- split each record for each occurrence of an end tag,


-- in this case it is "</program>"
LOAD DATA INFILE '/home/myusername/file.xml'
INTO TABLE `myxmltable`
CHARACTER SET latin1
-- FIELDS TERMINATED BY ''
LINES TERMINATED BY '</program>' ;

-- reintroduce the end tag that was lost during import


UPDATE myxmltable
SET xmldata=CONCAT(xmldata, '\n</program>')
WHERE xmldata LIKE '%<program%' ;

-- remove all xml-in the first record before first occurrence of start tag <program>
UPDATE myxmltable
SET xmldata=CONCAT('<program', SUBSTRING_INDEX(xmldata,'<program',-1))
WHERE xmldata LIKE '%<program%' ;

Obviously... LOAD XML saves a lot of unnecessary coding :-)

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates


13.2.8 REPLACE Syntax
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
[(col_name [, col_name] ...)]
{VALUES | VALUE} (value_list)
[, (value_list)] ...

REPLACE [LOW_PRIORITY | DELAYED]


[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
SET assignment_list

REPLACE [LOW_PRIORITY | DELAYED]


[INTO] tbl_name
[PARTITION (partition_name [,
partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...

value:
{expr | DEFAULT}

value_list:
value [, value] ...

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...
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. See Section 13.2.5, INSERT Syntax.
REPLACE is a MySQL extension to the SQL standard. It either inserts, or deletes and inserts. For
another MySQL extension to standard SQLthat either inserts orupdatessee Section 13.2.5.2,
INSERT ... ON DUPLICATE KEY UPDATE Syntax.
DELAYED inserts and replaces were deprecated in MySQL 5.6. In MySQL 5.7, DELAYED is not
supported. The server recognizes but ignores the DELAYED keyword, handles the replace as a
nondelayed replace, and generates an ER_WARN_LEGACY_SYNTAX_CONVERTED warning.
(REPLACE DELAYED is no longer supported. The statement was converted to REPLACE.)
The DELAYED keyword will be removed in a future release.
Note
REPLACE makes sense only if a table has a PRIMARY KEY or UNIQUE index. Otherwise, it becomes
equivalent to INSERT, because there is no index to be used to determine whether a new row
duplicates another.
Values for all columns are taken from the values specified in the REPLACE statement. Any missing
columns are set to their default values, just as happens forINSERT. You cannot refer to values from
the current row and use them in the new row. If you use an assignment such
as SET col_name = col_name + 1, the reference to the column name on the right hand side is
treated as DEFAULT(col_name), so the assignment is equivalent to SET col_name =
DEFAULT(col_name) + 1.
To use REPLACE, you must have both the INSERT and DELETE privileges for the table.
If a generated column is replaced explicitly, the only permitted value is DEFAULT. For information
about generated columns, see Section 13.1.18.8, CREATE TABLE and Generated Columns.
REPLACE supports explicit partition selection using the PARTITION keyword with a list of comma-
separated names of partitions, subpartitions, or both. As with INSERT, if it is not possible to insert the
new row into any of these partitions or subpartitions, the REPLACE statement fails with the
error Found a row not matching the given partition set. For more information and
examples, see Section 22.5, Partition Selection.
The REPLACE statement returns a count to indicate the number of rows affected. This is the sum of
the rows deleted and inserted. If the count is 1 for a single-row REPLACE, a row was inserted and no
rows were deleted. If the count is greater than 1, one or more old rows were deleted before the new
row was inserted. It is possible for a single row to replace more than one old row if the table contains
multiple unique indexes and the new row duplicates values for different old rows in different unique
indexes.
The affected-rows count makes it easy to determine whether REPLACE only added a row or whether
it also replaced any rows: Check whether the count is 1 (added) or greater (replaced).
If you are using the C API, the affected-rows count can be obtained using
the mysql_affected_rows() function.
You cannot replace into a table and select from the same table in a subquery.

MySQL uses the following algorithm for REPLACE (and LOAD DATA ... REPLACE):
1. Try to insert the new row into the table

2. While the insertion fails because a


duplicate-key error occurs for a primary
key or unique index:

a. Delete from the table the


conflicting row that has the
duplicate key value

b. Try again to insert the new row


into the table

It is possible that in the case of a duplicate-key error, a storage engine may perform the REPLACE as
an update rather than a delete plus insert, but the semantics are the same. There are no user-visible
effects other than a possible difference in how the storage engine increments Handler_xxx status
variables.
Because the results of REPLACE ... SELECT statements depend on the ordering of rows from
the SELECT and this order cannot always be guaranteed, it is possible when logging these
statements for the master and the slave to diverge. For this reason, REPLACE ...
SELECT statements are flagged as unsafe for statement-based replication. such statements produce
a warning in the error log when using statement-based mode and are written to the binary log using
the row-based format when using MIXED mode. See also Section 16.2.1.1, Advantages and
Disadvantages of Statement-Based and Row-Based Replication.
When modifying an existing table that is not partitioned to accommodate partitioning, or, when
modifying the partitioning of an already partitioned table, you may consider altering the table's
primary key (see Section 22.6.1, Partitioning Keys, Primary Keys, and Unique Keys). You should
be aware that, if you do this, the results of REPLACE statements may be affected, just as they would
be if you modified the primary key of a nonpartitioned table. Consider the table created by the
following CREATE TABLE statement:
CREATE TABLE test (
id INT UNSIGNED NOT NULL
AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT
CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
When we create this table and run the statements shown in the mysql client, the result is as follows:

mysql> REPLACE INTO test VALUES


(1, 'Old', '2014-08-20
18:47:00');
Query OK, 1 row affected (0.04
sec)

mysql> REPLACE INTO test VALUES


(1, 'New', '2014-08-20
18:47:42');
Query OK, 2 rows affected (0.04
sec)

mysql> SELECT * FROM test;


+----+------+--------------------
-+
| id | data | ts
|
+----+------+--------------------
-+
| 1 | New | 2014-08-20 18:47:42
|
+----+------+--------------------
-+
1 row in set (0.00 sec)
Now we create a second table almost identical to the first, except that the primary key now covers 2
columns, as shown here (emphasized text):

CREATE TABLE test2 (


id INT UNSIGNED NOT NULL
AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT
CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
PRIMARY KEY (id, ts)
);
When we run on test2 the same two REPLACE statements as we did on the original test table, we
obtain a different result:
mysql> REPLACE INTO test2 VALUES
(1, 'Old', '2014-08-20
18:47:00');
Query OK, 1 row affected (0.05
sec)
mysql> REPLACE INTO test2 VALUES
(1, 'New', '2014-08-20
18:47:42');
Query OK, 1 row affected (0.06
sec)

mysql> SELECT * FROM test2;


+----+------+--------------------
-+
| id | data | ts
|
+----+------+--------------------
-+
| 1 | Old | 2014-08-20 18:47:00
|
| 1 | New | 2014-08-20 18:47:42
|
+----+------+--------------------
-+
2 rows in set (0.00 sec)
This is due to the fact that, when run on test2, both the id and ts column values must match those
of an existing row for the row to be replaced; otherwise, a row is inserted.
A REPLACE statement affecting a partitioned table using a storage engine such as MyISAM that
employs table-level locks locks only those partitions containing rows that match
the REPLACE statement WHERE clause, as long as none of the table partitioning columns are updated;
otherwise the entire table is locked. (For storage engines such as InnoDB that employ row-level
locking, no locking of partitions takes place.) For more information, see Section 22.6.4, Partitioning
and Locking.

PREV HOME UP NEXT


User Comments
Posted by no forms on October 28, 2004
Be careful with InnoDB tables and REPLACE:
If you run a replace on existing keys on table T, and table F references T with a forgein key constraint ON
DELETE CASCADE, then table T will be updated - but table F will be emptied due to the DELETE before
INSERT.
e.g.:

CREATE TABLE T (
`id` int(10) unsigned NOT NULL auto_increment,
PRIMARY KEY (`id`)
);

CREATE TABLE F (
`foreign_id` int(10) unsigned NOT NULL,
CONSTRAINT `fkey` FOREIGN KEY (`foreign_id`) REFERENCES `T` (`id`) ON DELETE
CASCADE ON UPDATE CASCADE
);

<insert numbers 1..1000 into T>


<insert numbers 1..1000 into F>

REPLACE INTO T SELECT * FROM T;


=> T is updated
=> F is truncated - not the desired effect.
It is best to avoid REPLACE when working with constraints.

Posted by R Lenard on January 12, 2005


Be careful with REPLACE INTO with server side prepared statements and the 3.1.6 driver - it doesn't support
them. The 3.0.x driver did :-(

Posted by Eric Stevens on February 3, 2005


Performance considerations:

Please note that REPLACE INTO is a much slower performer than an UPDATE statement. Keep in mind that a
REPLACE INTO requires a test on the keys, and if a matching unique key is found on any or all columns, a
DELETE FROM is executed, then an INSERT is executed. There's a lot of management of rows involved in
this, and if you're doing it frequently, you'll hurt your performance unless you simply cannot do with any other
syntax.

The only time when I can see where you'd actually need a REPLACE INTO is when you have multiple unique
constraints on a table, and need to drop any rows that would match any of the constraints. Then REPLACE
INTO becomes more efficient from DELETE FROM... INSERT INTO...

If you're looking at a single unique column table (Primary Key), please use UPDATE, or INSERT. Also, check
out INSERT ... ON DUPLIATE KEY UPDATE... as an alternative if you're willing to stick to MySQL 4.1+

Posted by Rolf Martin-Hoster on May 8, 2006


INNODB mysql 5.0 does not support "DELAYED" but does support LOW_PRIORITY :

mysql> REPLACE DELAYED INTO `online_users` SET `session_id`='3580cc4e61117c0785372c426eddd11c',


`user_id` = 'XXX', `page` = '/', `lastview` = NOW();
ERROR 1031 (HY000): Table storage engine for 'online_users' doesn't have this option

Posted by Atif Ghaffar on September 23, 2007


PLEASE Note that the REPLACE does a DELETE operation.

We did not realize this and had the triggers that should be triggered on DELETE triggered.

After checking all the code, we just found a script that does a replace to refresh the values of some fields.

We should have had used "insert into ... on duplicate update" syntax instead.

Posted by J Mike on May 4, 2009


If you are using REPLACE INTO... triggers are fired in this order (if delete of duplcate key is used):
- before insert
- before delete
- after delete
- after insert

Posted by Pablo Fernandez on September 7, 2009


This can also be used to merge databases http://serverprotectors.com/blog/64-merging-mysql-databases.html

Posted by Abidir Rokhman on February 13, 2011


i already move my blog to another domain and realize that all images on my post still pointing to old domain, so
i need to find and replace all url on my post with my new domain. and i found this function useful to update just
old domain to all my post.
i am using this query :

UPDATE wp_posts SET post_content = REPLACE(post_content, 'olddomain.com', 'newdomain.com');

full explanation here http://cakarayam.com/find-and-replace-mysql-how-to-find-and-replace-data-in-mysql/

Posted by Meir Guttman on July 6, 2014


"no forms" tip also applies to a much simpler situation:

Simply having an Auto-Increment as a primary key will insert a new record with the same VALUES (...),(...);
whenever the same "REPLACE INTO..." query is executed.

Records then are ADDED, not REPLACE(d)!

Posted by Nathan Neulinger on April 18, 2015


Should note that this warning about inserts and nulls

"For multiple-row INSERT statements or INSERT INTO ... SELECT statements, the column is set to the implicit
default value for the column data type. This is 0 for numeric types, the empty string ('') for string types, and the
zero value for date and time types."

also appears to apply to a single row "replace into" query, which can be very confusing to debug when it
appears to not obey the table constraints and just turns nulls/missing columns into empty strings. This can
particularly be a problem if you have a unique constraint on one of those columns.

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.9 SELECT Syntax


13.2.9.1 SELECT ... INTO Syntax
13.2.9.2 JOIN Syntax
13.2.9.3 UNION Syntax
SELECT
[ALL | DISTINCT | DISTINCTROW
]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT]
[SQL_BIG_RESULT]
[SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE]
[SQL_CALC_FOUND_ROWS]
select_expr [, select_expr
...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr |
position}
[ASC | DESC], ... [WITH
ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr |
position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count |
row_count OFFSET offset}]
[PROCEDURE
procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET
charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [,
var_name]]
[FOR UPDATE | LOCK IN SHARE
MODE]]
SELECT is used to retrieve rows selected from one or more tables, and can
include UNION statements and subqueries. See Section 13.2.9.3, UNION Syntax,
and Section 13.2.10, Subquery Syntax.
The most commonly used clauses of SELECT statements are these:
Each select_expr indicates a column
that you want to retrieve. There must
be at least one select_expr.
table_references indicates the
table or tables from which to retrieve
rows. Its syntax is described
in Section 13.2.9.2, JOIN Syntax.
SELECT supports explicit partition
selection using the PARTITION with a
list of partitions or subpartitions (or
both) following the name of the table in
a table_reference (see Section 13.
2.9.2, JOIN Syntax). In this case,
rows are selected only from the
partitions listed, and any other
partitions of the table are ignored. For
more information and examples,
see Section 22.5, Partition Selection.
SELECT ... PARTITION from tables
using storage engines such
as MyISAM that perform table-level
locks (and thus partition locks) lock
only the partitions or subpartitions
named by the PARTITION option.
For more information,
see Section 22.6.4, Partitioning and
Locking.
The WHERE clause, if given, indicates
the condition or conditions that rows
must satisfy to be
selected. where_condition is an
expression that evaluates to true for
each row to be selected. The
statement selects all rows if there is
no WHERE clause.
In the WHERE expression, you can use
any of the functions and operators that
MySQL supports, except for aggregate
(summary) functions. See Section 9.5,
Expression Syntax,
and Chapter 12, Functions and
Operators.
SELECT can also be used to retrieve rows computed without reference to any table.
For example:

mysql> SELECT 1 + 1;
-> 2
You are permitted to specify DUAL as a dummy table name in situations where no tables are
referenced:
mysql> SELECT 1 + 1 FROM DUAL;
-> 2
DUAL is purely for the convenience of people who require that all SELECT statements should
have FROM and possibly other clauses. MySQL may ignore the clauses. MySQL does not
require FROM DUAL if no tables are referenced.
In general, clauses used must be given in exactly the order shown in the syntax description. For
example, a HAVING clause must come after any GROUP BY clause and before any ORDER BY clause.
The exception is that the INTO clause can appear either as shown in the syntax description or
immediately following theselect_expr list. For more information about INTO, see Section 13.2.9.1,
SELECT ... INTO Syntax.
The list of select_expr terms comprises the select list that indicates which columns to retrieve.
Terms specify a column or expression or can use *-shorthand:
A select list consisting only of a single
unqualified * can be used as
shorthand to select all columns from all
tables:
SELECT * FROM t1 INNER JOIN
t2 ...
tbl_name.* can be used as a qualified
shorthand to select all columns from
the named table:
SELECT t1.*, t2.* FROM t1
INNER JOIN t2 ...
Use of an unqualified * with other
items in the select list may produce a
parse error. To avoid this problem, use
a qualified tbl_name.* reference
SELECT AVG(score), t1.* FROM
t1 ...
The following list provides additional information about other SELECT clauses:
A select_expr can be given an alias
using AS alias_name. The alias is
used as the expression's column name
and can be used in GROUP BY, ORDER
BY, orHAVING clauses. For example:
SELECT CONCAT(last_name,',
',first_name) AS full_name
FROM mytable ORDER BY
full_name;
The AS keyword is optional when
aliasing a select_expr with an
identifier. The preceding example
could have been written like this:
SELECT CONCAT(last_name,',
',first_name) full_name
FROM mytable ORDER BY
full_name;
However, because the AS is optional, a
subtle problem can occur if you forget
the comma between
two select_expr expressions:
MySQL interprets the second as an
alias name. For example, in the
following statement, columnb is
treated as an alias name:
SELECT columna columnb FROM
mytable;
For this reason, it is good practice to
be in the habit of using AS explicitly
when specifying column aliases.
It is not permissible to refer to a
column alias in a WHERE clause,
because the column value might not
yet be determined when
the WHERE clause is executed.
See Section B.5.4.4, Problems with
Column Aliases.
The FROM table_references clause
indicates the table or tables from which
to retrieve rows. If you name more than
one table, you are performing a join.
For information on join syntax,
see Section 13.2.9.2, JOIN Syntax.
For each table specified, you can
optionally specify an alias.
tbl_name [[AS] alias]
[index_hint]
The use of index hints provides the
optimizer with information about how to
choose indexes during query
processing. For a description of the
syntax for specifying these hints,
see Section 8.9.4, Index Hints.
You can use SET
max_seeks_for_key=value as an
alternative way to force MySQL to
prefer key scans instead of table
scans. See Section 5.1.5, Server
System Variables.
You can refer to a table within the
default database as tbl_name, or
as db_name.tbl_name to specify a
database explicitly. You can refer to a
column
ascol_name, tbl_name.col_name,
or db_name.tbl_name.col_name. You
need not specify
a tbl_name or db_name.tbl_name pre
fix for a column reference unless the
reference would be ambiguous.
See Section 9.2.1, Identifier
Qualifiers, for examples of ambiguity
that require the more explicit column
reference forms.
A table reference can be aliased
using tbl_name AS alias_name or tb
l_name alias_name:
SELECT t1.name, t2.salary
FROM employee AS t1, info AS
t2
WHERE t1.name = t2.name;

SELECT t1.name, t2.salary
FROM employee t1, info t2
WHERE t1.name = t2.name;
Columns selected for output can be
referred to in ORDER BY and GROUP
BY clauses using column names,
column aliases, or column positions.
Column positions are integers and
begin with 1:
SELECT college, region, seed
FROM tournament
ORDER BY region, seed;

SELECT college, region AS r,
seed AS s FROM tournament
ORDER BY r, s;

SELECT college, region, seed
FROM tournament
ORDER BY 2, 3;
To sort in reverse order, add
the DESC (descending) keyword to the
name of the column in the ORDER
BY clause that you are sorting by. The
default is ascending order; this can be
specified explicitly using
the ASC keyword.
If ORDER BY occurs within a subquery
and also is applied in the outer query,
the outermost ORDER BY takes
precedence. For example, results for
the following statement are sorted in
descending order, not ascending order:
(SELECT ... ORDER BY a) ORDER
BY a DESC;
Use of column positions is deprecated
because the syntax has been removed
from the SQL standard.

If you use GROUP BY, output rows are


sorted according to the GROUP
BY columns as if you had an ORDER
BY for the same columns. To avoid the
overhead of sorting that GROUP
BY produces, add ORDER BY NULL:
SELECT a, COUNT(b) FROM
test_table GROUP BY a ORDER
BY NULL;
Relying on implicit GROUP BY sorting
(that is, sorting in the absence
of ASC or DESC designators) is
deprecated. To produce a given sort
order, use
explicit ASC or DESC designators
for GROUP BY columns or provide
an ORDER BY clause.
When you use ORDER BY or GROUP
BY to sort a column in a SELECT, the
server sorts values using only the initial
number of bytes indicated by
themax_sort_length system
variable.
MySQL extends the GROUP BY clause
so that you can also
specify ASC and DESC after columns
named in the clause:
SELECT a, COUNT(b) FROM
test_table GROUP BY a DESC;
MySQL extends the use of GROUP
BY to permit selecting fields that are
not mentioned in the GROUP BY clause.
If you are not getting the results that
you expect from your query, please
read the description of GROUP
BY found in Section 12.19, Aggregate
(GROUP BY) Functions.
GROUP BY permits a WITH
ROLLUP modifier. See Section 12.19.2,
GROUP BY Modifiers.
The HAVING clause is applied nearly
last, just before items are sent to the
client, with no optimization. (LIMIT is
applied after HAVING.)
The SQL standard requires
that HAVING must reference only
columns in the GROUP BY clause or
columns used in aggregate functions.
However, MySQL supports an
extension to this behavior, and
permits HAVING to refer to columns in
the SELECT list and columns in outer
subqueries as well.
If the HAVING clause refers to a column
that is ambiguous, a warning occurs. In
the following statement, col2 is
ambiguous because it is used as both
an alias and a column name:
SELECT COUNT(col1) AS col2
FROM t GROUP BY col2 HAVING
col2 = 2;
Preference is given to standard SQL
behavior, so if a HAVING column name
is used both in GROUP BY and as an
aliased column in the output column
list, preference is given to the column
in the GROUP BY column.
Do not use HAVING for items that
should be in the WHERE clause. For
example, do not write the following:
SELECT col_name FROM tbl_name
HAVING col_name > 0;
Write this instead:

SELECT col_name FROM tbl_name


WHERE col_name > 0;
The HAVING clause can refer to
aggregate functions, which
the WHERE clause cannot:
SELECT user, MAX(salary) FROM
users
GROUP BY user HAVING
MAX(salary) > 10;
(This did not work in some older
versions of MySQL.)

MySQL permits duplicate column


names. That is, there can be more
than one select_expr with the same
name. This is an extension to standard
SQL. Because MySQL also
permits GROUP BY and HAVING to refer
to select_expr values, this can result
in an ambiguity:
SELECT 12 AS a, a FROM t
GROUP BY a;
In that statement, both columns have
the name a. To ensure that the correct
column is used for grouping, use
different names for
each select_expr.
MySQL resolves unqualified column or
alias references in ORDER BY clauses
by searching in
the select_expr values, then in the
columns of the tables in
the FROM clause. For GROUP
BY or HAVING clauses, it searches
the FROM clause before searching in
the select_expr values. (For GROUP
BY and HAVING, this differs from the
pre-MySQL 5.0 behavior that used the
same rules as for ORDER BY.)
The LIMIT clause can be used to
constrain the number of rows returned
by the SELECT statement. LIMIT takes
one or two numeric arguments, which
must both be nonnegative integer
constants, with these exceptions:
Within prepared
statements, LIMIT parameters
can be specified
using ? placeholder markers.
Within stored
programs, LIMIT parameters can
be specified using integer-valued
routine parameters or local
variables.
With two arguments, the first argument
specifies the offset of the first row to
return, and the second specifies the
maximum number of rows to return.
The offset of the initial row is 0 (not 1):

SELECT * FROM tbl LIMIT 5,10;


# Retrieve rows 6-15
To retrieve all rows from a certain
offset up to the end of the result set,
you can use some large number for the
second parameter. This statement
retrieves all rows from the 96th row to
the last:
SELECT * FROM tbl LIMIT
95,18446744073709551615;
With one argument, the value specifies
the number of rows to return from the
beginning of the result set:

SELECT * FROM tbl LIMIT 5;


# Retrieve first 5 rows
In other words, LIMIT row_count is
equivalent to LIMIT 0, row_count.
For prepared statements, you can use
placeholders. The following statements
will return one row from the tbl table:
SET @a=1;
PREPARE STMT FROM 'SELECT *
FROM tbl LIMIT ?';
EXECUTE STMT USING @a;
The following statements will return the
second to sixth row from the tbl table:
SET @skip=1; SET @numrows=5;
PREPARE STMT FROM 'SELECT *
FROM tbl LIMIT ?, ?';
EXECUTE STMT USING @skip,
@numrows;
For compatibility with PostgreSQL,
MySQL also supports
the LIMIT row_count OFFSET offse
t syntax.
If LIMIT occurs within a subquery and
also is applied in the outer query, the
outermost LIMIT takes precedence.
For example, the following statement
produces two rows, not one:
(SELECT ... LIMIT 1) LIMIT 2;
A PROCEDURE clause names a
procedure that should process the data
in the result set. For an example,
see Section 8.4.2.4, Using
PROCEDURE ANALYSE, which
describes ANALYSE, a procedure that
can be used to obtain suggestions for
optimal column data types that may
help reduce table sizes.
A PROCEDURE clause is not permitted in
a UNION statement.
Note
PROCEDURE syntax is
deprecated as of MySQL
5.7.18, and is removed in
MySQL 8.0.
The SELECT ... INTO form
of SELECT enables the query result to
be written to a file or stored in
variables. For more information,
see Section 13.2.9.1, SELECT ...
INTO Syntax.
If you use FOR UPDATE with a storage
engine that uses page or row locks,
rows examined by the query are write-
locked until the end of the current
transaction. Using LOCK IN SHARE
MODE sets a shared lock that permits
other transactions to read the
examined rows but not to update or
delete them. See Section 14.5.2.4,
Locking Reads.
In addition, you cannot use FOR
UPDATE as part of the SELECT in a
statement such as CREATE
TABLE new_table SELECT ...
FROM old_table .... (If you attempt
to do so, the statement is rejected with
the error Can't update table
'old_table' while 'new_table'
is being created.) This is a
change in behavior from MySQL 5.5
and earlier, which permitted CREATE
TABLE ... SELECT statements to
make changes in tables other than the
table being created.
Following the SELECT keyword, you can use a number of modifiers that affect the operation of the
statement. HIGH_PRIORITY, STRAIGHT_JOIN, and modifiers beginning with SQL_ are MySQL
extensions to standard SQL.
The ALL and DISTINCT modifiers
specify whether duplicate rows should
be returned. ALL (the default) specifies
that all matching rows should be
returned, including
duplicates. DISTINCT specifies
removal of duplicate rows from the
result set. It is an error to specify both
modifiers. DISTINCTROW is a synonym
for DISTINCT.
HIGH_PRIORITY gives
the SELECT higher priority than a
statement that updates a table. You
should use this only for queries that
are very fast and must be done at
once. A SELECT
HIGH_PRIORITY query that is issued
while the table is locked for reading
runs even if there is an update
statement waiting for the table to be
free. This affects only storage engines
that use only table-level locking (such
as MyISAM, MEMORY, and MERGE).
HIGH_PRIORITY cannot be used
with SELECT statements that are part
of a UNION.
STRAIGHT_JOIN forces the optimizer
to join the tables in the order in which
they are listed in the FROM clause. You
can use this to speed up a query if the
optimizer joins the tables in nonoptimal
order. STRAIGHT_JOIN also can be
used in the table_references list.
See Section 13.2.9.2, JOIN Syntax.
STRAIGHT_JOIN does not apply to any
table that the optimizer treats as
a const or system table. Such a table
produces a single row, is read during
the optimization phase of query
execution, and references to its
columns are replaced with the
appropriate column values before
query execution proceeds. These
tables will appear first in the query plan
displayed by EXPLAIN.
See Section 8.8.1, Optimizing Queries
with EXPLAIN. This exception may
not apply to const or system tables
that are used on the NULL-
complemented side of an outer join
(that is, the right-side table of a LEFT
JOIN or the left-side table of a RIGHT
JOIN.
SQL_BIG_RESULT or SQL_SMALL_RES
ULT can be used with GROUP
BY or DISTINCT to tell the optimizer
that the result set has many rows or is
small, respectively.
For SQL_BIG_RESULT, MySQL directly
uses disk-based temporary tables if
needed, and prefers sorting to using a
temporary table with a key on
the GROUP BY elements.
For SQL_SMALL_RESULT, MySQL uses
fast temporary tables to store the
resulting table instead of using sorting.
This should not normally be needed.
SQL_BUFFER_RESULT forces the result
to be put into a temporary table. This
helps MySQL free the table locks early
and helps in cases where it takes a
long time to send the result set to the
client. This modifier can be used only
for top-level SELECT statements, not
for subqueries or following UNION.
SQL_CALC_FOUND_ROWS tells MySQL
to calculate how many rows there
would be in the result set, disregarding
any LIMIT clause. The number of rows
can then be retrieved with SELECT
FOUND_ROWS(). See Section 12.14,
Information Functions.
The SQL_CACHE and SQL_NO_CACHE m
odifiers affect caching of query results
in the query cache (see Section 8.10.3,
The MySQL Query
Cache). SQL_CACHEtells MySQL to
store the result in the query cache if it
is cacheable and the value of
the query_cache_type system
variable is 2 or DEMAND.
With SQL_NO_CACHE, the server does
not use the query cache. It neither
checks the query cache to see whether
the result is already cached, nor does it
cache the query result.
These two modifiers are mutually
exclusive and an error occurs if they
are both specified. Also, these
modifiers are not permitted in
subqueries (including subqueries in
the FROM clause),
and SELECT statements in unions other
than the first SELECT.
For views, SQL_NO_CACHE applies if it
appears in any SELECT in the query.
For a cacheable
query, SQL_CACHE applies if it appears
in the first SELECT of a view referred to
by the query.
Note
The query cache is deprecated
as of MySQL 5.7.20, and is
removed in MySQL 8.0.
Deprecation
includes SQL_CACHE andSQL_N
O_CACHE.

A SELECT from a partitioned table using a storage engine such as MyISAM that employs table-level
locks locks only those partitions containing rows that match the SELECT statement WHERE clause.
(This does not occur with storage engines such as InnoDB that employ row-level locking.) For more
information, seeSection 22.6.4, Partitioning and Locking.

PREV HOME UP NEXT


User Comments
Posted by Colin Nelson on February 26, 2003
You can simulate a CROSSTAB by the following method:-

Use IF function to select the key value of the sub table as in:

SELECT
SUM(IF(beta_idx=1, beta_value,0)) as beta1_value,
SUM(IF(beta_idx=2, beta_value,0)) as beta2_value,
SUM(IF(beta_idx=3, beta_value,0)) as beta3_value
FROM alpha JOIN beta WHERE alpha_id = beta_alpha_id;

where alpha table has the form alpha_id, alpha_blah, alpha_blah_blah


and beta table has the form beta_alpha_id, beta_other stuff,
beta_idx, beta_value

This will create 3 columns with totals of beta values according to their idx field

Posted by Corin Langosch on March 29, 2003


when selecting a single random row you have to use a query like this: SELECT ... FROM my_table ORDER BY
RAND() LIMIT 1.
as explain shows, mysql optimizes this VERY badly (or may be better said, doens't optimize it at all): it uses an
temporary table and an extra filesort.
couldn't this be optimized?!
if not, may be add a syntax like SELECT RANDOM_ROW .... FROM my_table ...

Posted by David Phillips on April 2, 2003


This method of selecting a random row should be fast:

LOCK TABLES foo READ;


SELECT FLOOR(RAND() * COUNT(*)) AS rand_row FROM foo;
SELECT * FROM foo LIMIT $rand_row, 1;
UNLOCK TABLES;

Unfortunately, variables cannot be used in the LIMIT clause, otherwise the entire thing could be done
completely in SQL.

Posted by on August 20, 2003


In reply to David Philips:

If your tables are not all that big, a simpler method is:
SELECT * FROM foo ORDER BY RAND(NOW()) LIMIT 1;

If it's a big table, your method will almost certainly be faster.

Posted by Count Henry De Havilland-Fortesque-Smedley on January 13, 2004


If you want to find duplicates on a field that hasn't been uniquely indexed, you can do this:

SELECT BookISBN, count(BookISBN) FROM Books GROUP BY BookISBN HAVING COUNT(BookISBN)>1;

Posted by Count Henry De Havilland-Fortesque-Smedley on January 13, 2004


Sometimes you want to retrieve the records that DONT match a select statement.

Consider this select:


SELECT CarIndex FROM DealerCatalog, BigCatalog WHERE
DealerCatalog.CarIndex=BigCatalog.CarIndex

This finds all the CarIndex values in the Dealer's catalog that are in the bigger distributor catalog.

How do I then find the dealer CarIndex values that ARE NOT in the bigger catalog?

The answer is to use LEFT JOIN - anything that doesn't join is given a NULL value , so we look for that:

SELECT CarIndex FROM DealerCatalog LEFT JOIN BigCatalog ON


DealerCatalog.CarIndex=BigCatalog.CarIndex WHERE BigCatalog.CarIndex IS NULL

Posted by Johann Eckert on February 11, 2004


To find double entries in a table:

SELECT db1.*
FROM tbl_data db1, tbl_data k2
WHERE db1.id <> db2.id
AND db1.name = db2.name

db1.id must be the PK


db1.name must be the fields that should be verified as double entries.

(I'm not sure wether the code is correct but in my case it works)

Johann

Posted by on March 2, 2004


In order to anti-match fields by wildcards, one has to check whether the value of the field is not NULL:

For example: The table 'runs' contains 34876 rows. 205 rows have an 'info' field containing the string 'wrong'.

To select those rows for which the 'info' column does *NOT* contain the word 'wrong' one has to do:

mysql> select count(*) FROM runs WHERE info is null or info not like '%wrong%';

+----------+
| count(*) |
+----------+
| 34671 |
+----------+

but not:
mysql> select count(*) FROM runs WHERE info not like %wrong%';

+----------+
| count(*) |
+----------+
| 5537 |
+----------+

which would lead to a much smaller number of selected rows.

Posted by M M on March 4, 2004


I have managed to select random records using php and MySQL like the following:

$min=1;
$row=mysql_fetch_assoc(mysql_query("SHOW TABLE STATUS LIKE 'table';"));
$max=$row["Auto_increment"];
$random_id=rand($min,$max);
$row=mysql_fetch_assoc(mysql_query("SELECT * FROM table WHERE id='$random_id'");

Voila...

Cezar
http://RO-Escorts.com

Posted by Geert van der Ploeg on March 9, 2004


Random records without PHP, only MySQL:

select * from mailinglists order by rand() limit 1

Regards,
Geert van der Ploeg

Posted by Cody Caughlan on May 26, 2004


Sometimes it is nice to use the SELECT query options like SQL_CALC_FOUND_ROWS or SQL_CACHE, but
to maintain compatibility across different databases or even older versions of MySQL which do not support
those options, it is possible to enclose them in a comment block, e.g.:

SELECT /*! 40000 SQL_CALC_FOUND_ROWS */ foo,bar FROM some_table;

The /* construct will stop DBMS's other than MySQL from parsing the comment contents, while /*! will tell ALL
MySQL versions to parse the "comment" (which is actually a non-comment to MySQL). The /*!40000 construct
will tell MySQL servers starting from 4.0.0 (which is the first version to support SQL_CALC_FOUND_ROWS) to
parse the comment, while earlier versions will ignore it.

Posted by Boris Aranovich on June 9, 2004


I am using this way to select random row or rows:

SELECT * [or any needed fileds], idx*0+RAND() as rnd_id FROM tablename ORDER BY rnd_id LIMIT 1 [or the
number of rows]

Meanwhile, I didn't stumble in any problems with this usage.


I picked this method in some forum, don't remember when, where or by who was it introduced :)

Posted by Michal Nedoszytko on August 10, 2004


My method of retrieving duplicate entries

In a database with personal information (name, surname, etc..) with an auto_increment index I wanted to
retrieve all the entries with same name and surname field (duplicate names), which by accident were inserted
to the base.

I used this syntax

SELECT name,surname,COUNT(name) AS cnt_n, COUNT(surname) AS cnt_s FROM the_table GROUP BY


name HAVING cnt_n>1 AND cnt_s>1;

I hope this might be of help to anyone that wants to do some extended maintenance on the database

Posted by Dmitri Mikhailov on August 24, 2004


On the other hand, for this case it's simplier to engage an appropriate index if there is such:

CREATE INDEX ccr_news_insert_date_i ON ccr_news (insert_date DESC);

SELECT *
FROM ccr_news
WHERE insert_date > 0;

or, if for some reason MySQL still uses a full table scan:

SELECT *
FROM ccr_news FORCE INDEX (ccr_news_insert_date_i)
WHERE insert_date > 0;

Posted by Adam Tylmad on August 25, 2004


If you want to ORDER BY [columnname] ASC
and have the NULL rows in the bottom
you can use ORDER BY -[columnname] DESC

Posted by Edward Hermanson on October 6, 2004


Select Name,Category FROM authors ORDER BY Category,Name;

Will allow you to sort by categories listed in a seperate table


IF the category column in this primary table contains ID values
from your ID column in your second reference table.

So your first "authors" table looks like:

id name category
1 Henry Miller 2
3 June Day 1
3 Thomas Wolf 2

and your second reference table looks like:

id category
1 Modern
2 Classics

Now when the order of categories is changed in the second table


the order of categories will be reflected in the primary table.

Then just select the categories from the reference table and put
the list into a numbered array. Then in your script when you run
across a category number from the first recordset just reference
the value from the index in the second array to obtain the value.
In php in the above example it might look like:

foreach ($recordset as $key => $record) {


echo $record["id"] . ":" . $record["name"] . ":" . $ordered_cats[$record["category"]];
}

This may seem obvious to some but I was pulling my hair out
trying to figure out how to order a recordset based on a list
from a different table. Hope this helps someone.

Ed

Posted by Greg Covey on December 2, 2004


The LIMIT clause can be used when you would use TOP in Access or MS SQL.

Posted by Kenan Bektas on December 14, 2004


(LINUX) By default, if you don't specify absolute path for OUTFILE in
select ... into OUTFILE "..."

It creates the file in "/var/lib/mysql/<database_name>"

Make sure current user has (NOT) a write permission in that directory.

Posted by Kumar S on January 4, 2005


If You want to find the rows which are having a column with identical values then,

SELECT managerId, count(company) FROM manager GROUP BY company HAVING COUNT(company)>=8


(say)

Regards,
Kumar.S

Posted by Imran Chaudhry on February 17, 2005


I found a nifty way of influencing the ORDER of rows returned by a query that helps in displaying a list with
frequently accessed items at the top.

An example is a name/address form where the country is a selectable list. If most of your users are from the
UK and US you may want to do something like:

SELECT * FROM countries ORDER by iso_code IN ('UK', 'US') desc

Which returns something like:

+----------+----------------------------------------+
| iso_code | name |
+----------+----------------------------------------+
| UK | United Kingdom |
| US | United States |
| AF | Afghanistan |
| AL | Albania |
| DZ | Algeria |
| AS | American Samoa |

Hope this helps someone! [email protected]

Posted by Fahed Bizzari on February 22, 2005


It seems there is no way to select * from table where a certain field is distinct. In 2 sqls it is easy:

$sql9 = "SELECT DISTINCT field AS distinctfield FROM table ORDER BY distinctfield ";
$res9= $db->execute($sql9);
for($ll=0;$ll<$res9->getNumTuples();$ll++)
{
$row = $res9->getTupleDirect($ll);
$distinctfield = $row[distinctfield];
$sql8="select * from table WHERE field='distinctfield' ORDER BY distinctfield LIMIT 1";
}

But not one!

Fahed

Posted by M Berman on February 22, 2005


reply to Fahed Bizzari's post, based on Havilland-Fortesque-Smedley's comment (above) the equivalent of
select * while doing DISTINCT is:
select *, count(FIELD) from TABLE group by FIELD having count(FIELD)=1 into outfile 'foobar.txt';

then you can check the output. note that there are twice as many rows as records, because each unique row is
followed by its count (in this case count=1). so just toss the .txt file into something and sort on the field
containing the count and throw out all the rows =1. this is the same result as a select * distinct FIELD (as far as
I can tell).

anyway, works for me. aloha. Lex

Posted by M Berman on February 22, 2005


oh, about the previous post, it's not correct because distinct should be

count(FIELD)=>1

which still doesn't solve the DISTINCT part

Lex

Posted by Gregory Turner on March 10, 2005


In regards to:
_______________________________________________
******************************************
I found a nifty way of influencing the ORDER of rows returned by a query that helps in displaying a list with
frequently accessed items at the top.

An example is a name/address form where the country is a selectable list. If most of your users are from the
UK and US you may want to do something like:

SELECT * FROM countries ORDER by iso_code IN ('UK', 'US') desc

Which returns something like:

+----------+----------------------------------------+
| iso_code | name |
+----------+----------------------------------------+
| UK | United Kingdom |
| US | United States |
| AF | Afghanistan |
| AL | Albania |
| DZ | Algeria |
| AS | American Samoa |
_______________________________________________
******************************************
If found that if you also add in another 'iso_code' column in the order by statment after the first one containing
the IN() statment, it will sort the remaining records:
SELECT * FROM countries ORDER by iso_code IN ('UK', 'US') desc, iso_code

Posted by Heywood on March 11, 2005


When using the SELECT ... INTO OUTFILE syntax, use a UNION to add headers. Here's an example for CSV
output:

SELECT 'Fiscal Year','Location','Sales'


UNION
SELECT FY, Loc, Sales INTO OUTFILE 'salesreport.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM SalesTable;

This will add the text headers Fiscal Year, Location and Sales to your fields. Only caveat is with an ORDER BY
statement, if you don't want your headers sorted along with your data you need to enclose it in parenthesis:

SELECT 'Fiscal Year','Location','Sales'


UNION
{SELECT FY, Loc, Sales INTO OUTFILE 'salesreport.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM SalesTable
ORDER BY Sales DESC);

Posted by on April 21, 2005


To correct Lex one more time, it should be count(FIELD)>=1.

So the whole query for retrieving a whole row with one field distinct is:

select *, count(FIELD) from TABLE group by FIELD having count(FIELD)>=1;

Thanks, Lex. You are a lifesaver.

Posted by Jerry Nelson on May 6, 2005


As a newbie to MySQL and to dealing with BLOBs, I had a difficult time trying to determine how to extract a
BLOB field from the database back to a file. It turns out to be quite simple by doing the following SQL:

select blobfield into dumpfile '/tmp/blobfile' from blobtable;

Posted by joel boonstra on May 12, 2005


In response to Heywood's tip about adding column headers to OUTFILEs...

Make sure that the format of the columns that match up with your headers doesn't limit the display of the
headers. For instance, I was using the UNION tip to add a header to a column defined as char(2) (for storing a
two-letter state code). The resulting CSV file only displayed the first two letters of my column header. The fix is
simple, just use CAST() on the column in the second SELECT to convert it to the appropriate type. In my case,
doing something like this:

SELECT 'state header' FROM table UNION SELECT CAST(state AS char) FROM table INTO OUTFILE [...]

worked just dandy. Hope that saves someone a little time.

Posted by Rene Liethof on June 8, 2005


Arbitrary Ordering

I came across this example at


http://www.shawnolson.net/a/722/
Neat way of using the CASE statement.

Example for ordering price information


price is orderd ascending but the 0.00
prices end up underneath

SELECT dienst.dienst, dienst.url, dienst.info, dienst_prijs.dienst_eenheid, dienst_prijs.prijs,


dienst_prijs.inc_btw, dienst_prijs.dienst_optie,
CASE dienst_prijs.prijs
WHEN dienst_prijs.prijs = '0.00' THEN 1000
WHEN dienst_prijs.prijs > '0.00' THEN 10
ELSE NULL
END AS orderme
FROM dienst, dienst_prijs
WHERE dienst.taal = 'nl' &&
dienst.dienst_type = 'Internet toegang' &&
dienst.dienst != 'alle diensten' &&
dienst.publiceer != '' &&
dienst_prijs.dienst_eenheid IN ( 'maand', 'jaar' ) &&
dienst.dienst = dienst_prijs.dienst
ORDER BY orderme, dienst_prijs.prijs

Posted by Callum Macdonald on June 27, 2005


If you want to use ORDER BY before GROUP BY, the only way I've found to achieve it is with a subquery.

For example, if you want to get a list of users from a table UserActions sorted according to the most recent
action (based on a field called Time) the query would be:

SELECT * FROM (SELECT * FROM UserActions ORDER BY Time DESC) AS Actions GROUP BY UserID
ORDER BY Time DESC;

Without the subquery, the group is performed first, and so the first record that appears in the database (which
is not necessarily in the order you want) will be used to determine the sort order. This caused me huge
problems as my data was in a jumbled order within the table.

--Edit--
This same result can be achieved with the use of MAX(Time), so the query would be:

SELECT *, MAX(Time) AS LatestAction GROUP BY UserID ORDER BY LatestAction DESC;

As far as I can see, the subquery model still holds up if you need more complex sorting before performing the
GROUP.

Posted by Paul Montgomery on August 13, 2005


I've seen it asked elsewhere about how to select all duplicates, not just one row for each dupe.

CREATE TEMPORARY TABLE dupes SELECT * FROM tablename GROUP BY colname HAVING
COUNT(*)>1 ORDER BY colname;
SELECT t.* FROM tablename t, dupes d WHERE t.colname = d.colname ORDER BY t.colname;

Posted by Wayne Smith on November 4, 2005


Be careful about the "SELECT...INTO OUTFILE" options. They are similar to, but not exactly the same as, the
mysqldump options.

Two things:

1) The options in mysqldump can be in any order, because they are true command-line options (that is, they
are conceptually used together, but syntactically separate on the mysqldump command line). The options in the
SELECT...INTO OUTFILE need to be in the exact order as specified in the documentation above.

2) The options MUST have dashes between the words (e.g., fields-enclosed-by) when use as options with the
mysqldump utility, but MUST NOT have dashes when used as options with the SELECT...INTO OUTFILE. This
may not be clear in the documentation above.

Wayne

Posted by Geoff on November 9, 2005


In reply to Fahed Bizzari et al...

If you want to select all fields from distinct rows why not use:
SELECT DISTINCT * FROM table GROUP BY field;
Don't forget the DISTINCT relates to the ORDER BY / GROUP BY and has nothing to do with the 'select_expr'

If you want the count as well then use:


SELECT DISTINCT *, count(*) AS count FROM table GROUP BY field;

Posted by Kumar Mitra-Endres on November 22, 2005


Where is the pagination code as offered by the google search machine????

Kumar/Germany

Posted by Flavio Ventura on December 9, 2005


If you have a binary string type field and you want a case insensitive sorting you can use CAST() as follow:

case sensitive example (DECODE return a binary string):


----------------------------------------------------------------------------
SELECT DECODE(EncodedField) AS DecodedField
FROM TableWithEncodedField
ORDER BY DecodedField;

case insensitive solution:


---------------------------------
SELECT CAST(DECODE(EncodedField) AS CHAR) AS DecodedField
FROM TableWithEncodedField
ORDER BY DecodedField;

I hope it may be usefull.

Posted by mike gieson on January 10, 2006


To select specific rows from the table use the IN statement.

Example:

SELECT * FROM table WHERE myid IN (2, 16, 93,102);

This would return multiple rows based on specific criteria.

Posted by Todd Farmer on January 22, 2006


For large tables with auto incremented primary key values, I have found the following to be most efficient in
obtaining one random row:

SELECT * FROM my_table


WHERE pk_column >=
(SELECT FLOOR( MAX(pk_column) * RAND()) FROM my_table)
ORDER BY pk_column
LIMIT 1;

Posted by Vlado Kocan on January 28, 2006


Reply to Edward Hermanson post (above):

I prefer this way of sorting table by column values listed in another table:

The accnumber column in primary table contains ID values from ID column in the secondary table.

Primary table "contacts":


id name accnumber
1 Cooke 3
2 Peterson 3
3 Stevens 1

Secondary table "accounts":


id accname
1 Company1
2 Company2
3 Company3

SELECT contacts.lname, accounts.accname


FROM contacts, accounts
WHERE contacts.accnumber = accounts.id ORDER BY accname;

Posted by Lars-Erik Hoffsten on March 14, 2006


ORDER BY textfield in natural order!?
Lets say you want the following result:
File1
File2
File10

I havn't found a way to do it in SQL, here is a way to do it in PHP (just replace 'order_by' to the field you want to
order by):

$result = mysql_query("SELECT order_by,... FROM table");


$rows = array();
if($result)
{
while(($row = mysql_fetch_array($result, MYSQL_ASSOC)))
$rows[] = $row;
usort($rows, create_function('$a, $b', 'return strnatcasecmp($a["order_by"], $b["order_by"]);'));
}

Posted by Michal Carson on March 19, 2006


SELECT ... INTO OUTFILE requires the id to have the FILE privilege. That is,

GRANT SELECT, FILE ON * . * TO "[whomever]"@ "localhost";

As noted above, the output directory must be writable by the id under which the mysqld process is running. Use
"grep user= /etc/my.cnf " to find it.

Posted by Andrew Culver on March 20, 2006


Selecting a random row in SQL? Try:

set @a = (SELECT COUNT(*)-1 c FROM palette)*RAND() DIV 1;


PREPARE STMT FROM 'SELECT * FROM palette LIMIT ?,1';
EXECUTE STMT USING @a;

Posted by on March 21, 2006


If you want to keep field names, consider using mysqldump instead of SELECT INTO OUTFILE.

I use this method to transfer small amounts of data from our live database to our test database, for example
when investigating a reported problem in our program code. (We cannot guarantee the field order across all our
databases.)

rem Edit order number before running


rem Give password when prompted
rem Result files will be in current working directory
\mysql\bin\mysqldump livedb -uliveuser -p --no-create-info --tables orderpayment --
where=orderid=2712>resultp.txt
\mysql\bin\mysqldump livedb -uliveuser -p --no-create-info --tables orderitem --where=orderid=2712>resulti.txt
\mysql\bin\mysqldump livedb -uliveuser -p --no-create-info --tables orderheader --where=id=2712>resulth.txt

Posted by Zhao Xinyou on March 29, 2006


when you meet more conditions, you may use the following code:
select * from yourdatabase where fieldone='value1' and fieldtwo='value2';

Posted by John Bachir on April 3, 2006


Fahed Bizzari, that is not 2 queries, that is $res9->getNumTuples() + 1 queries!

Posted by Michael Heyman on April 28, 2006


To select the identifiers with the greatest value in each class (where each identifier falls into one class):

SELECT id_class,id FROM tbl,(SELECT MAX(val) AS val FROM tbl GROUP BY id_class) AS _tbl WHERE
tbl.val = _tbl.val;

We had a table logging state changes for a series of objects and wanted to find the most recent state for each
object. The "val" in our case was an auto-increment field.

This seems to be the simplest solution that runs in a reasonable amount of time.

Posted by Rich Altmaier on May 4, 2006


In a student signup list, use sql to find classes which are
not full. Involves combined use of RIGHT JOIN, COUNT, WHERE, GROUP BY, HAVING, and ORDER BY.

CREATE TABLE `classdescription` (


`ClassID` mediumint(9) NOT NULL auto_increment,
`ClassType` varchar(10) NOT NULL default '',
`ClassName` varchar(50) NOT NULL default '',
`ClassDate` datetime NOT NULL default '0000-00-00 00:00:00',
`ClassMax` mediumint(9) default NULL,
PRIMARY KEY (`ClassID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

CREATE TABLE `class_signups` (


`s_PersonID` mediumint(9) NOT NULL default '0',
`s_ClassID` mediumint(9) NOT NULL default '0',
`s_Status` varchar(5) default NULL,
KEY `s_ClassID` (`s_ClassID`),
KEY `s_PersonID` (`s_PersonID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `classdescription` VALUES (2, 'firstaid', '', '2005-01-02 11:00:00', 2);
INSERT INTO `classdescription` VALUES (3, 'advanced-med', '', '2005-01-02 13:00:00', 1);

INSERT INTO `class_signups` VALUES (11, 2, '');


INSERT INTO `class_signups` VALUES (12, 2, '');

Now use RIGHT JOIN to list all class descriptions along with signups if any,
SELECT cs.s_ClassID, cs.s_PersonID, cd.ClassName, cd.ClassID, cd.ClassType, cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID )
in itself, not too useful, but you can see classes
having no one signed up as a NULL.

To count the number of signups for each class:


SELECT cs.s_ClassID, COUNT(s_ClassID) AS ClassTotal, cd.ClassName, cd.ClassID, cd.ClassType,
cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID )
GROUP BY cd.ClassID
The COUNT/GROUP BY options show a row per unique ClassID, and the COUNT is adding up
non-null occurances of field s_ClassID. If we had used COUNT(*) then the class with
no signups would have counted 1 record, rather than the desired 0/NULL for no
signups.

Now we show only classes where the count of signups is less than ClassMax, meaning the
class has openings!
SELECT cs.s_ClassID, COUNT(s_ClassID) AS ClassTotal, cd.ClassName, cd.ClassID, cd.ClassType,
cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID )
GROUP BY cd.ClassID
HAVING ClassTotal < cd.ClassMax
The HAVING clause limits the after-JOIN output rows to ones matching its criteria, discarding others!

We may want to look only at the firstaid ClassType, so add a WHERE clause to
the JOIN,
SELECT cs.s_ClassID, COUNT(s_ClassID) AS ClassTotal, cd.ClassName, cd.ClassID, cd.ClassType,
cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID ) WHERE cd.ClassType='firstaid'
GROUP BY cd.ClassID
HAVING ClassTotal < cd.ClassMax
Now there are no outputs as firstaid is full, but
suppose we are looking in this list with respect
to a certain student PersonID==12. That is, we want to see classes this person can signup
for, including the ones they are already in!
In the case we need to disregard signups by PersonID==12 for e.g.,

SELECT cs.s_ClassID, COUNT(s_ClassID) AS ClassTotal, cd.ClassName, cd.ClassID, cd.ClassType,


cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID AND cs.s_PersonID <> 12) WHERE cd.ClassType='firstaid'
GROUP BY cd.ClassID
HAVING ClassTotal < cd.ClassMax
In the join we drop out signups of PersonID 12, so they don't get counted.

Finally we probably want to show the available classes in date order:

SELECT cs.s_ClassID, COUNT(s_ClassID) AS ClassTotal , cd.ClassName, cd.ClassID, cd.ClassType,


cd.ClassDate, cd.ClassMax
from class_signups cs RIGHT JOIN
classdescription cd on (cs.s_ClassID = cd.ClassID AND cs.s_PersonID <> 12)
WHERE cd.ClassType='firstaid'
GROUP BY cd.ClassID
HAVING ClassTotal < cd.ClassMax ORDER BY ClassDate

I had fun figuring this out, I hope it works for you.


(sorry it was so long).
Rich
Posted by YI ZHANG on May 10, 2006
If you cancel a long-time running query by Ctrl-C, you might find the CPU load of mysqld remains at 99%.
That's because the query is still running on mysqld, and Ctrl-C only closes the client.
Now, you can enter mysql again and use command SHOW PROCESSLIST to check the thread of the query,
and kill the query by command KILL thread_id.
I'm using mysql 5.0.21.

Posted by Wade Bowmer on May 14, 2006


Be aware that SQL_CALC_FOUND_ROWS disables ORDER BY ... LIMIT optimizations (see
bugs http://bugs.mysql.com/bug.php?id=18454 and http://bugs.mysql.com/bug.php?id=19553). Until it's fixed,
you should run your own benchmarks with and without it.

Posted by Marc Grue on June 24, 2006


Since the LIMIT clause of a SELECT statement doesn't allow user variables you can use a prepared statement
as in the example above in the manual. An alternative is to load all record ids of yourTable into a temporary
table as shown below. This also has the benefit of getting all data necessary for pagination of your result set:

CREATE PROCEDURE `listData`(IN _limitstart INT, IN _limit INT)


BEGIN
-- make a 'row container'
DROP TEMPORARY TABLE IF EXISTS AllRows;
CREATE TEMPORARY TABLE AllRows (rownum INT, id INT, label VARCHAR(50)) ENGINE=MEMORY;

-- insert all ids (and optional labels (for use in a page selector))
SET @a=-1;
INSERT INTO AllRows SELECT @a:=@a+1 AS rownum, id, CONCAT(first_name, ' ', last_name) AS label
FROM yourTable;

## Output 1: total number of rows


SELECT @a+1 AS total_rows;

## Output 2: id/labels for pagination [see table 'NumberSeq' below]


SELECT * FROM AllRows
INNER JOIN NumberSeq ON AllRows.rownum = NumberSeq.n*_limit
WHERE (n*_limit) < @a+1;

## Output 3: data for list


SELECT yourTable.* FROM yourTable
INNER JOIN AllRows ON yourTable.id = AllRows.id
WHERE rownum >= _limitstart AND rownum < (_limitstart+_limit);

DROP TEMPORARY TABLE AllRows;


END

The NumberSeq table just contains the numbers 0, 1, 2, 3, ... 500 (or whatever limit you want to set on number
of pages..):

CREATE PROCEDURE `createNumberSeq `()


BEGIN
DECLARE _n int default -1;
DROP TABLE IF EXISTS NumberSeq;
CREATE TABLE NumberSeq (n INT);
loop1: LOOP
SET _n = _n + 1;
INSERT INTO NumberSeq (n) VALUES _n;
IF _n >= 500 THEN
LEAVE loop1;
END IF
END LOOP loop1;
END

With smaller record sets the second approach is faster than the prepared statement approach. Haven't
checked speed with bigger record sets, but suspect the first approach will win then...

Hope this helps to get around the limitations of the LIMIT clause. To the MySQL team: any plans to allow user
variables in the LIMIT clause? (pleeeze!)

Posted by Rene Lopez on June 23, 2006


If you want to get the record in an specific order you can do it like this

SELECT * FROM table ORDER BY FIELD( id, 23, 234, 543, 23 )

+----------+---------------------------+
| id | name |
+----------+---------------------------+
| 23 | rene |
| 234 | miguel |
| 543 | ana |
| 23 | tlaxcala |

or if the table as a name

SELECT * FROM table ORDER BY FIELD( name, 'miguel', 'rene', 'ana', 'tlaxcala' )

+----------+---------------------------+
| id | name |
+----------+---------------------------+
| 234 | miguel |
| 23 | rene |
| 543 | ana |
| 23 | tlaxcala |

Posted by Marc Grue on June 24, 2006


Example of using dynamic column_name parameters in the ORDER BY clause of a SELECT statement in
stored procedures:
http://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html
(go to posting by Marc Grue on June 24 2006)

Posted by Dennis Lindkvist on June 28, 2006


Or you could use this.

select [column], rand() as rnd from [table] order by rnd

Althoug there is still overhead compared to "order by null" its not as bad as "order by rand()".

Posted by Chris Whitten on July 14, 2006


I was trying to figure out how to sort a varchar field which contained both number string and alphanumeric
string. I wanted to sort it so that the numbers would be in order and then the alphanumeric entries would be in
order. Here is the query that helped me accomplish that:

SELECT partnum, comments , if( partnum >0, cast( partnum AS SIGNED ) , 0 ) AS numpart,
if( partnum >0, 0, partnum ) AS stringpart
FROM `part`
ORDER BY `numpart` , `stringpart`
Posted by Frank Flynn on October 6, 2006
If you wish to use OUTFILE or DUMPFILE with a variable for the file name you cannot simply put it in place -
MySQL will not resolve the name.

But you can put the whole command into a variable and use "prepare" and "execute" for example:

SELECT @myCommand := concat("SELECT * into OUTFILE '/home/mysql/archive/daemonLog-",


DATE_FORMAT(now(),'%Y%m%d-%H%i%s'), "' FROM daemonLog");
PREPARE stmt FROM @myCommand;
EXECUTE stmt;

This will work, Good luck.

Posted by Michael Ekoka on November 8, 2006


Just my little contribution when it comes to random row selection used with mysql & php. Based on the solution
that consists of returning the count(*) of a table, then using that value to select a random row.

SELECT FLOOR(RAND() * COUNT(*)) AS rand_row FROM foo;


SELECT * FROM foo LIMIT {$rand_row}, 1;
or
SELECT COUNT(*) AS rows FROM foo;
SELECT * FROM foo LIMIT {rand(0,$rows-1)}, 1;

The problem with that solution from the MySQL standpoint is that there still remains the possibility of duplicate
selections when we want more than one row, especially if the table is not that large (e.g. what are the chances
of getting at least 2 duplicate rows while selecting 5 randomly, 1 at a time, out of a set of 10).

My approach is to rather generate unique random numbers from php, then fetch the corresponding table rows:

1- Use the appropriate php methods to fetch the table count from MySQL as done before:
SELECT COUNT(*) FROM foo;

2- Use php to generate some unique random numbers based on the count.

This is the php function that i use. It takes 3 arguments: the minimum and maximum range values, and the
amount of unique random numbers to be returned. It returns these numbers as an array.

<?php
/*Array of Unique Random Numbers*/

function uniq_rand($min,$max,$size){
$randoms=array(); //this is our array

/*if ($min > $max) swap their value*/


if($min>$max){
$min=$min^$max;$max=$min^$max;$min=$min^$max;
}

/*if requested size of array is larger than possible


or if requested size of array is negative return*/
if ( (($max-$min)+1)<$size || $size<=0 ){return false;}

/*while array has not reached the requested size


keep generating random numbers and insert them
if they're not yet present in the array */
while (count($randoms)<$size){
$newval = rand($min,$max);
if(!in_array($newval,$randoms)){$randoms[] = $newval;}
}

return $randoms;
}
?>

3- Once you receive your set of randoms from the above function, perform a query for each random:

<?php
foreach($randoms as $random_row){
$query="SELECT * FROM foo LIMIT $random_row, 1;"
//perform query, retrieve values and move on to the next random row
...
}
?>

That's it
-----

On a side note regarding the php random number generation function that I have here, I'm sure it's not the best
solution all the time. For example, the closer the amount of random numbers gets to the range of numbers
available the less efficient the function gets, i.e. if you have a range of 300 numbers and you want 280 of them
unique and random, the function could spend quite some time trying to get the last 10 numbers into the array.
Some probabilities get involved here, but I suspect that it would be faster to insert the 300 numbers directly into
an array, shuffle that array, then finally select the 280 first entries and return them.

Also, as pointed earlier in the thread, keep in mind that if your table isn't that large, just performing the following
works very well (e.g. selecting 5 random rows on a moderately large table):
SELECT * FROM foo ORDER BY RAND() LIMIT 5;

Posted by Rustam Valiev on November 17, 2006


If you want use multilanguage queryies you cat use this:
Table 1
--------------
langid langname
--------------
1 rus
2 eng
3 den
---------------
Table 2 (catalog)
-----------------------
catid url
-----------------------
1 www.google.com
2 www.yandex.ru
3 www.mysql.com
------------------------
table 3 (titles of sites from Table 3)
-------------------------------------
langid catid title
-------------------------------------
1 1 Poiskovaya sistema
2 1 Search system
1 2 Portal
2 2 Portal
3 2 Portal
1 3 Sayt razrabotchikov MySQL
2 3 Site of MySQL's team
3 3 Bla bla bla
------------------------------------
And you need select sites from table2 on any language (for example Denmark), but site google.com have not
title by Denmark. Ok if you can't select title by current language, you should select title by default language
(here russian). You can make in one query
SELECT *, (
SELECT title
FROM table3
WHERE table3.catid = table2.catid AND langid = 3
UNION
SELECT title
FROM table3
WHERE table3.catid = table2.catid AND langid = 1
LIMIT 1
) as title
FROM table2

It very easy, but i think it query very big for MySQL if table2 contain around 1000-5000 rows, and site have
5000-6000 people per second.

You can make it another:


SELECT *, (SELECT title FROM table3 ORDER BY IF(langid='1',0,1) ASC LIMIT 1) as title FROM `table2`
i couldn't compare this queries, if anybody can compary spped of this method please write
[email protected] (by russian (:^) .

Now my task more complexed, i need select any site from table2 :
1 - On current language
2 - If site have not title, Select title by default language
3 - If site have not title on default, Select title by any language.
I think if will make it by thats method - it will very big for MySQL.

Posted by Ray Perea on December 8, 2006


In regards to:
Posted by Count Henry De Havilland-Fortesque-Smedley on January 13 2004 5:59am
--------------START QUOTE---------------------
Sometimes you want to retrieve the records that DONT match a select statement.

Consider this select:


SELECT CarIndex FROM DealerCatalog, BigCatalog WHERE
DealerCatalog.CarIndex=BigCatalog.CarIndex

This finds all the CarIndex values in the Dealer's catalog that are in the bigger distributor catalog.

How do I then find the dealer CarIndex values that ARE NOT in the bigger catalog?

The answer is to use LEFT JOIN - anything that doesn't join is given a NULL value , so we look for that:

SELECT CarIndex FROM DealerCatalog LEFT JOIN BigCatalog ON


DealerCatalog.CarIndex=BigCatalog.CarIndex WHERE BigCatalog.CarIndex IS NULL
------------------END QUOTE--------------------------

I have found that the Left Join is quite expensive when doing this type of SQL Query. It is great if you have less
than 1000 records in each table that you want to compare. But the real hardship is realized when you have
100,000 records in each table. Trying to do this type of join takes forever because each and every record in 1
table has to be compared to each and every record in the other table. In the case of 100,000 records, MySQL
will do 10 BILLION comparisons (from what I have read, I may be mistaken).

So I tried the sql query above to see which rows in 1 table do not have a corresponding value in the other table.
(Note that each table had close to 100,000 rows) I waited for 10 minutes and the Query was still going. I have
since came up with a better way that works for me and I hope it will work for someone else. Here goes....

1: You must create another field in your base table. Let's call the new field `linked` (For the example above, we
would perform this query ---ONLY ONCE--- to create the linked field in the DealerCatalog table.)

ALTER TABLE `DealerCatalog` ADD `linked` TINYINT NOT NULL ;

2: Now to get your results, simply execute the following queries instead of the left join query stated above

UPDATE `DealerCatalog` SET `linked` = 0;


UPDATE `DealerCatalog`, `BigCatalog` SET `linked` = 1 WHERE `DealerCatalog`.`CarIndex` =
`BigCatalog`.`CarIndex`;
SELECT `CarIndex` FROM `DealerCatalog` WHERE `linked` = 0;

I know it is 3 queries instead of 1 but I am able to achieve the same result with 100K rows in each table in
about 3 seconds instead of 10 minutes (That is just how long I waited until I gave up. Who knows how long it
actually takes) using the LEFT JOIN method.

I would like to see if anyone else has a better way of dealing with this type of situation. I have been looking for
a better solution for a few years now. I haven't tried MySQL 5 yet to see if there is a way to maybe create a
view to deal with this situation but I suspect MySQL developers know about the expensive LEFT JOIN....IS
NULL situation on large tables and are doing something about it.

Until then, you have my contribution


Ray Perea

Posted by Frederic Theriault on December 8, 2006


Make sure you don't use stored functions in your WHERE clause if it is not necessary.

For our search feature, we needed to get an id using a stored function. Since it was in the WHERE clause, it
reprocesses the function for every row! This could turn out to be pretty heavy.

If you can, do it in the FROM clause. Ex:


SELECT
...
FROM
...,
(select getSpecialID() as specialID) as tmp
WHERE
...

In our case we went from 6.5 sec query to 0.48 sec. We have over 2 million rows in our tables.

Posted by Hctor Hugo Huergo on April 19, 2007


Hi! I'm using SELECT ... INTO OUTFILE. First Ive permissions problems. Add to the user the FILE privileges...
AND RESTART THE DAEMON :). Bye
Posted by Will Jaspers on May 4, 2007
For anyone utilizing two or more tables to create select boxes, I've finally (and painstakingly) found a way to
check if the item is selected.

-- Sample table 1, we'll call this 'STATES'


CREATE TABLE states
(
state_id int auto_increment not null,
state_code char(2) not null,
state_name varchar(100) not null,
UNIQUE(state_code),
PRIMARY KEY(state_id)
);

CREATE TABLE drivers


(
driver id int not null auto_increment,
driver_name varchar(255) not null,
PRIMARY KEY(driver_id)
);

CREATE TABLE drove_to_states


(
state_id int not null,
driver_id int not null,
arrived datetime not null,
departed datetime not null,
notes text
);

-- Query
SELECT
s.`state_code`,
s.`state_name`,
IF(state_id IN
(SELECT d2s.state_id
FROM drove_to_states d2s
WHERE driver_id = '%u'
), 1, null)
`selected`
FROM `states` s,
ORDER BY `state_name` ASC;

Using PHP's sprintf command, we can create a select field using this query:

<?php
[...]
$driver_id = 1;
define("QUERY", (SEE ABOVE) );
define("OPTION",'<option value="%s"%s>%s</option>');
$query = mysql_query(sprintf(QUERY, $driver_id), $connect);
echo '<select>';
while(list($code,$state,$selected) = mysql_fetch_row($query))
{
$selected = is_null($selected) ? null : ' selected';
echo sprintf(OPTION, $code, $selected, $state);
}
echo '</select>';
[...]
?>

Hope this helps anyone.

If anyone has a better way of writing this, please post.

Posted by Martin Sarfy on August 14, 2007


SELECT INTO OUTFILE creates world-writable files. To avoid this security risk, you can create new
subdirectory with +x rights for mysql and your user only (e.g. using chown me:mysql restricted_dir, chmod 770
restricted_dir), and then save the file into this directory. This way only you and mysql process can modify the
file.

Posted by Dan Bogdan on October 27, 2007


If you want to copy a file from the server in other location you can use
select load_file('source_file') into OUTFILE 'target_file'
Security issue on windows ... you can copy any file from any folder even if you don't have access to that file
to an convenient folder where you have access !!

Posted by Drazen Djurisic on November 13, 2007


If you need names from second table for more then 1 columns in first table.
Select
table1.id,
table1.konto,
table2.name as name1,
table1.konto1,
table2_2.name as name2,
table1.konto3,
table2_3.naziv as name3,
from table1
left join table2 on (table1.konto=table2.id)
left join table2 as table2_2 on (table1.konto2=table2_2.id)
left join table2 as table2_3 on (table1.konto3=table2_3.id)

Posted by Rich Altmaier on February 16, 2008


As a variant on the random row selection question, I had the goal of reading out a limited set of rows, always in
the same order, but starting at a different point in the sequence each time (like Facebook short list of
members):
e.g. given records a, b, c, d, e, f
I want random selections of triplets such as:
b, c, d
c, d, e
f, a, b --> note I want wraparound!

The prior postings on random rows selections have shown:


SELECT * FROM foo ORDER BY count*RAND() LIMIT 5;
This will yield the 5 random rows, but not in the same record ordering.

To preserve order, including a wraparound,


we must UNION a pair of queries.
For e.g. to get 3 rows from a table of $counted rows,
where we have selected $start, which happens to be within
3 of the end, we wrap as:
(SELECT * FROM `Ordering` ORDER BY something LIMIT $start, 1) UNION
(SELECT * FROM `Ordering` ORDER BY something LIMIT 0, 2)

suppose the table has 6 rows, and we decide


randomly to start with row 6, then concretely:
(SELECT * FROM `Ordering` ORDER BY something LIMIT 5, 1) UNION
(SELECT * FROM `Ordering` ORDER BY something LIMIT 0, 2)

Posted by engin karahan on February 17, 2008


As a variant on the random row selection question, I had the goal of reading out a limited set of rows, always in
the same order, but starting at a different point in the sequence each time (like Facebook short list of
members):
e.g. given records a, b, c, d, e, f
I want random selections of triplets such as:
b, c, d
c, d, e
f, a, b --> note I want wraparound!

The prior postings on random rows selections have shown:


SELECT * FROM foo ORDER BY count*RAND() LIMIT 5;
This will yield the 5 random rows, but not in the same record ordering.

To preserve order, including a wraparound,


we must UNION a pair of queries.
For e.g. to get 3 rows from a table of $counted rows,
where we have selected $start, which happens to be within
3 of the end, we wrap as:

(SELECT * FROM `Ordering` ORDER BY something LIMIT $start, 1) UNION


(SELECT * FROM `Ordering` ORDER BY something LIMIT 0, 2)

suppose the table has 6 rows, and we decide


randomly to start with row 6, then concretely:
(SELECT * FROM `Ordering` ORDER BY something LIMIT 5, 1) UNION
(SELECT * FROM `Ordering` ORDER BY something LIMIT 0, 2)

Posted by Michael Yakobi on March 6, 2008


Rotating rows to columns - crosstab pivoted queries
Having the following tables where Attributes.objId refers to Objects.id:

| Objects Attributes
+----+------+------+ +-------+-----+-------+
| id | type | name | | objId | key | value |
+====+======+======+ +=======+=====+=======+
| 1 | T1 | O1 | | 1 | K1 | V1 |
| 2 | T2 | O2 | | 1 | K2 | V2 |
| 3 | T1 | O3 | | 2 | K3 | V3 |
| 4 | T2 | O4 | | 2 | K4 | V4 |
| | 2 | K5 | V5 |
| | 3 | K1 | V6 |
| | 3 | K2 | V7 |
The common approach for selecting the attributes of each object into a single result-row per object is to join
Objects with Attributes multiple times. However, not only such SELECT can grow very big and ugly, with large
tables it becomes very slow.
This could be dealt with using group-by functions, so to select all the objects of type T1, use the following SQL:
| SELECT
| o.id,
| o.name,
| MAX(IF(a.key='K1', a.value, null)) as K1,
| MAX(IF(a.key='K2', a.value, null)) as K2
| FROM
| Objects o,
| Attributes a
| WHERE
| o.id = a.objid and
| o.type = 'T1'
| GROUP BY
| a.id
The result will be:

+----+------+----+----+
| id | name | K1 | K2 |
+====+======+====+====+
| 1 | O1 | V1 | V2 |
| 3 | O3 | V6 | V7 |

Posted by Wiebe Cazemier on March 25, 2008


For those who don't fully understand the concept of joins, I wrote an article which might help.

http://www.halfgaar.net/sql-joins-are-easy

Posted by Sam on April 8, 2008


I just spent a few hours figuring this one out and there doesn't seem to be much info online about it so I thought
I'd share.

You should use the following syntax to create a CSV file in the format expected by Microsoft Excel:

... INTO OUTFILE '/temp.csv' FIELDS ESCAPED BY '""' TERMINATED BY ',' ENCLOSED BY '"' LINES
TERMINATED BY '\r\n';

However fields with carriage returns may break the CSV as MySQL will automatically close a field when the \r\n
line break is found. To work around this, replace all \r\n breaks with \n. The field does not close on \n breaks
and it will be read into a single cell in Excel. You can do this in the same SQL statement, for example:

SELECT REPLACE(field_with_line_breaks, '\r\n', '\n') FROM table INTO OUTFILE '/temp.csv' FIELDS
ESCAPED BY '""' TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n';

I also found that null values could break the CSV. These can be handled in a similar way:

SELECT IFNULL(possible_null_field, "") FROM table INTO OUTFILE '/temp.csv' FIELDS ESCAPED BY '""'
TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\r\n';

Note: this replaces NULL values with an empty string which is technically not the same thing but it will give you
an empty cell in Excel instead of breaking the CSV structure and shifting the following cells to the left.

Posted by Paris Alex on October 16, 2009


To create a SELECT statement that categorize and label its result set according to special rules, try this...

SELECT 'cheap' AS priceCat, productName productCount FROM MyProducts WHERE price < 1000
UNION
SELECT 'moderate' AS priceCat, productName FROM MyProducts WHERE price >= 1000 AND price <2000
UNION
SELECT 'expensive' AS priceCat, productName FROM MyProducts WHERE price >= 2000

It essentially returns a two column result set. The first column contains the word 'cheap', 'moderate' or
'expensive' depending on the price of the product. The second column is the product name. This query can
easily be modified to return a count of number of products categorized by the price range:

SELECT 'cheap' AS priceCat, COUNT(*) productCount FROM MyProducts WHERE price < 1000
UNION
SELECT 'moderate' AS priceCat, COUNT(*) FROM MyProducts WHERE price >= 1000 AND price <2000
UNION
SELECT 'expensive' AS priceCat, COUNT(*) FROM MyProducts WHERE price >= 2000

It may sound like an obvious thing the an experienced SQL guy, but I think this tip will be useful to a beginner.
Hope this tip helps a SQL developer soon! ;-)

Posted by Joseph Triplett on October 16, 2009


to pass the output of a SELECT into a variable array for further processing (PHP), do the following:

$array = ("SELECT ID, post_title, FROM Posts", ARRAY_A);

Notice the "ARRAY_A" declaration at the end of the variable assignment.

I have had issues passing SQL statements into arrays, when the "ARRAY_A" declaration is not made.

Posted by Yury Ramanouski on November 13, 2009


# To select a random row of the table `tbl`
# I call the following procedure:

CREATE PROCEDURE select_rnd()


BEGIN
START TRANSACTION;
SELECT FLOOR(RAND() * COUNT(*)) INTO @rnd FROM tbl;
PREPARE stmt FROM 'SELECT * FROM tbl LIMIT ?, 1';
EXECUTE stmt USING @rnd;
COMMIT;
END;

Posted by Peter Colclough on November 26, 2009


A really good speedup for those using 'Group By'. This is reported to MySql who are looking atr it, but can
halve the speed of your query.

If you have a query that looks like:

Select col1, col2, col3


From tab1, tab2 ...
Group by col1, col2

You can add the following:


Group By col1, col2 WITH ROLLUP
Having (col1 IS NOT NULL) and (Col2 is not NUll)

This totals the 'groupings' but then removes those rows from the query. At the moment it is believed that an
optimisation was performed for the 'WITH ROLLUP' that didn't make it into the main optimisation...

HTH

Posted by Jon Webb on December 7, 2009


Ordering the Order By...
SELECT country,population FROM places ORDER BY country='UK' DESC, country ASC
This gives:
UK
Agola
Belgium
etc

Posted by Michael Ash on December 17, 2009


Several users asked about including headers, i.e., column names or variable names, in the "INTO OUTFILE"
syntax.

One approach is to use the "--column-names" option in the mysql invocation:

mysql --column-names -e 'SELECT * FROM mysql.user' > test.dat

(This creates a tab-delimited file test.dat with column names in the first row followed by the query results.)

Posted by Elliot Greene on June 4, 2010


I discovered a well placed parentheses can make a difference in output. This Query search at least three
columns for data like the $query variable.

Example 1: (This doesn't work)

$query = "Whatever text";

$sql2 = "SELECT * FROM $tbl_name WHERE CompanyName LIKE '%". $query ."%' OR description LIKE '%".
$query ."%' OR KeywordTags LIKE '%". $query ."%' AND Active='yes' AND State=Florida ";

Example 2: (Works for Me)


Notice the parentheses enclosing the "WHERE" section of the query separating it from the final "AND" Section.

$sql2 = "SELECT * FROM $tbl_name WHERE (CompanyName LIKE '%". $query ."%' OR description LIKE '%".
$query ."%' OR KeywordTags LIKE '%". $query ."%' AND Active='yes') AND State=Florida ";

Regards,
Elliot
http://www.sioure.com

Posted by pablo uribe on January 10, 2011


You can use this example to look for uniques rows using distinct over a mix of fields. use concat .

para hacer un distinct de varias columnas se puede usar concat

SELECT distinct(concat(id_cliente,rut,fecha_cesion)), id_cliente,rut,fecha_cesion FROM `tmp_consolidado`


WHERE 1

www.puribe.cl

Posted by Sagi Rozen on January 25, 2011


In order to select random rows from a table don't use the ORDER BY RAND() clause.
You can get a much better performing query if you use the RAND() function at the WHERE clause only. This
query will not result in file sort and will stop as soon as it get to the limit.
See http://www.rndblog.com/how-to-select-random-rows-in-mysql/

Posted by erick ringot on March 31, 2011


RECURSION / RECURSIVE SELECT :

1) Let `task` be a MySql table containing at least 2 columns: id (primary key), pid (parent id - may be NULL) so
that the rows form a classic tree structure.

2) Suppose you want to extract the tree relative to a particular actual id (constituted by itself and all its spawns)
so that you need a recursive select which is unfortunately not implemented in MySql.

You can proceed by writing a recursive function as below.

CREATE PROCEDURE `TASKTREE`(tid INT UNSIGNED, flag BOOLEAN)


BEGIN
--
-- TASKTREE(id,flag)
-- recursive function, must be called with flag=FALSE
-- tid is the task (row) id
-- creation of a temporary table `tasktree`
-- containing the tree relative to tid
--
declare xid,xpid INT UNSIGNED;
declare tend BOOLEAN DEFAULT FALSE;
declare tcur CURSOR FOR SELECT id,pid FROM `task`
WHERE ((tid>0 AND pid=tid) OR (tid=0 AND pid IS NULL));
declare CONTINUE HANDLER FOR NOT FOUND SET tend=TRUE;
--
-- external call : flag MUST be FALSE
-- -> creation of the temporary table `tasktree`
--
IF (NOT flag) THEN
DROP TEMPORARY TABLE IF EXISTS `tasktree`;
CREATE TEMPORARY TABLE `tasktree` (
`id` int(10) unsigned NOT NULL,
`pid` int(10) unsigned,
PRIMARY KEY (`id`));
SELECT pid FROM `task` WHERE id=tid INTO xpid;
INSERT `tasktree` SET id=tid,pid=xpid;
END IF;
--
-- recursive (internal) call: flag MUST be TRUE
--
OPEN tcur;
tscan:LOOP
FETCH tcur INTO xid,xpid;
IF tend THEN LEAVE tscan; END IF;
INSERT `tasktree` SET id=xid,pid=xpid;
CALL TASKTREE(xid,TRUE);
END LOOP;
CLOSE tcur;
END

-----------------
Note: Don't omit to set the global variable max_sp_recursion_depth to an adequate positive value (for instance
in the file 'my.ini').

Posted by Charles Peterson on February 22, 2012


Reply to Post by Heywood on March 11 2005 2:04pm
QUOTE
When using the SELECT ... INTO OUTFILE syntax, use a UNION to add headers. Here's an example for CSV
output:
SELECT 'Fiscal Year','Location','Sales'
UNION
SELECT FY, Loc, Sales INTO OUTFILE 'salesreport.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM SalesTable;

This will add the text headers Fiscal Year, Location and Sales to your fields. Only caveat is with an ORDER BY
statement, if you don't want your headers sorted along with your data you need to enclose it in parenthesis:

SELECT 'Fiscal Year','Location','Sales'


UNION
{SELECT FY, Loc, Sales INTO OUTFILE 'salesreport.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM SalesTable
ORDER BY Sales DESC);

END QUOTE...

Here is a more dynamic option for adding column_names to the top of output...

SELECT group_concat( column_name


SEPARATOR "," )
FROM information_schema.columns
WHERE table_name = 'SalesTable'
GROUP BY table_name
UNION
{SELECT * INTO OUTFILE 'salesreport.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
FROM SalesTable
ORDER BY Sales DESC);

Posted by Roland Giesler on June 23, 2012


In an effort to automate the exporting of data for a larger number of tables to .csv file by using SELECT ... INTO
OUTFILE, I have created a stored procedure to facilitate this. It's somewhat bulky, but please refer
to http://lifeboysays.wordpress.com/2012/06/23/mysql-how-to-export-data-to-csv-with-column-headers/ if you
have need for this.

Posted by Richard Pecker on May 19, 2016


This may help with figuring out certain syntax related things

SELECT Place, count(*) FROM Testing WHERE SUBSTRING(Place,2,1) IN ('c', 'u','s') GROUP BY Place
HAVING count(*)>=2 ORDER BY count(*)asc, Place DESC;

SELECT CONCAT(employer.companyname, ', ', employer.division ,', ', city, ', ', statecode, ' ', zipcode) AS
"Employer Info"
FROM employer, interview
WHERE employer.companyname=interview.companyname and
employer.division=interview.division
and listing='y'
ORDER BY zipcode ASC, employer.companyname DESC, employer.division ASC;

SELECT statecode FROM state WHERE statecode NOT IN (SELECT location FROM quarter);

SELECT SUBSTR(qtrCode, 1, 4) AS Year,


ROUND(AVG(minsal)) "Average Minimum Salary",
ROUND(MIN(minsal)) "Minimum Offered"
FROM quarter
GROUP BY Year;

SELECT Description, COUNT(location) as 'Number of Locations'


FROM STATE LEFT JOIN quarter ON state.statecode=quarter.location WHERE
INSTR(Description, 'or')
GROUP BY Description;

SELECT quarter.qtrCode "QTR", state.description "state", employer.companyname "company",


employer.division "division", interview.interviewdate "Date"
FROM quarter, employer, state, interview
WHERE employer.companyname = interview.companyname AND
employer.division= interview.division AND
quarter.qtrcode= interview.qtrcode AND
employer.statecode= quarter.location AND
employer.statecode= state.statecode;

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10 Subquery Syntax


13.2.10.1 The Subquery as Scalar Operand
13.2.10.2 Comparisons Using Subqueries
13.2.10.3 Subqueries with ANY, IN, or SOME
13.2.10.4 Subqueries with ALL
13.2.10.5 Row Subqueries
13.2.10.6 Subqueries with EXISTS or NOT EXISTS
13.2.10.7 Correlated Subqueries
13.2.10.8 Derived Tables (Subqueries in the FROM Clause)
13.2.10.9 Subquery Errors
13.2.10.10 Optimizing Subqueries
13.2.10.11 Rewriting Subqueries as Joins
A subquery is a SELECT statement within another statement.
All subquery forms and operations that the SQL standard requires are supported, as well as a few
features that are MySQL-specific.

Here is an example of a subquery:

SELECT * FROM t1 WHERE column1 =


(SELECT column1 FROM t2);
In this example, SELECT * FROM t1 ... is the outer query (or outer statement), and (SELECT
column1 FROM t2) is the subquery. We say that the subquery is nested within the outer query, and
in fact it is possible to nest subqueries within other subqueries, to a considerable depth. A subquery
must always appear within parentheses.
The main advantages of subqueries are:

They allow queries that


are structured so that it is possible to
isolate each part of a statement.
They provide alternative ways to
perform operations that would
otherwise require complex joins and
unions.


Many people find subqueries more
readable than complex joins or unions.
Indeed, it was the innovation of
subqueries that gave people the
original idea of calling the early
SQL Structured Query Language.
Here is an example statement that shows the major points about subquery syntax as specified by
the SQL standard and supported in MySQL:

DELETE FROM t1
WHERE s11 > ANY
(SELECT COUNT(*) /* no hint */
FROM t2
WHERE NOT EXISTS
(SELECT * FROM t3
WHERE ROW(5*t2.s1,77)=
(SELECT 50,11*s1 FROM t4
UNION SELECT 50,77 FROM
(SELECT * FROM t5) AS
t5)));
A subquery can return a scalar (a single value), a single row, a single column, or a table (one or
more rows of one or more columns). These are called scalar, column, row, and table subqueries.
Subqueries that return a particular kind of result often can be used only in certain contexts, as
described in the following sections.

There are few restrictions on the type of statements in which subqueries can be used. A subquery
can contain many of the keywords or clauses that an ordinarySELECT can contain: DISTINCT, GROUP
BY, ORDER BY, LIMIT, joins, index hints, UNION constructs, comments, functions, and so on.
A subquery's outer statement can be any one of: SELECT, INSERT, UPDATE, DELETE, SET, or DO.
In MySQL, you cannot modify a table and select from the same table in a subquery. This applies to
statements such as DELETE, INSERT, REPLACE, UPDATE, and (because subqueries can be used in
the SET clause) LOAD DATA INFILE.
For information about how the optimizer handles subqueries, see Section 8.2.2, Optimizing
Subqueries, Derived Tables, and View References. For a discussion of restrictions on subquery
use, including performance issues for certain forms of subquery syntax, see Section C.4,
Restrictions on Subqueries.

PREV HOME UP NEXT


User Comments
Posted by Are you mortal Then prepare to die. on January 5, 2005

Ever wanted to turn an AUTO_INCRIMENT primary key into one of those 'rolling ID' columns? i.e. the type
which changes back to ID = 1 when some other part of your (new) PK changes... Use a subquery!

Suppose you have this

TABLE t1...

AUTO_INCR_PK <-> X
1 <-> A
2 <-> A
3 <-> A
4 <-> B
5 <-> B
6 <-> B
7 <-> C
8 <-> C
9 <-> D

Try this cool sub-query!

CREATE TABLE t2 ( ID, X, PK(ID,X) );

INSERT INTO t2;


SELECT
a.X
a.AUTO_INCR_PK -
b.FIRST_KEY_IN_SERIES AS ID
FROM
t1
INNER JOIN
(
SELECT
X,
MIN(AUTO_INCR_PK) AS FIRST_KEY_IN_SERIES
FROM
t1
GROUP BY
X
) AS b
USING
(X)
;

Which gives you

TABLE t2 ...

ID <-> X
1 <-> A
2 <-> A
3 <-> A
1 <-> B
2 <-> B
3 <-> B
1 <-> C
2 <-> C
1 <-> D

Cool eh?

Posted by Tayfun Duran on September 10, 2005


If you can't use subquery, you can use this;

$sec1 = mysql_query("SELECT foto FROM profoto WHERE proje=$id");


if ($kyt1 = mysql_fetch_array($sec1)) {$dizi = $kyt1["foto"];} else {$dizi="0";}
while ($kyt1 = mysql_fetch_array($sec1)) {
$dizi = $dizi . "," . $kyt1["foto"];
}
mysql_free_result($sec1);
$sec = mysql_query("SELECT foto.id, foto.dosya, foto.baslik FROM foto WHERE id NOT IN (" . $dizi . ") LIMIT
$baslangic, $sayfalama");

First, you create a selection and then you use it in your real selection. This is a kind of subquery :)

Posted by Svavar Lthersson on June 4, 2006


This order of things also works for count functions. For example:

SELECT *,(SELECT COUNT(*) FROM table2 WHERE table2.field1 = table1.id) AS count FROM table1
WHERE table1.field1 = 'value'

This command will enable you to count fields in table2 based on a column value in table1 and label the result
as "count". The value in table1.field1 can be any valid field type.

Posted by ch4dwick m. on May 21, 2007


Here's simple insert query I came up with that serves 3 functions in my PHP applications:
1.) retrieves data from the select query
2.) Inserts that row into another table (for record keeping purposes such as purchase orders from shopping
carts)
3.) validates the input (using mysql_affected_rows()) and will return 0 if the select failed and will not insert at all.

INSERT INTO table2 (field1, field2, field3, field4) (SELECT 'value1 from user input', field1, field2, field3 from
table1)

The 4 fields in table2 will be populated by the 4 fields (including the string) returned by the SELECT sub-query
respectively.

I know this MIGHT raise issues with speed of queries but it's better than writing long lines of PHP code that
does those 3 things - even with a framework! I can just use the mysql_affected_rows() after that query to see if
everything went fine.

NOTE: Make sure the number of fields in the SELECT query is EXACTLY the same number of fields you are
about to insert.

Posted by Andy Leon on June 23, 2009


It mentions here that you cannot select from and modify the same table as part of your subquery. There is a
workaround listed on the following page:

http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html

that shows you how to use a temporary table. But you can also create a View based on a table, use that for the
SELECT statement and then use the regular table name for the UPDATE / DELETE statement.

Posted by Christian Berrigan on March 14, 2010


Updating a table using a subquery. This uses an example of a table of people, and a separate table of votes
those people have received. After the votes table has been populated with new votes, the total vote count of
each of the people is calculated and updated with one query.

UPDATE people,
(SELECT count(*) as votecount, person_id
FROM votes GROUP BY person_id) as tally
SET people.votecount = tally.votecount
WHERE people.person_id = tally.person_id
Posted by Devang Modi on August 30, 2011
Combine queries for Insert and Select always obeys Innodb locking rules
if one of the source table is based on Innodb engine.
It is also possible that the INSERT activity applicable to TEMPORARY
table which is not InnoDB engine. It is also possible that in SELECT
section with INNODB, some other TEMPORARY Tables are used.
Devang Modi

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.1 The Subquery as Scalar Operand


In its simplest form, a subquery is a scalar subquery that returns a single value. A scalar subquery is
a simple operand, and you can use it almost anywhere a single column value or literal is legal, and
you can expect it to have those characteristics that all operands have: a data type, a length, an
indication that it can be NULL, and so on. For example:
CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);
The subquery in this SELECT returns a single value ('abcde') that has a data type of CHAR, a length
of 5, a character set and collation equal to the defaults in effect at CREATE TABLE time, and an
indication that the value in the column can be NULL. Nullability of the value selected by a scalar
subquery is not copied because if the subquery result is empty, the result is NULL. For the subquery
just shown, if t1 were empty, the result would be NULL even though s2 is NOT NULL.
There are a few contexts in which a scalar subquery cannot be used. If a statement permits only a
literal value, you cannot use a subquery. For example, LIMITrequires literal integer arguments,
and LOAD DATA INFILE requires a literal string file name. You cannot use subqueries to supply
these values.
When you see examples in the following sections that contain the rather spartan construct (SELECT
column1 FROM t1), imagine that your own code contains much more diverse and complex
constructions.
Suppose that we make two tables:

CREATE TABLE t1 (s1 INT);


INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (s1 INT);
INSERT INTO t2 VALUES (2);
Then perform a SELECT:
SELECT (SELECT s1 FROM t2) FROM t1;
The result is 2 because there is a row in t2 containing a column s1 that has a value of 2.
A scalar subquery can be part of an expression, but remember the parentheses, even if the
subquery is an operand that provides an argument for a function. For example:

SELECT UPPER((SELECT s1 FROM t1)) FROM t2;

PREV HOME UP NEXT

User Comments
Posted by mrfox on February 6, 2007

when the same subquery is used several times, mysql does not use this fact to optimize the query, so be
careful not to run into performance problems.

example:

SELECT
col0,
(SELECT col1 FROM table1 WHERE table1.id = table0.id),
(SELECT col2 FROM table1 WHERE table1.id = table0.id)
FROM
table0
WHERE ...

the join of table0 with table1 is executed once for EACH subquery, leading to very bad performance for this
kind of query.
Posted by Rami Jamleh on June 3, 2012

Oracle says that you can left join via scalar sub-queries
e.g
create table x (id int auto_increment primary key,name varchar(20),yid int);

create table y (id int auto_increment primary key,name varchar(20));

insert into x(name,yid) values('Alex',null),('Marvin',1),('Bob',null);


insert into y(name) values('GO'),('GOO'),('GOOO');

watch this now


select id,name,(select name from y where x.yid = y.id) from x;
which is equivalent to
select x.id,x.name,y.name
from x left join y on (x.yid = y.id);

and they say outer joins may have negative impact on performance

13.2.10.2 Comparisons Using Subqueries


The most common use of a subquery is in the form:

non_subquery_operand comparison_operator (subquery)


Where comparison_operator is one of these operators:
= > < >= <= <> != <=>
For example:

... WHERE 'a' = (SELECT column1 FROM t1)


MySQL also permits this construct:

non_subquery_operand LIKE (subquery)


At one time the only legal place for a subquery was on the right side of a comparison, and you might
still find some old DBMSs that insist on this.

Here is an example of a common-form subquery comparison that you cannot do with a join. It finds
all the rows in table t1 for which the column1 value is equal to a maximum value in table t2:
SELECT * FROM t1
WHERE column1 = (SELECT MAX(column2) FROM t2);
Here is another example, which again is impossible with a join because it involves aggregating for
one of the tables. It finds all rows in table t1 containing a value that occurs twice in a given column:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
For a comparison of the subquery to a scalar, the subquery must return a scalar. For a comparison
of the subquery to a row constructor, the subquery must be a row subquery that returns a row with
the same number of values as the row constructor. See Section 13.2.10.5, Row Subqueries.

PREV HOME UP NEXT

User Comments
Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.3 Subqueries with ANY, IN, or SOME


Syntax:

operand comparison_operator ANY (subquery)


operand IN (subquery)
operand comparison_operator SOME (subquery)
Where comparison_operator is one of these operators:
= > < >= <= <> !=
The ANY keyword, which must follow a comparison operator, means return TRUE if the comparison
is TRUE for ANY of the values in the column that the subquery returns. For example:
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
Suppose that there is a row in table t1 containing (10). The expression is TRUE if
table t2 contains (21,14,7) because there is a value 7 in t2 that is less than10. The expression
is FALSE if table t2 contains (20,10), or if table t2 is empty. The expression is unknown (that
is, NULL) if table t2 contains(NULL,NULL,NULL).
When used with a subquery, the word IN is an alias for = ANY. Thus, these two statements are the
same:
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);
IN and = ANY are not synonyms when used with an expression list. IN can take an expression list,
but = ANY cannot. See Section 12.3.2, Comparison Functions and Operators.
NOT IN is not an alias for <> ANY, but for <> ALL. See Section 13.2.10.4, Subqueries with ALL.
The word SOME is an alias for ANY. Thus, these two statements are the same:
SELECT s1 FROM t1 WHERE s1 <> ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);
Use of the word SOME is rare, but this example shows why it might be useful. To most people, the
English phrase a is not equal to any b means there is no b which is equal to a, but that is not what is
meant by the SQL syntax. The syntax means there is some b to which a is not equal. Using <>
SOME instead helps ensure that everyone understands the true meaning of the query.
PREV HOME UP NEXT

User Comments
Posted by anonymous on September 2, 2004

SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2); example:


if there is a row containing (10) in table t1, the expression is true if table t2 contains (20,10) because 10 is not
equal to one or more (i.e., some) of t2's values, namely the 20.

A NOT IN condition, otoh, would be false. NOT IN is always going to be at least as hard to satisfy (as <>
SOME) because to be true /all/ rows have to be non-equal.

Posted by sukasom chaiyakul on April 8, 2005

# table paper, contains the record of each research paper


CREATE TABLE paper
(
paperid INTEGER NOT NULL AUTO_INCREMENT,
title varchar(256) not null,
PRIMARY KEY(paperid)
)

# One paper can have many reviewing,


# table reviewing contains the reviewing records.
CREATE TABLE reviewing
(
reviewingid INTEGER NOT NULL AUTO_INCREMENT,
paperid INTEGER NOT NULL,
reviewerid INTEGER NOT NULL,
unique(paperid, reviewerid),
PRIMARY KEY(reviewingid),
FOREIGN KEY (paperid) REFERENCES paper (paperid),
FOREIGN KEY (reviewerid) REFERENCES reviewer (reviewerid)
);

#table score , each record contains the score of each reviewing and each questions
CREATE TABLE score
(
reviewingid integer ,
score integer,
FOREIGN KEY (reviewingid) REFERENCES reviewing (reviewingid)
);

#find all paperid that are not dont from reviewing


# Finish reviewing paper are paper that
# for each reviewing answer 9 QAs
# for paper there are three done reviewings.
# We want to find paper that are not done from reviewing.
SELECT paperid from paper
WHERE paperid not in
(
SELECT paperid FROM
(
SELECT paperid, COUNT(paperid) as numdonereviewing from
(
SELECT reviewing.paperid , COUNT(*) as numcheck from reviewing, score
where reviewing.reviewingid = score.reviewingid
GROUP by reviewing.reviewingid
) as temp1
WHERE numcheck = 9
GROUP by paperid
) AS temp2 WHERE numdonereviewing >= 3
);

Posted by Patrick Jackson on March 3, 2007

Using IN in a DELETE subquery is a handy way to remove orphans.

Suppose you want to create foreign keys on an existing table with orphans. If you try to ALTER TABLE to
create the foreign keys, get the dreaded:

error 1452 "cannot add or update a child row: foreign key constaint fails"

This is a good thing, because after implementing foreign keys you want your tables to be consistent, and not
contain orphans, so you must delete them beforehand.

Given tables 'child' and 'parent' where child.parent_id is a foreign key referencing parent.id, use the following to
clean up any orphans.

DELETE FROM child WHERE child.parent_id NOT IN (SELECT id FROM parent)

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.4 Subqueries with ALL


Syntax:

operand comparison_operator ALL (subquery)


The word ALL, which must follow a comparison operator, means return TRUE if the comparison
is TRUE for ALL of the values in the column that the subquery returns. For example:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
Suppose that there is a row in table t1 containing (10). The expression is TRUE if
table t2 contains (-5,0,+5) because 10 is greater than all three values in t2. The expression
is FALSE if table t2 contains (12,6,NULL,-100) because there is a single value 12 in table t2 that
is greater than 10. The expression is unknown(that is, NULL) if table t2 contains (0,NULL,1).
Finally, the expression is TRUE if table t2 is empty. So, the following expression is TRUE when
table t2 is empty:
SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);
But this expression is NULL when table t2 is empty:
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);
In addition, the following expression is NULL when table t2 is empty:
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);
In general, tables containing NULL values and empty tables are edge cases. When writing
subqueries, always consider whether you have taken those two possibilities into account.
NOT IN is an alias for <> ALL. Thus, these two statements are the same:
SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

PREV HOME UP NEXT

User Comments
Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

3.2.10.5 Row Subqueries


Scalar or column subqueries return a single value or a column of values. A row subquery is a
subquery variant that returns a single row and can thus return more than one column value. Legal
operators for row subquery comparisons are:
= > < >= <= <> != <=>
Here are two examples:

SELECT * FROM t1
WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);
SELECT * FROM t1
WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);
For both queries, if the table t2 contains a single row with id = 10, the subquery returns a single
row. If this row has col3 and col4 values equal to the col1and col2 values of any rows in t1,
the WHERE expression is TRUE and each query returns those t1 rows. If
the t2 row col3 and col4 values are not equal the col1 and col2 values of any t1 row, the
expression is FALSE and the query returns an empty result set. The expression is unknown (that
is, NULL) if the subquery produces no rows. An error occurs if the subquery produces multiple rows
because a row subquery can return at most one row.
For information about how each operator works for row comparisons, see Section 12.3.2,
Comparison Functions and Operators.
The expressions (1,2) and ROW(1,2) are sometimes called row constructors. The two are
equivalent. The row constructor and the row returned by the subquery must contain the same
number of values.
A row constructor is used for comparisons with subqueries that return two or more columns. When a
subquery returns a single column, this is regarded as a scalar value and not as a row, so a row
constructor cannot be used with a subquery that does not return at least two columns. Thus, the
following query fails with a syntax error:

SELECT * FROM t1 WHERE ROW(1) = (SELECT column1 FROM t2)


Row constructors are legal in other contexts. For example, the following two statements are
semantically equivalent (and are handled in the same way by the optimizer):

SELECT * FROM t1 WHERE (column1,column2) = (1,1);


SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
The following query answers the request, find all rows in table t1 that also exist in table t2:
SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3) IN
(SELECT column1,column2,column3 FROM t2);
For more information about the optimizer and row constructors, see Section 8.2.1.18, Row
Constructor Expression Optimization

PREV HOME UP NEXT

User Comments
Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.6 Subqueries with EXISTS or NOT EXISTS


If a subquery returns any rows at all, EXISTS subquery is TRUE, and NOT
EXISTS subquery is FALSE. For example:
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
Traditionally, an EXISTS subquery starts with SELECT *, but it could begin with SELECT
5 or SELECT column1 or anything at all. MySQL ignores the SELECT list in such a subquery, so it
makes no difference.
For the preceding example, if t2 contains any rows, even rows with nothing but NULL values,
the EXISTS condition is TRUE. This is actually an unlikely example because a [NOT]
EXISTS subquery almost always contains correlations. Here are some more realistic examples:
What kind of store is present in one or more cities?

SELECT DISTINCT store_type FROM stores


WHERE EXISTS (SELECT * FROM cities_stores
WHERE cities_stores.store_type = stores.store_type);
What kind of store is present in no cities?

SELECT DISTINCT store_type FROM stores


WHERE NOT EXISTS (SELECT * FROM cities_stores
WHERE cities_stores.store_type = stores.store_type);
What kind of store is present in all cities?

SELECT DISTINCT store_type FROM stores s1


WHERE NOT EXISTS (
SELECT * FROM cities WHERE NOT EXISTS (
SELECT * FROM cities_stores
WHERE cities_stores.city = cities.city
AND cities_stores.store_type = stores.store_type));
The last example is a double-nested NOT EXISTS query. That is, it has a NOT EXISTS clause within
a NOT EXISTS clause. Formally, it answers the question does a city exist with a store that is not
in Stores? But it is easier to say that a nested NOT EXISTS answers the question is x TRUE for
all y?

PREV HOME UP NEXT

User Comments
Posted by ersin yilmaz on February 24, 2004

Last example (using double negation) can be interpreted as follows:

Store 'si' is in all cities if and only if for this store we can not find a city cj such that 'si' does not exist.

so the second select statement SELECT * FROM cities WHERE NOT EXISTS is applied to detemine that.

best

Posted by Radu Borza on February 9, 2005

EXISTS function provides a simple way to find intersection between tables (INTERSECT operator from
relational model).

If we have table1 and table2, both having id and value columns, the intersection could be calculated like this:

SELECT * FROM table1 WHERE EXISTS(SELECT * FROM table2 WHERE table1.id=table2.id AND
table1.value=table2.value)

Posted by Aaron Chantrill on April 19, 2009

I'm coming from an MS SQL background (not my fault, honest) and would like to add that 'exists' does not
operate as I expected it to in interactive mode.

I expect to be able to do something like:

if exists(select 1 from users where username=@username) then


do something;
end if;

but in interactive mode, this produces a syntax error. Oddly enough, though, this does work in a stored
procedure.

Posted by Edgar Sandi on May 26, 2009

Well...

You'll must build your own "IF EXISTS(..." with a set


of SQL statments.

Its a challenge!

Cheers.

Posted by mike tsai on August 12, 2009


NOT EXISTS will always return false if table is empty.

For example:
CREATE TABLE states
(
state_id int auto_increment not null,
state_code char(2) not null,
state_name varchar(100) not null,
UNIQUE(state_code),
PRIMARY KEY(state_id)
);

mysql> select 100 from states where not exists (select 1 from states where state_id=1);
Empty set (0.00 sec)

Posted by Scott Rosenberg on October 22, 2009

I also come from an MSSQL background (also not my fault as I like to work), and found that this works in place
of "IF EXISTS() THEN":

DECLARE v_user INTEGER DEFAULT (SELECT `user` FROM user_privacy WHERE `user` = p_user);

IF v_user IS NOT NULL THEN


-- do whatever
END IF;

I won't speak to the efficiency of that, but there it is. (I wouldn't store VARCHARs or TEXTs, etc. that way, for
no reason).

It can also be written with the SELECT inline with the IF statement:

IF (SELECT `user` FROM user_privacy WHERE `user` = p_user) IS NOT NULL THEN
-- do whatever
END IF;

.. but I'm in the habit of sticking things like that into vars for re-use in longer SPs.

Posted by mojgan kavehei on March 10, 2014

Hi,
I wonder if anyone tested the last example "What kind of store is present in all cities?"
it did not work for me, but instead i used this query in below ..

select count(stype), stype , city from cities_stores S group by S.stype having count(stype) = ( select
count(distinct D.city) from cities_stores D )

any thought?

Thanks,

Posted by sunghun kim on June 27, 2017

Do not use "exists subquery" with "loose index scan" in different column.
Because you do not have access to the entire index, there may be problems when "exists subquery" is
performed based on another column than "group by".

example)
CREATE TABLE `g1` (
`seq` int(11) NOT NULL,
`key1` bigint(20) DEFAULT NULL,
PRIMARY KEY (`seq`),
KEY `idx1` (`key1`)
);
CREATE TABLE `g2` (
`seq` int(11) NOT NULL,
`key2` bigint(20) DEFAULT NULL,
PRIMARY KEY (`seq`),
KEY `idx1` (`key2`)
);

mysql> select * from g1;

+-----+------+
| seq | key1 |
+-----+------+
| 1 | 10 |
| 2 | 20 |
| 3 | 30 |
| 4 | 30 |
... (There are enough rows to do a "loose index scan")

mysql> select * from g2;

+-----+
| seq |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
+-----+

mysql> select key1 from g1 where exists (select 1 from g2 where g1.seq=g2.seq) group by g1.key1;

+------+
| key1 |
+------+
| 10 |
| 20 |
| 30 |
+------+

mysql> delete from g2 where seq = 3;


mysql> select key1 from g1 where exists (select 1 from g2 where g1.seq=g2.seq) group by g1.key1;

+------+
| key1 |
+------+
| 10 |
| 20 |
+------+

When using "loose index scan", only the seq = 3 which is located first among the items with key1 = 30.
Therefore, even if seq = 4 exists in "exists subquery", it returns there is no item with key1 of 30.
+------+-----+
| key1 | seq |
+------+-----+
| 10 | 1 |
| 20 | 2 |
| 30 | 3 |
| 30 | 4 |
...

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.7 Correlated Subqueries


A correlated subquery is a subquery that contains a reference to a table that also appears in the
outer query. For example:
SELECT * FROM t1
WHERE column1 = ANY (SELECT column1 FROM t2
WHERE t2.column2 = t1.column2);
Notice that the subquery contains a reference to a column of t1, even though the
subquery's FROM clause does not mention a table t1. So, MySQL looks outside the subquery, and
finds t1 in the outer query.
Suppose that table t1 contains a row where column1 = 5 and column2 = 6; meanwhile,
table t2 contains a row where column1 = 5 and column2 = 7. The simple expression ... WHERE
column1 = ANY (SELECT column1 FROM t2) would be TRUE, but in this example,
the WHERE clause within the subquery isFALSE (because (5,6) is not equal to (5,7)), so the
expression as a whole is FALSE.
Scoping rule: MySQL evaluates from inside to outside. For example:
SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));
In this statement, x.column2 must be a column in table t2 because SELECT column1 FROM t2
AS x ... renames t2. It is not a column in table t1 becauseSELECT column1 FROM t1 ... is an
outer query that is farther out.
For subqueries in HAVING or ORDER BY clauses, MySQL also looks for column names in the outer
select list.
For certain cases, a correlated subquery is optimized. For example:

val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)


Otherwise, they are inefficient and likely to be slow. Rewriting the query as a join might improve
performance.

Aggregate functions in correlated subqueries may contain outer references, provided the function
contains nothing but outer references, and provided the function is not contained in another function
or expression.

PREV HOME UP NEXT


User Comments
Posted by Are you mortal Then prepare to die. on November 24, 2004

Another example of when a subquery is optimized is when using a subquery based on a multipart primary key
to 'join' the two tables.

For example

[sql]
DELETE FROM t1 WHERE ROW(c1,c2) IN (
SELECT c1, c2 FROM t2
);
[/sql]

You could easily select the above 'join' using a 'where t1.c1=t2.c1 and t1.c2=t2.c2', but a delete statement
won't know what to do (and fails) over the joined tables.

Posted by Ryan Findley on January 11, 2006

Note that according to bug #9090 ( http://bugs.mysql.com/bug.php?id=9090 ) it appears that ALL subqueries
will be executed as correlated subqueries until version 5.2 or 6.0, when the optimizer may gain the ability to
correctly execute uncorrelated subqueries.

Posted by Stephen Dewey on August 18, 2006

Ryan Findley is good to point out the bug report, but as far as I can tell it is not true that MySQL rewrites ALL
subqueries as correlated subqueries. Rather, the problem that the bug report identifies is that the MySQL
optimizer does that to subqueries that test an IN statement. This is listed as one of the current limitations of
MySQL's subquery support here (third item down, "Subquery optimization for IN..."):

http://dev.mysql.com/doc/refman/5.0/en/subquery-restrictions.html

So if you are writing a subquery that does not use IN, I think that you will be able to keep it uncorrelated.
However, I have not tested this.

Posted by Tobias F on April 12, 2007

If you have a slow 'correlated' subquery with IN, you can optimize it with a join to get around the bug described
by Ryan and Stephen. After the optimization the execution time is no longer O(MN).

the queries are made up for this example.


original query (execution time 4 sec):
SELECT * FROM employee WHERE room = 15 OR
room IN (
SELECT room FROM assistant WHERE building = 11
)

optimized query (execution time 0,004 sec):


SELECT e1.* FROM employee e1
INNER JOIN (
SELECT room FROM assistant WHERE building = 11
) ea ON e1.room = ea.room
UNION SELECT * FROM employee WHERE room = 15

if you have a simple query like


SELECT * FROM employee WHERE room IN (
SELECT room FROM assistant WHERE building = 11
)
just leave the UNION operator

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.8 Derived Tables (Subqueries in the FROM Clause)


A derived table is a subquery in a SELECT statement FROM clause:
SELECT ... FROM (subquery) [AS] tbl_name ...
The [AS] tbl_name clause is mandatory because every table in a FROM clause must have a name.
Any columns in the subquery select list must have unique names.
For the sake of illustration, assume that you have this table:

CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);


Here is how to use a subquery in the FROM clause, using the example table:
INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
WHERE sb1 > 1;
Result: 2, '2', 4.0.
Here is another example: Suppose that you want to know the average of a set of sums for a grouped
table. This does not work:

SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;


However, this query provides the desired information:

SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;
Notice that the column name used within the subquery (sum_column1) is recognized in the outer
query.
Derived tables can return a scalar, column, row, or table.

Derived tables cannot be correlated subqueries, or contain outer references or references to other
tables of the same SELECT.
The optimizer determines information about derived tables in such a way that materialization of them
does not occur for EXPLAIN. See Section 8.2.2.3, Optimizing Derived Tables and View
References.
It is possible under certain circumstances that using EXPLAIN SELECT will modify table data. This
can occur if the outer query accesses any tables and an inner query invokes a stored function that
changes one or more rows of a table. Suppose that there are two tables t1 and t2 in database d1,
and a stored function f1that modifies t2, created as shown here:
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (c1 INT);
CREATE TABLE t2 (c1 INT);
CREATE FUNCTION f1(p1 INT) RETURNS INT
BEGIN
INSERT INTO t2 VALUES (p1);
RETURN p1;
END;
Referencing the function directly in an EXPLAIN SELECT has no effect on t2, as shown here:
mysql> SELECT * FROM t2;
Empty set (0.02 sec)

mysql> EXPLAIN SELECT f1(5)\G


*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
1 row in set (0.01 sec)

mysql> SELECT * FROM t2;


Empty set (0.01 sec)
This is because the SELECT statement did not reference any tables, as can be seen in
the table and Extra columns of the output. This is also true of the following nested SELECT:
mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;


+-------+------+------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------+
| Note | 1249 | Select 2 was reduced during optimization |
+-------+------+------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM t2;


Empty set (0.00 sec)
However, if the outer SELECT references any tables, the optimizer executes the statement in the
subquery as well:
mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
partitions: NULL
type: system
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: a1
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
3 rows in set (0.00 sec)

mysql> SELECT * FROM t2;


+------+
| c1 |
+------+
| 5 |
+------+
1 row in set (0.00 sec)
This also means that an EXPLAIN SELECT statement such as the one shown here may take a long
time to execute because the BENCHMARK() function is executed once for each row in t1:
EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));

PREV HOME UP NEXT

User Comments
Sign UpLoginYou must be logged in to post a comment.
2017, Oracle Corporation and/or its affiliates

13.2.10.9 Subquery Errors


There are some errors that apply only to subqueries. This section describes them.

Unsupported subquery syntax:

ERROR 1235 (ER_NOT_SUPPORTED_YET)


SQLSTATE = 42000
Message = "This version of MySQL doesn't yet support
'LIMIT & IN/ALL/ANY/SOME subquery'"
This means that MySQL does not support statements of the following form:

SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)


Incorrect number of columns from subquery:

ERROR 1241 (ER_OPERAND_COL)


SQLSTATE = 21000
Message = "Operand should contain 1 column(s)"
This error occurs in cases like this:

SELECT (SELECT column1, column2 FROM t2) FROM t1;


You may use a subquery that returns multiple columns, if the purpose is row comparison. In
other contexts, the subquery must be a scalar operand. SeeSection 13.2.10.5, Row
Subqueries.
Incorrect number of rows from subquery:

ERROR 1242 (ER_SUBSELECT_NO_1_ROW)


SQLSTATE = 21000
Message = "Subquery returns more than 1 row"
This error occurs for statements where the subquery must return at most one row but returns
multiple rows. Consider the following example:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);


If SELECT column1 FROM t2 returns just one row, the previous query will work. If the
subquery returns more than one row, error 1242 will occur. In that case, the query should be
rewritten as:
SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);
Incorrectly used table in subquery:

Error 1093 (ER_UPDATE_TABLE_USED)


SQLSTATE = HY000
Message = "You can't specify target table 'x'
for update in FROM clause"
This error occurs in cases such as the following, which attempts to modify a table and select
from the same table in the subquery:

UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);


You can use a subquery for assignment within an UPDATE statement because subqueries are
legal in UPDATE and DELETE statements as well as in SELECTstatements. However, you cannot
use the same table (in this case, table t1) for both the subquery FROM clause and the update
target.
For transactional storage engines, the failure of a subquery causes the entire statement to fail. For
nontransactional storage engines, data modifications made before the error was encountered are
preserved.

PREV HOME UP NEXT

User Comments
Posted by Guy Gordon on November 25, 2006

Wanting to copy a longtext field from one record to another, I first tried:
Update table set list=(select list from t1 where recno=230) where recno=169
I expected this to select one value from record 230 and copy it into record 169. Instead it fails with Error 1093.
Even though this is a single scalar value, MySQL will not let you use the same table in both the update and
from parts.

I got the desired result using a temp variable and two queries:
Set @Guy = (select list from t1 where recno=230);
Update t1 set list=@Guy where recno=169

Note that the semicolon separates the two statements (in phpMyAdmin). Since the temp variable is connection
specific, the two queries must be run together.

Posted by Frank Heikens on February 23, 2008

There is a workaround for the use of LIMIT in a subquery, just use a variable (seperate query, execute this one
first):
SET @i = 0;

And then the select-query with the subquery including the LIMIT:
SELECT
*
FROM
my_table
WHERE
id_my_other_table IN(
SELECT id FROM my_other_table
WHERE
( @i := ( @i +1 ) ) <= 10
);

In this case there's a limit of 10 results in the subquery.

Tested in version 5.0.45

Posted by Cleo - on November 1, 2009

For a workaround with on the update query look at

When I try to run update query for my table "comments", MySQL returns the #1093 - You can't specify target
table 'comments' for update in FROM clause message. My contrived table structure and update query are as
follow:

CREATE TABLE comments(id int primary key, phrase text, uid int);

INSERT INTO comments VALUES(1, 'admin user comments',1), (2, 'HR User Comments',2), (3, 'RH User
Comments',2);

UPDATE comments SET phrase =


(SELECT phrase FROM comments WHERE uid=2 AND id=2)
WHERE id = 3;

Is there any easy way to work around the #1093 - You can't specify target table 'comments' for update in
FROM clause error?

Answer No: 156


Actually, your above update query seems illegal as per SQL standard. MySQL does not allow to UPDATE or
DELETE a table's data if you're simultaneously reading that same data with a subquery. Because you are
doing so that is why MySQL tersely said its such error message. Therefore, you will have to rewrite your above
update query.

Since MySQL materializes sub queries in the FROM Clause as temporary tables, wrapping the subquery into
another inner subquery in the FROM Clause causes it to be executed and stored into a temporary table, then
referenced implicitly in the outer subquery. So, the update query will succeed by rewriting it like below:

UPDATE comments SET phrase =


( SELECT phrase FROM ( SELECT * FROM comments) AS c1 WHERE c1.uid=2 AND c1.id=2 ) WHERE id
=3;

FROM:
http://www.mysqlfaqs.net/mysql-faqs/Errors/1093-You-can-not-specify-target-table-comments-for-update-in-
FROM-clause

Posted by Usman Mahmood on September 30, 2010

Well, I'd a scenario where I'd a table with one BLOB field to store images. I'd about 3000 records in the
database. For first, we needed a default image for all these 3000 records. So, I inserted an image into the table
using phpmyadmin for the first record. Now, what I wanted to do was to copy this image from first record and
update (paste) all the 2999 records instead of uploading the image for each record. I tried hard to find a
solution. Asked many friends, but none of them had the answer. Eventually, I'd to create a copy of that table
and then run the following query :
update table1 set image = (select image from table2 where id=1)

This worked for me ! This is the fastest and easiest way to do it. If anyone else has a better way to do it, do let
me know.

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

13.2.10.11 Rewriting Subqueries as Joins


Sometimes there are other ways to test membership in a set of values than by using a subquery.
Also, on some occasions, it is not only possible to rewrite a query without a subquery, but it can be
more efficient to make use of some of these techniques rather than to use subqueries. One of these
is the IN()construct:
For example, this query:

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);


Can be rewritten as:

SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;


The queries:

SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);


SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);
Can be rewritten as:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table1.id=table2.id
WHERE table2.id IS NULL;
A LEFT [OUTER] JOIN can be faster than an equivalent subquery because the server might be
able to optimize it bettera fact that is not specific to MySQL Server alone. Prior to SQL-92, outer
joins did not exist, so subqueries were the only way to do certain things. Today, MySQL Server and
many other modern database systems offer a wide range of outer join types.
MySQL Server supports multiple-table DELETE statements that can be used to efficiently delete rows
based on information from one table or even from many tables at the same time. Multiple-
table UPDATE statements are also supported. See Section 13.2.2, DELETE Syntax,
and Section 13.2.11, UPDATE Syntax.

PREV HOME UP NEXT

User Comments
Posted by on January 17, 2004

Here is a rough description of one more method to do something equivalent to a subquery in a DELETE for
older versions of MySQL that do not support it. It only works for the case where there is a unique key on the
table. It requires making a temporary table and a temporary column on the table from which you wish to delete.
However it's all done in a sequence of SQL commands which is a little cleaner than the other methods.

Let's say the table from which you want to delete is "origtable". First create a temporary table with the same
structure as origtable (though without autoincrement columns), let's call it "temptable". Then fill it with the rows
of origtable that you wish to delete, for example:

INSERT INTO temptable SELECT ... FROM origtable WHERE ...

It's important that all results from the SELECT statement should have unique keys that are present in origtable,
in other words don't do something weird here like taking the cosine of the primary key. Next create a temporary
new column on origtable to designate which rows you intend to delete, and default this to 1:

ALTER TABLE origtable ADD `tempdeleteflag` int(12) NOT NULL default 1;

Next set tempdeleteflag to 0 for the rows that are present in temptable using REPLACE:

REPLACE origtable SELECT id, col1, col2, ..., colN, 0 FROM temptable;

Now tempdeleteflag should be set to 0 for rows you intended to keep or 1 for rows you inteded to delete, so:
DELETE FROM origtable WHERE tempdeleteflag = 1;

Finally clean up the temporary column:

ALTER TABLE origtable DROP tempdeleteflag;

If you created temptable using TEMPORARY it will go away when your session ends, otherwise drop it now.

As an alternative, you can do the logic the other way here:


default tempdeleteflag to 0, select rows you wish to delete into temptable, then set tempdeleteflag to 1 on rows
common to the two tables.

Posted by David Buzz on May 6, 2004

In reference to the first user comment on this page, I have 2 comments:


1) GREAT CONCEPT - I use it a lot now!
2) You actually made a typo, and if done exactly as you describe you will delete all the rows you wanted to
keep, and keep those you wanted to delete!.

You say to create a "temptable" and fill it with the rows you wish to delete... this should say "fill it with the rows
you wish to KEEP", alternatively the following SQL DELETE statement should be inverted so that you delete
those "where tempdeleteflag = 0";

Why? Well, you are defaulting the origtable to have a value of 1 in the tempdeleteflag column, and then setting
it to 0 for those that you want to DELETE. (0 means delete) obviously then the DELETE statement should
delete those that are 0. Alternatively, if you set it to 0 for those that you want to KEEP (0 means keep, then 1
means DELETE) then you DELETE those that are set to 1. Be very careful to get it right.

Posted by anonymous on August 27, 2004

About the above comments, if one can

INSERT INTO temptable SELECT ... FROM origtable WHERE ...

to choose exactly what to DELETE, why not simply

DELETE FROM origtable WHERE <same where clause as above>

and be done with it?

Posted by Are you mortal Then prepare to die. on November 24, 2004

About the last comment, presumably the select involves a join which a straight delete could not.

A final method is to use a left join to remove those rows you dont want from the results set and insert that
results set into a new table and swap that table witht the table you wanted to delete from...

I hate this method so much I am hear reading how to do this....

DELETE FROM
WHERE
ROW(SUNID1,SUNID2) IN (
SELECT
SUNID1,SUNID2
FROM
toExcludeFromInterfaceBreakdown
);

Yay for subselects!

Sign UpLoginYou must be logged in to post a comment.

2017, Oracle Corporation and/or its affiliates

3.2.11 UPDATE Syntax


UPDATE is a DML statement that modifies rows in a table.
Single-table syntax:

UPDATE [LOW_PRIORITY] [IGNORE]


table_reference
SET assignment_list
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]

value:
{expr | DEFAULT}

assignment:
col_name = value

assignment_list:
assignment [, assignment] ...
Multiple-table syntax:

UPDATE [LOW_PRIORITY] [IGNORE]


table_references
SET assignment_list
[WHERE where_condition]
For the single-table syntax, the UPDATE statement updates columns of existing rows in the named
table with new values. The SET clause indicates which columns to modify and the values they should
be given. Each value can be given as an expression, or the keyword DEFAULT to set a column
explicitly to its default value. The WHERE clause, if given, specifies the conditions that identify which
rows to update. With no WHERE clause, all rows are updated. If the ORDER BYclause is specified, the
rows are updated in the order that is specified. The LIMIT clause places a limit on the number of
rows that can be updated.
For the multiple-table syntax, UPDATE updates rows in each table named in table_references that
satisfy the conditions. Each matching row is updated once, even if it matches the conditions multiple
times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.
For partitioned tables, both the single-single and multiple-table forms of this statement support the
use of a PARTITION option as part of a table reference. This option takes a list of one or more
partitions or subpartitions (or both). Only the partitions (or subpartitions) listed are checked for
matches, and a row that is not in any of these partitions or subpartitions is not updated, whether it
satisfies the where_condition or not.
Note
Unlike the case when using PARTITION with an INSERT or REPLACE statement, an otherwise
valid UPDATE ... PARTITION statement is considered successful even if no rows in the listed
partitions (or subpartitions) match the where_condition.
For more information and examples, see Section 22.5, Partition Selection.
where_condition is an expression that evaluates to true for each row to be updated. For
expression syntax, see Section 9.5, Expression Syntax.
table_references and where_condition are specified as described in Section 13.2.9, SELECT
Syntax.
You need the UPDATE privilege only for columns referenced in an UPDATE that are actually updated.
You need only the SELECT privilege for any columns that are read but not modified.
The UPDATE statement supports the following modifiers:
With the LOW_PRIORITY modifier,
execution of the UPDATE is delayed
until no other clients are reading from
the table. This affects only storage
engines that use only table-level
locking (such as MyISAM, MEMORY,
and MERGE).
With the IGNORE modifier, the update
statement does not abort even if errors
occur during the update. Rows for
which duplicate-key conflicts occur on
a unique key value are not updated.
Rows updated to values that would
cause data conversion errors are
updated to the closest valid values
instead. For more information,
see Comparison of the IGNORE
Keyword and Strict SQL Mode.
UPDATE IGNORE statements, including those having an ORDER BY clause, are flagged as unsafe for
statement-based replication. (This is because the order in which the rows are updated determines
which rows are ignored.) Such statements produce a warning in the error log when using statement-
based mode and are written to the binary log using the row-based format when using MIXED mode.
(Bug #11758262, Bug #50439) See Section 16.2.1.3, Determination of Safe and Unsafe Statements
in Binary Logging, for more information.
If you access a column from the table to be updated in an expression, UPDATE uses the current
value of the column. For example, the following statement setscol1 to one more than its current
value:
UPDATE t1 SET col1 = col1 + 1;
The second assignment in the following statement sets col2 to the current (updated) col1 value,
not the original col1 value. The result is that col1 and col2have the same value. This behavior
differs from standard SQL.
UPDATE t1 SET col1 = col1 + 1,
col2 = col1;
Single-table UPDATE assignments are generally evaluated from left to right. For multiple-table
updates, there is no guarantee that assignments are carried out in any particular order.
If you set a column to the value it currently has, MySQL notices this and does not update it.

If you update a column that has been declared NOT NULL by setting to NULL, an error occurs if strict
SQL mode is enabled; otherwise, the column is set to the implicit default value for the column data
type and the warning count is incremented. The implicit default value is 0 for numeric types, the
empty string ('') for string types, and the zero value for date and time types. See Section 11.7,
Data Type Default Values.
If a generated column is updated explicitly, the only permitted value is DEFAULT. For information
about generated columns, see Section 13.1.18.8, CREATE TABLE and Generated Columns.
UPDATE returns the number of rows that were actually changed. The mysql_info() C API function
returns the number of rows that were matched and updated and the number of warnings that
occurred during the UPDATE.
You can use LIMIT row_count to restrict the scope of the UPDATE. A LIMIT clause is a rows-
matched restriction. The statement stops as soon as it has foundrow_count rows that satisfy
the WHERE clause, whether or not they actually were changed.
If an UPDATE statement includes an ORDER BY clause, the rows are updated in the order specified by
the clause. This can be useful in certain situations that might otherwise result in an error. Suppose
that a table t contains a column id that has a unique index. The following statement could fail with a
duplicate-key error, depending on the order in which rows are updated:
UPDATE t SET id = id + 1;
For example, if the table contains 1 and 2 in the id column and 1 is updated to 2 before 2 is updated
to 3, an error occurs. To avoid this problem, add an ORDER BY clause to cause the rows with
larger id values to be updated before those with smaller values:
UPDATE t SET id = id + 1 ORDER BY
id DESC;
You can also perform UPDATE operations covering multiple tables. However, you cannot use ORDER
BY or LIMIT with a multiple-table UPDATE. Thetable_references clause lists the tables involved in
the join. Its syntax is described in Section 13.2.9.2, JOIN Syntax. Here is an example:
UPDATE items,month SET
items.price=month.price
WHERE items.id=month.id;
The preceding example shows an inner join that uses the comma operator, but multiple-
table UPDATE statements can use any type of join permitted in SELECTstatements, such as LEFT
JOIN.
If you use a multiple-table UPDATE statement involving InnoDB tables for which there are foreign key
constraints, the MySQL optimizer might process tables in an order that differs from that of their
parent/child relationship. In this case, the statement fails and rolls back. Instead, update a single
table and rely on the ON UPDATE capabilities that InnoDB provides to cause the other tables to be
modified accordingly. See Section 14.8.1.6, InnoDB and FOREIGN KEY Constraints.
You cannot update a table and select from the same table in a subquery.

An UPDATE on a partitioned table using a storage engine such as MyISAM that employs table-level
locks locks only those partitions containing rows that match the UPDATE statement WHERE clause, as
long as none of the table partitioning columns are updated. (For storage engines such
as InnoDB that employ row-level locking, no locking of partitions takes place.) For more information,
see Section 22.6.4, Partitioning and Locking.

PREV HOME UP NEXT


User Comments
Posted by Vjero Fiala on December 6, 2003
Update one field with more fields from another table

Table A

+--------+-----------+
| A-num | text |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
+--------+-----------+

Table B:

+------+------+--------------+
| B-num| date | A-num |
| 22 | 01.08.2003 | 2 |
| 23 | 02.08.2003 | 2 |
| 24 | 03.08.2003 | 1 |
| 25 | 04.08.2003 | 4 |
| 26 | 05.03.2003 | 4 |

I will update field text in table A


with
UPDATE `Table A`,`Table B`
SET `Table A`.`text`=concat_ws('',`Table A`.`text`,`Table B`.`B-num`," from ",`Table B`.`date`,'/')
WHERE `Table A`.`A-num` = `Table B`.`A-num`

and come to this result


Table A

+--------+------------------------+
| A-num | text |
| 1 | 24 from 03 08 2003 / |
| 2 | 22 from 01 08 2003 / |
| 3 | |
| 4 | 25 from 04 08 2003 / |
| 5 | |
--------+-------------------------+
(only one field from Table B is accepted)

But i will come to this result


Table A

+--------+--------------------------------------------+
| A-num | text |
| 1 | 24 from 03 08 2003 |
| 2 | 22 from 01 08 2003 / 23 from 02 08 2003 / |
| 3 | |
| 4 | 25 from 04 08 2003 / 26 from 05 03 2003 / |
| 5 | |
+--------+--------------------------------------------+

Posted by Babu Ramesh on January 12, 2004


Update column in a table whose values are not found in another table.

UPDATE TABLE_1 LEFT JOIN TABLE_2 ON TABLE_1.COLUMN_1= TABLE_2.COLUMN_2


SET TABLE_1.COLUMN = EXPR WHERE TABLE_2.COLUMN2 IS NULL

An outerjoin is performed based on the equijoin condition.


Records not matching the equijoin from table2 are marked with null.

This facilitates to update table1 column with expression whose corresponding value from table2 is returned as
NULL
Posted by Adam Boyle on March 2, 2004
It took me a few minutes to figure this out, but the syntax for UPDATING ONE TABLE ONLY using a
relationship between two tables in MySQL 4.0 is actually quite simple:

update t1, t2 set t1.field = t2.value where t1.this = t2.that;

Posted by Neil Yalowitz on March 30, 2004


It should be noted that even simple applications of UPDATE can conflict with the 'safe mode' setting of the
mysql daemon. Many server admins default the MySQL daemon to 'safe mode'.

If UPDATE gives an error like this:

"You are using safe update mode and you tried to update a table without...etc."

...then it may be that your .cnf file must be edited to disable safemode. This worked for me. In order for the
change in the .cnf file to take effect, you must have permission to restart mysqld in the server OS environment.
There is a page in the online documentation that explains safe mode entitled 'safe Server Startup Script'.

Posted by Csaba Gabor on May 26, 2004


Suppose you have a table where each row is associated with a certain group (For example, orders are
associated with the customers placing them) where each item WITHIN the group has a distinct number (For
example, each person my have a sequence of competition results - each person, therefore, has a 1st, 2nd,
3rd... competition).
If you would like to renumber items within their group so that each has the same baseline (say 0), here is an
example way to proceed:

Create TEMPORARY Table Groups (Id INTEGER AUTO_INCREMENT PRIMARY KEY,


Name VARCHAR(31), GroupId VARCHAR(31), ValWithinGroup INTEGER);
INSERT INTO Groups VALUES (null, "Davy", "Boy", 2);
INSERT INTO Groups VALUES (null, "Mary", "Girl", 2);
INSERT INTO Groups VALUES (null, "Bill", "Boy", 5);
INSERT INTO Groups VALUES (null, "Jill", "Girl", -3);
INSERT INTO Groups VALUES (null, "Fred", "Boy", 3);

# Find the lowest value for each group


CREATE TEMPORARY TABLE GroupSum AS SELECT GroupId, MIN(ValWithinGroup)
AS baseVal FROM Groups GROUP BY GroupId;
# create an index so mySQL can efficiently match
ALTER TABLE GroupSum ADD UNIQUE (GroupId);
# finally, make the baseline adjustment
UPDATE Groups LEFT JOIN GroupSum USING (GroupId)
SET ValWithinGroup=ValWithinGroup-baseVal;
SELECT * FROM Groups;
# 1 Davy Boy 0
# 2 Mary Girl 5
# 3 Bill Boy 3
# 4 Jill Girl 0
# 5 Fred Boy 1
#Each group ("Boy", "Girl") now has a (lowest) ValWithinGroup entry of 0.

Notes: That index addition is necessary because on larger tables mySQL would rather die than figure to
(internally) index a single column join.

I was not able, using mySQL 4.1.1, to do this as a subquery:


UPDATE Groups LEFT JOIN (SELECT GroupId, MIN(ValWithinGroup) AS baseVal FROM Groups GROUP BY
GroupId) AS GrpSum USING (GroupId) SET ValWithinGroup=ValWithinGroup-baseVal;
Csaba Gabor

Posted by Micha&#322; &#321;ukaszewski on June 10, 2004


UPDATE Syntax with "on-line" updating value limitations.

I had a problem - a had to update a column "rate" but if the existince or new value is greater then 5 this "5" will
be finally value in field.
So, I do it in one "magick" query ;)
Here an example:

"3" is a some value, from form or something

update item
set rate = case when round((rate+3)/2) < 6 then round((rate+3)/2) else 5 end
where id = 1 and rate <= 6;

greetings
pecado

Posted by Alex de Landgraaf on July 21, 2004


You sometimes run into the problem that you want to replace a substring occuring in a column with a different
string, without touching the rest of the string. The solution is surprisingly simple, thanks to MySQL:

UPDATE xoops_bb_posts_text
SET post_text=(
REPLACE (post_text,
'morphix.sourceforge.net',
'www.morphix.org'));

using the string function REPLACE, all items in the post_text column with 'morphix.sourceforge.net' get this
substring replaced by 'www.morphix.org'. Ideal when writing a script is just too much effort.

Posted by Justin Swanhart on July 29, 2004


Sometimes you have a lot of processes that could be updating a column value in a table. If you want to return
the value before you updated it without using a seperate select (which unless you lock the table could return a
different value than is updated) then you can use a mysql variable like this:

update some_table
set col = col + 1
where key = 'some_key_value'
and @value := col

The @value := col will always evaluate to true and will store the col value before the update in the @value
variable.

You could then do

select @value;

in order to see what the value was before you updated it

Posted by Vladimir Petrov on December 9, 2004


MySQL uses Watcom (Oracle) syntax for UPDATE, so it's possible to write something like:

update Table1 t1
join Table2 t2 on t1.ID=t2.t1ID
join Table3 t3 on t2.ID=t3.t2ID
set t1.Value=12345
where t3.ID=54321

Posted by Matt Ryan on February 16, 2005


Here's a workaround for the update/subquery/cant do self table "bug"

Senario is, ID 8 has multiple records, only the last (highest) record needs to be changed

update t1 set c1 = 'NO'


where id='8'
order by recno desc limit 1

I would prefer update t1 set c1='NO' WHERE ID=8 AND RECNO = (SELECT MAX(RECNO) FROM T1
WHERE ID=8)

But that's not currently allowed

Posted by Bob Terrell on February 24, 2005


If you want to update a table based on an aggregate function applied to another table, you can use a correlated
subquery, for example:

UPDATE table1 SET table1field = (SELECT MAX(table2.table2field) FROM table2 WHERE table1.table1field =
table2.table2field)

This can be helpful if you need to create a temporary table storing an ID (for, say, a person) and a "last date"
and already have another table storing all dates (for example, all dates of that person's orders).

Additional information on MySQL correlated subqueries is at http://dev.mysql.com/doc/mysql/en/correlated-


subqueries.html

Posted by Ken Miller on April 6, 2005


I was looking at this example:

update item
set rate = case when round((rate+3)/2) < 6 then round((rate+3)/2) else 5 end
where id = 1 and rate <= 6;

I think it can be done simpler with LEAST:

update item
set rate = least(round((rate+3)/2), 5)
where id = 1 and rate <= 6;

(I could be wrong, but that looks like it ought to work.)

Posted by David Friedman on May 5, 2005


The UPDATE can apparently be used to implement a semaphore (pardon my pseudocode):

while TRUE {
..UPDATE table SET value = 1
....WHERE value = 0 and name = 'name'
..if no. of rows affected > 0, break
..else wait and try again
}

The code above waits until the semaphore is "cleared" (value = 0) and then "sets" it (value = 1). When done,
you "clear" the semaphore by
UPDATE table SET value = 0 WHERE name = 'name'

The assumption is that the UPDATE is "atomic" in that no concurrent access by another process can occur
between testing and setting the value field.

Posted by Mohamed Hossam on May 9, 2005


[I have posted this in the Flow Control Functions page last year but I still see people asking how to update
multiple rows. So, here it is again.]

A very server resources friendly method to update multiple rows in the same table is by using WHEN THEN
(with a very important note).

UPDATE tbl_name SET fld2 = CASE fld1


WHEN val1 THEN data1
WHEN val2 THEN data2
ELSE fld2 END

The note is: do not forget ELSE. If you do not use it, all rows that are outside the range of your updated values
will be set to blank!

Posted by Christian Hansel on July 1, 2005


If you wish to use an increment based on subset of a table you may combine UPDATE with Variables:

e.g. A table that contains entries of different categories, in which an internal order needs to represented ( lets
say a table with busstops on different routes). If you add new entries or move stops from one route to another
you will most likely want to increment the position of the busstop within this route. That's how you can do it

table busstops

id | route | busstop | pos


1|1|A|1
2|1|B|2
3|1|C|3
4|2|C|1
5|2|D|2
6|2|A|3
7|2|E|4
8|2|F|5
9|2|G|6
10 | 2 | H | 7

Moving D,E,F,G To route 1


SET @pos=(SELECT max(t1.pos) FROM busstops t1 WHERE t1.route = 1 );
UPDATE busstops SET pos = ( SELECT @pos := @pos +1 ), route =1 WHERE id IN (5,7,8,9)

I doubt this could be done otherwise since referencing the table you wish to update within the subquery creates
circular references

After DELETE or UPDATE i.e. when a row of a subset is lost/deleted/moved away from it, the whole subset will
need to be reordered. This can be done similarily :

SET @pos=0;
UPDATE busstops SET pos = ( SELECT @pos := @pos +1 ) WHERE route = 1 ORDER BY pos ASC

Chris H (chansel0049)

Posted by Anders Elton on November 24, 2005


I experienced a weird issue converting from 4 to 5.

A is a normal table, B is a temporary table:


Worked in 4
update A, B set A.population=B.pop_count where A.id=B.id

In version 5, however, the above query only updated one element while still matching "all"

In 5 I had to do it like this:


update A RIGHT JOIN B on A.id=B.id set A.population=B.pop_count
Updates all population counts correctly.

[edit: RIGHT JOIN not LEFT JOIN...]

Posted by Jan Slauer on December 9, 2005


I had the same problem after update from mysql 4.x.x to 5.x.x. I just exported all the tables to files via
PhpMyAdmin
and imported them back. Now everything works fine.

Posted by on March 17, 2006


Related to the post of Mohamed Hossam on May 9 2005 4:38am
A more general method to updtate more one row:

UPDATE table SET f1='foo', f2=


IF(f3=value,one,IF(f3=value_bis,two,f2))
WHERE f5='afected'

This set the values of field 'f2' according to the values of field 'f3' in the rows field f5 'afected'.

Posted by Rafi B. on April 26, 2006


Here is a way to use multiple tables in your UPDATE statement, but actually copying one row values into the
other, meaning, we're using the same table:

UPDATE jobs AS toTable, jobs AS fromTable


SET
toTable.job_type_id = fromTable.job_type_id,
toTable.job_company_id = fromTable.job_company_id,
toTable.job_source = fromTable.job_source,
WHERE
(toTable.job_id = 6)
AND
(fromTable.job_id = 1)

--------------
Pretty cool. What I'm doing here is copying the information I need from the row where job_id=1 to the row
where job_id=6, on the same table.

Posted by Christopher Marshall on June 7, 2006


Adam Boyle's commment above was just what I was trying to do, update one table based on a relationship
between that table and another. His example was:

update t1,t2 set t1.field=t2.value where t1.this=t2.that;

That strikes me as an elegant syntax. Here is the closest I could come up with for doing that on Oracle:
update t1 set t1.field=(select value from t2 where t1.this=t2.that) where t1.this in (select that from t2);

That strikes me as convoluted by comparison.

Posted by venky kris on June 8, 2006


Just following up on Matt Ryan's Post

Matt Ryan Writes :


>>Here's a workaround for the update/subquery/cant do self >>table "bug"

>>Senario is, ID 8 has multiple records, only the last


>>(highest) record needs to be changed

>>update t1 set c1 = 'NO'


>>where id='8'
>>order by recno desc limit 1

You can also accomplish the same by the following query :

update t1 , (select id ,max(recno) as recno from t1 where id=8 group by recno) tt


set t1.c1 = 'NO'
where tt.id=t1.id and
t1.recno=tt.recno

Comments are welcome.

Posted by Paul Decowski on August 1, 2006


Regarding Justin Swanhart's comment about retrieving a field's value in UPDATE query.

> update some_table


> set col = col + 1
> where key = 'some_key_value'
> and @value := col

> The @value := col will always evaluate to true and will store the col value before the update in the @value
variable.

In fact, in won't if `col` is NULL (0, empty string etc.) - then the condition is not met and the update query won't
be processed. The correct condition would be:

AND ((@value := `col`) OR (1 = 1))

It was very helpful to me anyway. Thx Justin!

Posted by Barry Shantz on October 24, 2006


To update a column of a table with a rank based on subsets of data, the IF() function does a wonderful job.

A summary table (in this case created to hold summary counts of other genealogy data, based on the two fields
that make up the PRIMARY key) often contains unique key fields and one or more summary totals (Cnt in this
case). Additional ranking fields in the summary table can be easily updated to contain rankings of the Cnt field
using the IF function and
local variables.

Table DDL:

CREATE TABLE `countsbyboth` (


`SurnameID` int(11) unsigned NOT NULL default '0',
`GedID` int(11) unsigned NOT NULL default '0',
`Cnt` int(11) unsigned NOT NULL default '0',
`sRank` int(11) unsigned NOT NULL default '0',
`nRank` int(11) unsigned NOT NULL default '0',
PRIMARY KEY (`SurnameID`,`GedID`),
KEY `SurnameID` (`SurnameID`,`Cnt`),
KEY `GedID` (`GedID`,`Cnt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

After populating the table with rows containing key and summary data (and leaving the rank field(s) to be
updated in
a subsequent step), the rank fields can be updated using syntax similar to the following:

update countsbyboth set srank=0, nrank=0;


set @rnk:=1, @gedid=0;
update countsbyboth
set srank=if(@gedid=(@gedid:=gedid), (@rnk:=@rnk+1),(@rnk:=1))
order by gedid desc, cnt desc;
set @rnk:=1, @snmid=0;
update countsbyboth
set nrank=if(@snmid=(@snmid:=surnameid), (@rnk:=@rnk+1),(@rnk:=1))
order by surnameid desc, cnt desc;

Query OK, 11752 rows affected (0.08 sec)


Query OK, 0 rows affected (0.00 sec)
Query OK, 11752 rows affected (0.24 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 11752 rows affected (0.19 sec)

It looks convoluted, but is really quite simple. The @rnk variable needs to be initialized, and the keyval variable
(in this case @gedid or @snmid) needs to be set to a value that will not be matched by the first record. The IF()
function checks the previous key value (left side) against the current key value (right side), and either
increments the @rnk variable when the desired key value is the same as the previous records, or reset the
@rnk variable to 1 when the key value changes.

This can be easily extended to accomodate ranking on more than one key value, and does not require sub-
selects that take considerable resources for a large table.

This example intentionally assigns different ranks to equal values of Cnt for a given key, to facilitate reporting
where column headings contain the rank value.

Posted by Barry Shantz on October 24, 2006


In the previous example, if the @rnk value is initialed with
set @rnk:=0
rather than
set @rnk:=1 ,
then it won't matter whether or not the first record's key value matches the 'key value' @gedid variable.

Posted by Jon Meredith on October 31, 2006


Thanks for Justin Swanhart/Paul Decowski tip. As of 5.0.18 it looks like the optimiser has been improved so the

AND ((@value := `col`) OR (1 = 1))

gets optimised out as 'true' and @value is left as NULL after the update.

I got it to work again by rewriting as

update some_table
set col = col + 1
where key = 'some_key_value'
and ((@value := col) IS NULL OR (@value := col) IS NOT NULL)

So you get a true value either way and value will get set. Be careful what you put on the right-hand-side as it
could get evaluated twice.

Posted by Dewey Gaedcke on December 27, 2006


Above in the docs, it says "you cannot update a table and select from the same table in a subquery"

This is true but there are two simple ways around this limit.
1) nest the subquery 2 deep so it is fully materialized before the update runs. For example:
Update t1 set v1 = t3.v1 where id in
(select t2.id, t2.v1 from (select id, v1 from t1) t2) t3

2) use a self join rather than a subquery

Posted by Lars Aronsson on March 9, 2007


Oracle databases has a keyword NOWAIT that can be used with UPDATE, causing the update to abort if it
would get stuck waiting for locks. This keyword is not available in MySQL. Just letting you know, so you can
stop looking for it.

Posted by John Batzel on March 16, 2007


The UPDATE 'bug' mentioned above is apparently related to upgrading from 4.x to 5.0x. The indexes are
slightly different formats, and it breaks *some* things. myisamchk/check table won't fix this. Dropping and re-
adding the indexes will. (And dumping the table to file and reloading it is just recreating the indexes with lots
more IO than you need to do.)

Posted by James Goatcher on March 16, 2007


This example/tip/bug-report uses MySQL version 5.0.19.

When updating one table using values obtained from another table, the manual describes the "update table1,
table2" syntax, but does not delve into the correlated subquery approach very much. It also does not point out
a VERY important execution difference.

Consider the following script:


======================================================
drop table if exists test_1;
drop table if exists test_2;

CREATE TABLE test_1 (


col_pk integer NOT NULL,
col_test integer
);

alter table test_1 add PRIMARY KEY (col_pk);

CREATE TABLE test_2 (


col_pk_join integer NOT NULL,
col_test_new integer
);

insert into test_1 (col_pk, col_test) values ( 1, null );


insert into test_1 (col_pk, col_test) values ( 2, null );
commit;

insert into test_2 (col_pk_join, col_test_new) values ( 1, 23 );


insert into test_2 (col_pk_join, col_test_new) values ( 1, 34 );
insert into test_2 (col_pk_join, col_test_new) values ( 2, 45 );
commit;

select * from test_1;


select * from test_2;

# This update should NOT work, but it does.


UPDATE test_1 t,
test_2 tmp
set t.col_test = tmp.col_test_new
where t.col_pk = tmp.col_pk_join;
commit;

select * from test_1;


======================================================

The output of the select and update statements is:

+--------+----------+
| col_pk | col_test |
+--------+----------+
| 1 | NULL |
| 2 | NULL |
+--------+----------+
2 rows in set

+-------------+--------------+
| col_pk_join | col_test_new |
+-------------+--------------+
| 1 | 23 |
| 1 | 34 |
| 2 | 45 |
+-------------+--------------+
3 rows in set

Query OK, 2 rows affected


Rows matched: 2 Changed: 2 Warnings: 0

Query OK, 0 rows affected

+--------+----------+
| col_pk | col_test |
+--------+----------+
| 1 | 23 |
| 2 | 45 |
+--------+----------+
2 rows in set

Note that the update did NOT produce any errors or warnings. It should have. Why? Because a join on value 1
produces two values from table test_2. Two values cannot fit into a space for one. What MySQL does in this
case is use the first value and ignore the second value. This is really bad in my opinion because it is, in
essence, putting incorrect data into table test_1.

Replace the update statement above with:


UPDATE test_1 t1
set t1.col_test = (
select col_test_new
from test_2 t2
where t1.col_pk = t2.col_pk_join
)
;

This will produce the appropriate error for the given data:
"ERROR 1242 : Subquery returns more than 1 row"
and will not perform any update at all, which is good (it protects table test_1 from getting bad data).

Now if you have different data........if you comment out one of the "1" values inserted into table test_2 and use
the correlated subquery update instead of the multi-table update, table test_1 will get updated with exactly what
you expect.

The moral of this example/tip/bug-report: do not use the multi-table update. Use the correlated subquery
update instead. It's safe. If you keep getting an error when you think you shouldn't, you either have bad data in
your source table or you need to rework your subquery such that it produces a guaranteed one-row result for
each destination row being updated.

The reason I call the multi-table update a bug is simply because I feel it should produce the same or similar
error as the correlated subquery update. My hope is that MySQL AB will agree with me.

Posted by Luciano Fantuzzi on March 23, 2007


Este sencillo script permite recrear el indice de una columna de forma automatica.
Nota: Si una columna tiene una restriccion NOT NULL, sera necesario usar primero 'ALTER TABLE' para
quitarle temporalmente la restriccion.

/* INICIO del script */

#En caso de tener con NOT NULL alguna columna (Ejemplo)


ALTER TABLE MiTabla CHANGE columna
columna MEDIUMINT UNSIGNED DEFAULT NULL;

#Cambio todos los valores a NULL (para que no haya riesgo de valores duplicados con restricciones UNIQUE)
UPDATE MiTabla SET columna=NULL;

#Declaro una variable como contador (puede ser 1,2,3... o el num desde donde queremos empezar)
SET @c:=1;

#Consulta
UPDATE MiTabla SET columna=(SELECT @c:=@c+1);

#Ahora podemos usar ALTER TABLE nuevamente si queremos cambiar la columna a NOT NULL (en caso de
que la hayamos cambiado)

/* FIN del script */

Tengan en cuenta de que los indices principales (los declarados como PRIMARY KEY, por ejemplo, o los que
se usan para linquear tablas) NO DEBERIAN CAMBIARSE, ya que se estropearian los vinculos entre las
tablas! Esto podria evitarse declarando las claves foraneas (FOREIGN KEY) de las tablas de linqueo con el
valor ON UPDATE CASCADE (lo que al actualizar los indices refrescaria los links entre las tablas).

Posted by Marc Vos on July 18, 2007


Here's the easy way to update a column in a table using values from other tables.

update db1.a, (
select distinct b.col1, b.col2
from db2.b, db2.c, db2.d
where b.col1<>'' and d.idnr=b.idnr and c.user=d.user and c.role='S'
order by b.col1) as e
set a.col1 = e.col1
where a.idnr = e.col1

The point is that every select statement returns a table. Name the result and you can access its columns. In
this example I called the result 'e'.

Posted by Richard Bronosky on September 5, 2007


Marc Vos led me to a solution to a problem that has been troubling me for a long time. As a DBA I often have to
support application developers who need to have data I control presented in a specific manner. This always
results in a table based on their needs and populating the columns with data from existing tables. Usually it
something like 15 columns from table A, 5 from table B, 30 from table c, and 230 from table d. In the past I
have done this with either a series of "create temporary table t1 as select ... join ..." statements until I get the
right set of columns.

I never could figure out how to set the value of multiple columns with nesting a select statement dedicated to
each column. Now I've got it. I'm attaching a transcript of doing it both ways. The statements use the tables that
already exist in the mysql schema (at least in 5.0), so you can easily recreate this on your box in a test schema.

--------------
DROP TABLE IF EXISTS test
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
CREATE TABLE test (t_id INT,k_id INT, t_name CHAR(64), t_desc TEXT) AS
SELECT help_topic_id AS t_id, help_keyword_id AS k_id, NULL AS t_name, NULL AS t_desc FROM
mysql.help_relation LIMIT 10
--------------

Query OK, 10 rows affected (0.01 sec)


Records: 10 Duplicates: 0 Warnings: 0

--------------
SELECT * FROM test
--------------

+------+------+--------+--------+
| t_id | k_id | t_name | t_desc |
+------+------+--------+--------+
| 0 | 0 | NULL | NULL |
| 327 | 0 | NULL | NULL |
| 208 | 1 | NULL | NULL |
| 409 | 2 | NULL | NULL |
| 36 | 3 | NULL | NULL |
| 388 | 3 | NULL | NULL |
| 189 | 4 | NULL | NULL |
| 169 | 5 | NULL | NULL |
| 393 | 6 | NULL | NULL |
| 17 | 7 | NULL | NULL |
+------+------+--------+--------+
10 rows in set (0.00 sec)

--------------
######
## This is the elegant single select solution! ##
######
UPDATE test AS t, (SELECT * FROM mysql.help_topic) AS h SET
t.t_name=h.name,
t.t_desc=substr(h.url,1-locate('/',reverse(h.url)))
WHERE t.t_id=h.help_topic_id
--------------

Query OK, 10 rows affected (0.04 sec)


Rows matched: 10 Changed: 10 Warnings: 0

--------------
SELECT * FROM test
--------------

+------+------+------------------+---------------------------+
| t_id | k_id | t_name | t_desc |
+------+------+------------------+---------------------------+
| 0 | 0 | JOIN | join.html |
| 327 | 0 | SELECT | select.html |
| 208 | 1 | REPEAT LOOP | repeat-statement.html |
| 409 | 2 | ISOLATION | set-transaction.html |
| 36 | 3 | REPLACE INTO | replace.html |
| 388 | 3 | LOAD DATA | load-data.html |
| 189 | 4 | CREATE FUNCTION | create-function.html |
| 169 | 5 | CHANGE MASTER TO | change-master-to.html |
| 393 | 6 | CHAR | string-type-overview.html |
| 17 | 7 | SHOW COLUMNS | show-columns.html |
+------+------+------------------+---------------------------+
10 rows in set (0.03 sec)

--------------
DROP TABLE IF EXISTS test
--------------

Query OK, 0 rows affected (0.00 sec)

--------------
CREATE TABLE test (t_id INT,k_id INT, t_name CHAR(64), t_desc TEXT) AS
SELECT help_topic_id AS t_id, help_keyword_id AS k_id, NULL AS t_name, NULL AS t_desc FROM
mysql.help_relation LIMIT 10
--------------

Query OK, 10 rows affected (0.01 sec)


Records: 10 Duplicates: 0 Warnings: 0

--------------
SELECT * FROM test
--------------

+------+------+--------+--------+
| t_id | k_id | t_name | t_desc |
+------+------+--------+--------+
| 0 | 0 | NULL | NULL |
| 327 | 0 | NULL | NULL |
| 208 | 1 | NULL | NULL |
| 409 | 2 | NULL | NULL |
| 36 | 3 | NULL | NULL |
| 388 | 3 | NULL | NULL |
| 189 | 4 | NULL | NULL |
| 169 | 5 | NULL | NULL |
| 393 | 6 | NULL | NULL |
| 17 | 7 | NULL | NULL |
+------+------+--------+--------+
10 rows in set (0.00 sec)

--------------
######
## This is the nasty one select for each column that needs to be updated method! ##
######
UPDATE test AS t SET
t.t_name=(SELECT name FROM mysql.help_topic WHERE t.t_id=help_topic_id),
t.t_desc=(SELECT substr(url,1-locate('/',reverse(url))) FROM mysql.help_topic WHERE t.t_id=help_topic_id)
--------------

Query OK, 10 rows affected (0.00 sec)


Rows matched: 10 Changed: 10 Warnings: 0

--------------
SELECT * FROM test
--------------

+------+------+------------------+---------------------------+
| t_id | k_id | t_name | t_desc |
+------+------+------------------+---------------------------+
| 0 | 0 | JOIN | join.html |
| 327 | 0 | SELECT | select.html |
| 208 | 1 | REPEAT LOOP | repeat-statement.html |
| 409 | 2 | ISOLATION | set-transaction.html |
| 36 | 3 | REPLACE INTO | replace.html |
| 388 | 3 | LOAD DATA | load-data.html |
| 189 | 4 | CREATE FUNCTION | create-function.html |
| 169 | 5 | CHANGE MASTER TO | change-master-to.html |
| 393 | 6 | CHAR | string-type-overview.html |
| 17 | 7 | SHOW COLUMNS | show-columns.html |
+------+------+------------------+---------------------------+
10 rows in set (0.00 sec)

Bye

Posted by Joris Kinable on April 30, 2008


Updating multiple fields based on query results can be quite expensive if the same query has to be executed
multiple times. Imagine the following table:

summary(X,A,B,C,D) and a query which returns: (X,E,F) and you want to update the summary table fields C
and D with the values of E and F:

Summary: (1,2,3,0,0),(10,12,13,0,0) and query result: (1,4,5),(10,14,15) should result in the updated summary
table: (1,2,3,4,5,6),(10,11,12,13,14,15)

BAD SOLUTION (same query is evaluated twice!):

UPDATE summary SET C=(SELECT E FROM (query) q WHERE summary.X=q.X), D=(SELECT F FROM
(query) q WHERE summary.X=q.X)

GOOD SOLUTION (query is only evaluated once):

UPDATE summary AS t, (query) AS q SET t.C=q.E, t.D=q.F WHERE t.X=q.X

Posted by Nigel Smith on September 16, 2008


Example of updating a table using a group selection from another table:-
update tableA,
(
select idTableA,min(valueField) as minV from tableB group by idTableA
) as T
set tableA.minValue=minV where tableA.idTableA=T.idTableA

Posted by Roger Morris on September 23, 2008


To swap two values in a single table. If you need to keep the lower value in a certain column:
mysql> select * from test;
+-------+------+-------+-------+
| index | name | item1 | item2 |
+-------+------+-------+-------+
| 1 | one | 25 | 50 |
| 2 | two | 75 | 40 |
| 3 | one | 35 | 60 |
| 4 | four | 100 | 80 |
+-------+------+-------+-------+
4 rows in set (0.00 sec)

### (@olditem1:=item1) will assign the value of item1 *before* the update.

mysql> update test set item1=item2,item2=@olditem1 where (@olditem1:=item1) and item1>item2;


Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0

mysql> select * from test;


+-------+------+-------+-------+
| index | name | item1 | item2 |
+-------+------+-------+-------+
| 1 | one | 25 | 50 |
| 2 | two | 40 | 75 |
| 3 | one | 35 | 60 |
| 4 | four | 80 | 100 |
+-------+------+-------+-------+
4 rows in set (0.00 sec)

Posted by Enrico Modanese on September 2, 2009


Following the post of James Goatcher (object: ORDER BY in multi-table UPDATE) I'd like to resume the
argument and related work-around:

1. multi-table UPDATE doesn't support ORDER BY (as written in documentation)

2. multi-table UPDATE retrieving more than 1 row for every row to be updated, will perform only 1 update with
the first found value and wont send any message about following skipped values (I don't know if it should be
called an error)

3. first work-around (+quick -secure): be sure that the joined tables are ordered to offer as first the correct value

4. second work-around (-quick +secure): use a subselect for the value to be set [ x=(SELECT yy FROM ...
ORDER BY... LIMIT 1) ] as shown in the preceding example of James Goatcher (please note the use of LIMIT)

Hope this will help, Enrico

Posted by Pavel Tishkin on January 26, 2010


UPDATE some_table as bm
SET bm.i_ordi=(SELECT @a:=@a+1)
WHERE bm.i_type=1 AND (@a:=IFNULL(@a,-2)+1)<>'1'
ORDER BY bm.i_create_ts;

Sorting AND set auto_increment order


Posted by Anto Justus on June 2, 2010
you can try this type of query :

UPDATE dt_log AS t,
(
SELECT max(el_count)+1 as maxcount
FROM dt_log where dt_nameid IN ('1','2','3','4')
) AS h
SET t.dt_rej = h.maxcount
WHERE t.dt_edate = '0000-00-00 00:00:00'
AND t.dt_nameid IN ('1','2','3','4')

get the max and update..

Posted by Dave Scotese on October 11, 2010


When I executed a correlated subquery:

UPDATE T1 SET f1= (SELECT COUNT(*) FROM T2 WHERE T2.f2=T1.f2)

to update one table with aggregates from another, it took 3 seconds to do 50 records and about 57 seconds to
do 800 records.

When I used a non-correlated subquery:

UPDATE T1 INNER JOIN (SELECT COUNT(*) AS c FROM T2 GROUP BY f2) t USING(f2) SET f1=t.c

it did 76 records in 177 ms, and 350 records in 177 ms and 2800 records in 250 ms.

I believe that a correlated subquery is executed once for each result of the outer query, whereas a JOIN to a
non-correlated subquery executes the inner query only once.

Posted by Misha B on April 21, 2011


Change values between two and more columns. In result, ufter update, columns will have values from after
columns
column1 = column2, column2 = column1

UPDATE
table1
SET
column1 = (@v := column1), column1 = column2, column2 = @v;

Posted by Ajmer Phull on February 2, 2012


Hopefully this will be useful to someone else, like it was for me when I had to perform data cleansing and
enhancing badly designed databases. This can also be helpful for replacing data in fields with ID's when
normalising databases.

The following will update a field (field9 which is empty) in TABLE1 with data from a field (field9) in TABLE3
using joins with TABLE2 and TABLE3. I have made up the WHERE & AND conditions to show this example.

UPDATE table1 t1
JOIN table2 t2 ON t1.field1 = t2.field1
JOIN table3 t3 ON (t3.field1=t2.field2 AND t3.field3 IS NOT NULL)
SET t1.field9=t3.field9
WHERE t1.field5=1
AND t1.field9 IS NULL

Sign UpLoginYou must be logged in to post a comment.


2017, Oracle Corporation and/or its affiliates

You might also like