{"id":97336,"date":"2023-07-27T16:25:19","date_gmt":"2023-07-27T16:25:19","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=97336"},"modified":"2026-04-23T15:39:31","modified_gmt":"2026-04-23T15:39:31","slug":"exporting-data-from-a-mysql-database-using-selectinto-outfile","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/exporting-data-from-a-mysql-database-using-selectinto-outfile\/","title":{"rendered":"MySQL SELECT INTO OUTFILE: Export Data to CSV\/Text"},"content":{"rendered":"<p>MySQL\u2019s SELECT\u2026INTO OUTFILE clause exports query results directly to a text file on the server. Add INTO OUTFILE \u2018\/path\/to\/file.csv\u2019 to any SELECT statement to write the result set to a file. You can control the output format with FIELDS TERMINATED BY (column delimiter, default tab), FIELDS ENCLOSED BY (value quoting), and LINES TERMINATED BY (row delimiter, default newline). The file must not already exist, the MySQL user must have the FILE privilege, and the output path must comply with the secure-file-priv setting. This guide demonstrates the full syntax with working examples for CSV, TSV, and custom-delimited exports.<\/p>\n<p style=\"margin: 0in; font-family: Calibri; font-size: 11.0pt;\"><p><strong>This article is part of Robert Sheldon's continuing series on Learning MySQL. To see all of the items in the series, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/mysql-coding-basics\/\">click here<\/a>.<\/strong><\/p>\n<\/p>\n<p>In the previous article in this series, I introduced you to the MySQL <code>LOAD<\/code> <code>DATA<\/code> statement, which lets you retrieve data from a plain text file and insert it into a table. In this article, I cover the <code>SELECT\u2026INTO<\/code> <code>OUTFILE<\/code> statement, a type of <code>SELECT<\/code> statement that includes the <code>INTO<\/code> <code>OUTFILE<\/code> clause. The clause lets you export data from one or more MySQL tables into a plain text file, providing a counterpart to the <code>LOAD<\/code> <code>DATA<\/code> statement.<\/p>\n<p>Building a <code>SELECT\u2026INTO<\/code> <code>OUTFILE<\/code> statement is relatively straightforward. The main part of the <code>SELECT<\/code> statement (without the <code>INTO<\/code> <code>OUTFILE<\/code> clause) is like any other <code>SELECT<\/code> statements, except for a couple minor considerations. And the <code>INTO<\/code> <code>OUTFILE<\/code> clause itself is fairly easy to construct. Perhaps the biggest issue you\u2019ll run into is not having the permissions necessary to save a file to the target folder, which I discuss later in the article. Otherwise, you should have little problem getting started with the <code>INTO<\/code> <code>OUTFILE<\/code> clause.<\/p>\n<p>In this article, I show you multiple examples that demonstrate how the clause works so you have a foundation in how to use it to export data. Most of the examples are built with basic <code>SELECT<\/code> statements, so they should be fairly easy for you to try out. If you have any questions about the <code>SELECT<\/code> statement itself (other than the <code>INTO<\/code> <code>OUTFILE<\/code> clause), refer to an <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/introducing-the-mysql-select-statement\/\">earlier article<\/a> in this series that introduces you to the statement.<\/p>\n<p>Note: The examples in this article are based on a local instance of MySQL that hosts a very simple database and tables. The last section of the article\u2014\u201cAppendix: Preparing your MySQL environment\u201d\u2014provides information about how I set up my system and includes the SQL script for creating the database and tables on which the examples are based.<\/p>\n<h2>Introducing the <strong>SELECT\u2026INTO<\/strong> <strong>OUTFILE<\/strong> statement<\/h2>\n<p>Before we jump into the examples, you should have a basic understanding of the <code>INTO<\/code> <code>OUTFILE<\/code> clause and how it fits into a <code>SELECT<\/code> statement. The following syntax shows the elements that make up the clause:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT <em>statement_elements<\/em>\nINTO OUTFILE '<em>file_name<\/em>'\n[FIELDS\n  [TERMINATED BY '<em>string<\/em>']\n  [[OPTIONALLY] ENCLOSED BY '<em>char<\/em>']\n  [ESCAPED BY '<em>char<\/em>']]\n[LINES\n  [STARTING BY '<em>string<\/em>']\n  [TERMINATED BY '<em>string<\/em>']];<\/pre>\n<p>The <code>SELECT<\/code> statement itself is shown only with <code>statement_elements<\/code> placeholder, which represents all the elements that can potentially be included in a <code>SELECT<\/code> statement, other than the <code>INTO<\/code> <code>OUTFILE<\/code> clause. For the most part, you can create just about any type of <code>SELECT<\/code> statement. The main caveat is that you should not use an <code>INTO<\/code> <code>OUTFILE<\/code> clause in a nested <code>SELECT<\/code> statement because that statement must return its results to the outer statement.<\/p>\n<p>The MySQL documentation also states that MySQL places \u201cconstraints on the use of <code>INTO<\/code> within <code>UNION<\/code> statements.\u201d Unfortunately, the documentation does not state what those constraints might be. I was able to run a <code>UNION<\/code> statement that included an <code>INTO<\/code> <code>OUTFILE<\/code> clause tagged onto the end of the statement, and it created the file just fine. However, when I placed the clause just before the first <code>FROM<\/code> clause, I received an error stating that the <code>INTO<\/code> clause must be placed at the end of the <code>UNION<\/code> statement, so perhaps \u201cconstraints\u201d applies primarily to the clause\u2019s placement.<\/p>\n<p>In the syntax above, the <code>INTO<\/code> <code>OUTFILE<\/code> clause is placed after all the other <code>SELECT<\/code> statement elements. Strictly speaking, you don\u2019t have to place the clause at the end of the statement (except for a <code>UNION<\/code> statement or other <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/set-operations.html\">set operators<\/a> like <code>INTERSECT<\/code> and <code>EXCEPT<\/code>). For example, you can place the clause before the <code>FROM<\/code> clause or before a locking clause such as <code>FOR<\/code> <code>UPDATE<\/code>. According to MySQL documentation, however, the end of the statement is the preferred position. In fact, placing the clause before a locking clause is deprecated as of MySQL 8.0.20, and if you try to do this, you\u2019ll receive a warning message. I recommend that you place the clause at the end of your <code>SELECT<\/code> statements, as the documentation advises.<\/p>\n<p>Now let\u2019s return to the <code>INTO<\/code> <code>OUTFILE<\/code> clause itself. The clause starts by specifying the name of the target file that will hold the result set returned by the <code>SELECT<\/code> statement. In most cases, this will be a full pathname that points to a location on the MySQL host. If the path is not included, the file will be saved to the folder that holds the database data.<\/p>\n<p>When specifying the <code>INTO<\/code> <code>OUTFILE<\/code> clause, you can also include one or more export options, which you define in the optional <code>FIELDS<\/code> clause and <code>LINES<\/code> clause. The two clauses are syntactically identical to the ones used for the <code>LOAD<\/code> <code>DATA<\/code> statement and work much the same way. The <code>FIELDS<\/code> clause supports one or more of the following three options:<\/p>\n<ul>\n<li>The <code>TERMINATED<\/code> <code>BY<\/code> option specifies the string used in the text file to terminate each field. The string can be one or more characters. The default value is <code>\\t<\/code> for tab, which means that tabs are used to separate field values.<\/li>\n<li>The <code>ENCLOSED<\/code> <code>BY<\/code> option specifies the character used in the text file to enclose all or some values in the text file. If you include the <code>OPTIONALLY<\/code> keyword, the <code>ENCLOSED<\/code> <code>BY<\/code> character applies only to values with a string data type, such as <code>CHAR<\/code>, <code>BINARY<\/code>, <code>TEXT<\/code>, or <code>ENUM<\/code>. The default value for the <code>ENCLOSED<\/code> <code>BY<\/code> option is an empty string, indicating that no fields are enclosed by an <code>ENCLOSED<\/code> <code>BY<\/code> character.<\/li>\n<li>The <code>ESCAPED<\/code> <code>BY<\/code> option specifies the character used in the text file to escape special characters. The default value is a backslash (<code>\\<\/code>), which is used in MySQL to escape special characters, including the backslash itself. Many programming languages also use the backslash to escape characters.<\/li>\n<\/ul>\n<p>The <code>FIELDS<\/code> clause is itself optional. If you include it, you must specify at least one of the three options. The <code>LINES<\/code> clause is also optional. It supports either one or both of the following two options:<\/p>\n<ul>\n<li>The <code>STARTING<\/code> <code>BY<\/code> option specifies the common prefix used at the beginning of each line in the text file. The default value is an empty string, indicating that no specific prefix is used.<\/li>\n<li>The <code>TERMINATED<\/code> <code>BY<\/code> option specifies the string used in the text file to terminate each line. The string can be one or more characters. The default value is <code>\\n<\/code>, which refers to a newline character (linefeed). The system on which you\u2019re working might require a different setting. For example, <code>\\n<\/code> works fine on Mac computers, but you might need to use <code>\\r\\n<\/code> on Windows system.<\/li>\n<\/ul>\n<p>If you include both the <code>FIELDS<\/code> clause and <code>LINES<\/code> clause, the <code>FIELDS<\/code> clause must come first. I recommend that you review the MySQL topic <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/load-data.html\">LOAD DATA Statement<\/a> to learn more about the various elements that go into the <code>INTO<\/code> <code>OUTFILE<\/code> clause.<\/p>\n<h2>Outputting MySQL data to a file<\/h2>\n<p>Now that you have a basic understanding of the <code>INTO<\/code> <code>OUTFILE<\/code> syntax, let\u2019s start into the examples, which should help you better understand the information above. The most basic <code>SELECT\u2026INTO<\/code> <code>OUTFILE<\/code> statement is one that includes only a <code>SELECT<\/code> clause and an <code>INTO<\/code> <code>OUTFILE<\/code> clause, without any export options. The following <code>SELECT<\/code> statement saves four values (two strings and two integers) to the <strong>values01.txt<\/strong> file:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT 'abc', 123, 'def', 456\nINTO OUTFILE 'values01.txt';<\/pre>\n<p>The <code>SELECT<\/code> clause defines the four values, and the <code>INTO<\/code> <code>OUTFILE<\/code> clause specifies that name of the new file. The file cannot already exist when you run this statement. It if does, you will receive an error. If it does not exist, MySQL creates the file and inserts the values returned by the <code>SELECT<\/code> statement. The following figure shows the file opened in BBEdit.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1026\" height=\"328\" class=\"wp-image-97337\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-1.png\" \/><\/p>\n<hr \/>\n<p>Note: depending on your configuration, you may receive an error such as:<\/p>\n<p><code>INTO OUTFILE 'values01.txt'\t<\/code><\/p>\n<p><code>Error Code: 1290. The MySQL server is running with the --secure-file-priv option so it cannot execute this statement\t<\/code><\/p>\n<p>when you execute this statement. You can see this security setting using:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SHOW VARIABLES LIKE \"secure_file_priv\";<\/pre>\n<p>This will show you a path that has been set up for you to securely use from the server. You may need to prefix your .txt file names with the path that is returned. Or you can change the setting in your config file to be <code>\"\"<\/code> and your file will be output to any location on the server where it has rights to.<\/p>\n<hr \/>\n<p>When you use the <code>INTO<\/code> <code>OUTFILE<\/code> clause, MySQL creates the file on the computer where MySQL is running. There is no way to save the file to another computer unless the remote computer can be accessed via a network-mapped path on the host system.<\/p>\n<p>You might have noticed in the preceding example that the filename is specified without the full pathname. When you don\u2019t specify a pathname, MySQL creates the file in the database directory, which in this case, is the <strong>travel<\/strong> directory because you\u2019re working in the <code>travel<\/code> database. The <strong>travel<\/strong> directory stores the data files for the <code>airplanes<\/code> and <code>manufacturers<\/code> tables. (Note: on the editor&#8217;s Windows machine the file was located in: <code>C:\\ProgramData\\MySQL\\MySQL Server 8.0\\Data\\travel<\/code>).<\/p>\n<p>If you\u2019re using a MySQL instance that is not under your control, you might find that database administrators or other stakeholders do not want you to save files to the database directory, in which case, you\u2019ll need to use a different folder. To save the output file elsewhere, you must specify the full pathname in the <code>INTO<\/code> <code>OUTFILE<\/code> clause. In addition, the target directory must be configured with the proper write permissions. If you receive an \u201cOS errno 13 &#8211; Permission denied\u201d error message when you try to run your statement, you\u2019ll know that something is wrong with the directory permissions.<\/p>\n<p>Another issue that you might have to contend with is that the account you use to log into MySQL must be granted the <code>FILE<\/code> privilege in order to read and write files on the MySQL host. Without this privilege, you\u2019ll receive an access denied error message when attempting to run your statements. If you\u2019re trying out the examples in this article, chances are you\u2019re running them against a MySQL host that you control, so you can set up the necessary permissions yourself. If you don\u2019t control the host, you\u2019ll need to work with a database or system administrator to get you set up.<\/p>\n<p>With all that in mind, the rest of examples assume that you\u2019ll be targeting a location other than the database directory when defining your <code>INTO<\/code> <code>OUTFILE<\/code> clause and that you have all the necessary permissions in place. The next example is similar to the previous one, but it now specifies the full directory path:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT 'abc', 123, 'def', 456\nINTO OUTFILE '\/Users\/user1\/data\/values02.txt';<\/pre>\n<p>The <code>INTO<\/code> <code>OUTFILE<\/code> clause now points the <strong>\/Users\/user1\/data\/<\/strong> directory instead of the database folder. However, you can specify whatever directory works for you. (You can also use whatever filename you like.) If you\u2019re working on a Windows system, you should specify pathname backslashes as either forward slashes or double backslashes.<\/p>\n<p>Most <code>SELECT<\/code> statements include a <code>FROM<\/code> clause that retrieves data from a table or another type of table structure, such as a <code>VALUES<\/code> clause or table subquery. For example, the <code>FROM<\/code> clause in following <code>SELECT<\/code> statement include a <code>VALUES<\/code> clause that creates a table with two columns and three rows, which are outputted to the <strong>values03.txt<\/strong> file:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT *\nFROM (VALUES \n  ROW('abc', 123), \n  ROW('def', 456), \n  ROW('ghi', 789)) AS tbl\nINTO OUTFILE '\/Users\/user1\/data\/values03.txt';<\/pre>\n<p>When you run the statement, MySQL creates the file and populates it with the returned values, as shown in the following figure:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"912\" height=\"322\" class=\"wp-image-97338\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-2.png\" \/><\/p>\n<p>Of course, you can also retrieve data from a regular table and output it to a text file, which is how you\u2019ll most likely be using the <code>INTO<\/code> <code>OUTFILE<\/code> clause. For example, the following <code>SELECT<\/code> statement retrieves data from the <code>airplanes<\/code> table and outputs those results to the <strong>airplanes01.txt<\/strong> file:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airplanes\nORDER BY plane\nLIMIT 10\nINTO OUTFILE '\/Users\/user1\/data\/airplanes01.txt';<\/pre>\n<p>The <code>SELECT<\/code> statement sorts the data by the <code>plane<\/code> column and limits the results to the first 10 rows. Because the <code>SELECT<\/code> clause includes only an asterisk (*), the statement returns all of the table\u2019s columns and saves them to the <strong>airplanes01.txt<\/strong> file, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1918\" height=\"586\" class=\"wp-image-97339\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-3.png\" \/><\/p>\n<p>The MySQL <code>TABLE<\/code> statement also supports the <code>INTO<\/code> <code>OUTFILE<\/code> clause. Because of this, you can recast the preceding <code>SELECT<\/code> statement as the following <code>TABLE<\/code> statement, which returns that same results as the previous example but saves them to the <strong>airplanes02.txt<\/strong> file:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">TABLE airplanes\nORDER BY plane\nLIMIT 10\nINTO OUTFILE '\/Users\/user1\/data\/airplanes02.txt';<\/pre>\n<p>The <code>TABLE<\/code> statement is fairly limited in scope and supports only a few clauses, including <code>ORDER<\/code> <code>BY<\/code> and <code>LIMIT<\/code>. The statement can be useful when you want to return all columns and either all rows or a certain number of rows. That said, you\u2019ll usually want more control over your queries, which is why you\u2019ll likely be using the <code>SELECT<\/code> statement. The statement lets you specify which columns to return, and it provides additional clauses, such as <code>WHERE<\/code> and <code>GROUP<\/code> <code>BY<\/code>. For example, the following <code>SELECT<\/code> statement limits the results to specific columns and types of planes:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, engine_type, engine_count, max_weight, plane_length\nFROM airplanes\nWHERE engine_type = 'jet'\nORDER BY plane\nINTO OUTFILE '\/Users\/user1\/data\/jets01.txt';<\/pre>\n<p>Now the results are much more targeted, as reflected in the <strong>jets01.txt<\/strong> file, which is shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1248\" height=\"572\" class=\"wp-image-97340\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-4.png\" \/><\/p>\n<p>As expected, the file contains only those rows whose <code>engine_type<\/code> value equals <code>jet<\/code>. The data is also limited to the five specified columns: <code>plane<\/code>, <code>engine_type<\/code>, <code>engine_count<\/code>, <code>max_weight<\/code> and <code>plane_length<\/code>.<\/p>\n<h2>Working with the <strong>INTO OUTFILE<\/strong> export options<\/h2>\n<p>As mentioned earlier, the <code>INTO<\/code> <code>OUTFILE<\/code> clause supports multiple export options. The options let you better control how the returned data is saved to the output file. If you don\u2019t specify any export options, MySQL uses the default options, such as using tabs to separate values and not enclosing the values in quotes or other characters.<\/p>\n<p>If the previous statement were redefined to include the export options and their default values, it would look like the following <code>SELECT<\/code> statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk \">SELECT plane, engine_type, engine_count, max_weight, plane_length\nFROM airplanes\nWHERE engine_type = 'jet'\nORDER BY plane\nINTO OUTFILE '\/Users\/user1\/data\/jets02.txt'\n  FIELDS TERMINATED BY '\\t' ENCLOSED BY '' ESCAPED BY '\\\\'\n  LINES TERMINATED BY '\\n' STARTING BY '';<\/pre>\n<p>The statement returns the same results as the previous one. The only difference is that the <code>INTO<\/code> <code>OUTFILE<\/code> clause explicitly defines the export options, using their default values. However, suppose you want to use a comma instead of a tab as the field terminator, and you want to enclose string values in double quotes. To do this, you can modify the export options as follows:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, engine_type, engine_count, max_weight, plane_length\nFROM airplanes\nWHERE engine_type = 'jet'\nORDER BY plane\nINTO OUTFILE '\/Users\/user1\/data\/jets03.txt'\n  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '\\\\'\n  LINES TERMINATED BY '\\n' STARTING BY '';<\/pre>\n<p>The <code>FIELDS<\/code> <code>TERMINATED<\/code> <code>BY<\/code> option now specifies a comma as its value, and the <code>ENCLOSED<\/code> <code>BY<\/code> option specifies a double quote as it value. The clause also includes the <code>OPTIONALLY<\/code> keyword, which limits its application to string values. Although this <code>SELECT<\/code> statement and the preceding one return the same data, the output file now looks much different, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1286\" height=\"568\" class=\"wp-image-97341\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-5.png\" \/><\/p>\n<p>Each string value is enclosed in double quotes, and the fields are separated by commas. If you want, you can use the .csv extension for the file, rather than .txt. The results would be the same. You should use whichever file extension best supports your requirements.<\/p>\n<p>Now suppose you want to add a prefix to the beginning of each row. You can easily do this by changing the value of the <code>STARTING<\/code> <code>BY<\/code> option. For example, the following <code>SELECT<\/code> statement replaces the empty string with <code>xxx<\/code> <code>:<\/code> (including the trailing space):<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, engine_type, engine_count, max_weight, plane_length\nFROM airplanes\nWHERE engine_type = 'jet'\nORDER BY plane\nINTO OUTFILE '\/Users\/user1\/data\/jets04.txt'\n  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '\\\\'\n  LINES TERMINATED BY '\\n' STARTING BY 'xxx : ';<\/pre>\n<p>Now each line in the file starts with the specified prefix, even though the result set itself is still the same, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1352\" height=\"594\" class=\"wp-image-97342\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-6.png\" \/><\/p>\n<p>A prefix can be useful if you\u2019re working with an application or system that needs to be able to clearly delineate the beginning of each row. It\u2019s also useful if you want to add information before the prefix but want it clearly distinguished from the core data so the data can be imported without issue. For example, someone might need to add a comment to the text file after it has been generated:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">xxx : \"747-8F\",\"Jet\",4,987000,250.17\nxxx : \"747-SP\",\"Jet\",4,696000,184.75\nxxx : \"757-300\",\"Jet\",2,270000,178.58\nverify listing xxx : \"767-200\",\"Jet\",2,315000,159.17\nxxx : \"767-200ER\",\"Jet\",2,395000,159.17\nxxx : \"A340-600\",\"Jet\",4,837756,247.24\nxxx : \"A350-800 XWB\",\"Jet\",2,546700,198.58<\/pre>\n<p>An application or process that reads that file, such as the MySQL <code>LOAD<\/code> <code>DATA<\/code> statement, can ignore everything up to and including the <code>xxx<\/code> <code>:<\/code> prefix, importing only the actual data.<br \/><strong>Read also:<br \/><\/strong><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/retrieving-mysql-data-python\/\">Retrieving MySQL data with Python<\/a><br \/><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/oracle-databases\/a-guide-to-insert-update-and-delete-statements-in-oracle\/\">Oracle INSERT, UPDATE, and DELETE operations<\/a><br \/><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/database-administration-sql-server\/creating-csv-files-using-bcp-and-stored-procedures\/\"><span data-sheets-root=\"1\">Creating CSV files using BCP<\/span><\/a><strong><br \/><\/strong><\/p>\n<h2>Mixing things up<\/h2>\n<p>The examples up to this point used the default <code>LINES<\/code> <code>TERMINATED<\/code> <code>BY<\/code> value (<code>\\n<\/code>), which meant that each row started on a new line, making it easy to distinguish one row from the next. There might be times, however, when you want to terminate each row in some other way. For example, the following <code>SELECT<\/code> statement uses a semi-colon (;) as the <code>LINES<\/code> <code>TERMINATED<\/code> <code>BY<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, engine_count, max_weight, wingspan, plane_length\nFROM airplanes\nWHERE engine_type = 'jet'\nORDER BY plane\nINTO OUTFILE '\/Users\/user1\/data\/jets05.txt'\n  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '\\\\'\n  LINES TERMINATED BY ';';<\/pre>\n<p>Because a semi-colon is used to terminate each row, the data is saved to the file as a single row. The following figure shows part of the results as they\u2019re saved to the <strong>jets05.txt<\/strong> file. Even though the data is in a single row, the values are still distinguishable from each other, with commas separating the values and semi-colons separating the rows.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2240\" height=\"248\" class=\"wp-image-97343\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-7.png\" \/><\/p>\n<p>The <code>SELECT<\/code> and <code>TABLE<\/code> statements also support the <code>INTO<\/code> <code>DUMPFILE<\/code> clause. The clause can be used in place of the <code>INTO<\/code> <code>OUTFILE<\/code> clause, but only if the query returns a single row. For example, the following <code>SELECT<\/code> statement returns one row from the <code>airplanes<\/code> table and saves it to the <strong>jets06.txt<\/strong> file:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT plane, engine_count, max_weight, wingspan, plane_length\nFROM airplanes\nWHERE plane_id = 1001\nINTO DUMPFILE '\/Users\/user1\/data\/jets06.txt';<\/pre>\n<p>The challenge with the <code>INTO<\/code> <code>DUMPFILE<\/code> clause is that it writes the data without any field or row terminators and without escaping any characters, running all the values together in a single row, as shown in the following figure. For this reason, the clause is usually best suited to retrieving a single <code>BLOB<\/code> value and storing it into a file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"266\" class=\"wp-image-97344\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-8.png\" \/><\/p>\n<p>The <code>INTO<\/code> <code>OUTFILE<\/code> clause is much more flexible, and you can use it with a wide range of <code>SELECT<\/code> statements. For example, the following <code>SELECT<\/code> statement joins the <code>manufacturers<\/code> and <code>airplanes<\/code> tables, groups the data based on the <code>manufacturer_id<\/code> values, and then aggregates the values from several columns:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT a.manufacturer_id, m.manufacturer, \n  COUNT(*) AS plane_count,\n  ROUND(AVG(a.wingspan), 2) AS avg_span, \n  ROUND(AVG(a.plane_length), 2) AS avg_length\nFROM airplanes a INNER JOIN manufacturers m\n  ON a.manufacturer_id = m.manufacturer_id\nGROUP BY a.manufacturer_id\nORDER BY m.manufacturer\nINTO OUTFILE '\/Users\/user1\/data\/manufacturers01.txt'\n  FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"';<\/pre>\n<p>The <code>INTO<\/code> <code>OUTFILE<\/code> clause saves the data to the <strong>manufacturers01.txt<\/strong> file, as shown in the following figure:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"444\" class=\"wp-image-97345\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97336-9.png\" \/><\/p>\n<p>Although the data has been grouped and aggregated, the <code>INTO<\/code> <code>OUTFILE<\/code> clause still treats the results like it did the early examples: commas separate the field values, each row starts on a new line, and string values are enclosed in double quotes. As you can see, you can just as easily export the results from a more complex query as you can a simply query.<\/p>\n<h2>Getting started with exporting data in MySQL<\/h2>\n<p>The <code>INTO<\/code> <code>OUTFILE<\/code> clause can provide you with an extremely useful tool for exporting data. Because you can include it in your <code>SELECT<\/code> and <code>TABLE<\/code> statements, you can easily export data wherever you normally run SQL queries, which means you can also automate and schedule export operations.<\/p>\n<p>You should be aware, however, that there are other ways to export data. One approach is to run a <strong>mysql<\/strong> or <strong>mysqldump<\/strong> command at a command prompt and direct the results to a file. You can also use the features built into a MySQL client to export data. For example, MySQL Workbench lets you export data directly from the search results and save them as JSON, CSV, XML, HTML, or other formats. Workbench also includes an Export and Import wizard that steps you though the process of exporting data.<\/p>\n<p>Although you have plenty of options for exporting MySQL data, the <code>INTO<\/code> <code>OUTFILE<\/code> clause can still be very useful. You can easily tag it onto your existing <code>SELECT<\/code> statements, making it possible to use it repeatedly (keeping in mind that it will not overwrite an existing file). You can also set up your output files so the <code>LOAD<\/code> <code>DATA<\/code> statement can later be used to import the data. The better you understand how the <code>INTO<\/code> <code>OUTFILE<\/code> clause works, the better you can take advantage of this simple yet effective tool.<strong><br \/><\/strong><\/p>\n<h2>Appendix: Preparing your MySQL environment<\/h2>\n<p>When creating the examples for this article, I used a Mac computer that was set up with a local instance of MySQL 8.0.29 (Community Server edition). I also used MySQL Workbench to interface with MySQL.<\/p>\n<p>The examples in this article retrieve data from the <code>travel<\/code> database and export the data to individual text files on that computer. The database contains <code>manufacturers<\/code> table and the <code>airplanes<\/code> table, which includes a foreign key that references the <code>manufacturers<\/code> table. This is the same database and tables you saw in previous articles in this series. If you plan to try out the examples, start by running the following script against your MySQL instance:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP DATABASE IF EXISTS travel;\nCREATE DATABASE travel;\nUSE travel;\nCREATE TABLE manufacturers (\n  manufacturer_id INT UNSIGNED NOT NULL,\n  manufacturer VARCHAR(50) NOT NULL,\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  last_update TIMESTAMP NOT NULL \n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (manufacturer_id) );\nCREATE TABLE airplanes (\n  plane_id INT UNSIGNED NOT NULL,\n  plane VARCHAR(50) NOT NULL,\n  manufacturer_id INT UNSIGNED NOT NULL,\n  engine_type VARCHAR(50) NOT NULL,\n  engine_count TINYINT NOT NULL,\n  max_weight MEDIUMINT UNSIGNED NOT NULL,\n  wingspan DECIMAL(5,2) NOT NULL,\n  plane_length DECIMAL(5,2) NOT NULL,\n  parking_area INT \n    GENERATED ALWAYS AS ((wingspan * plane_length)) STORED,\n  icao_code CHAR(4) NOT NULL,\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n  last_update TIMESTAMP NOT NULL \n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (plane_id),\n  CONSTRAINT fk_manufacturer_id FOREIGN KEY (manufacturer_id) \n    REFERENCES manufacturers (manufacturer_id) );<\/pre>\n<p>The script will create the <code>travel<\/code> database and add the <code>manufacturers<\/code> and <code>airplanes<\/code> tables in the proper order to accommodate the foreign key defined in the <code>airplanes<\/code> table. After you the create the tables, you can then run the following <code>INSERT<\/code> statements:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO manufacturers (manufacturer_id, manufacturer)\nVALUES (101,'Airbus'), (102,'Beagle Aircraft Limited'), \n  (103,'Beechcraft'), (104,'Boeing');\nINSERT INTO airplanes \n  (plane_id, plane, manufacturer_id, engine_type, engine_count, \n    wingspan, plane_length, max_weight, icao_code)\nVALUES\n  (1001,'A340-600',101,'Jet',4,208.17,247.24,837756,'A346'),\n  (1002,'A350-800 XWB',101,'Jet',2,212.42,198.58,546700,'A358'),\n  (1003,'A350-900',101,'Jet',2,212.42,219.16,617295,'A359'),\n  (1004,'A380-800',101,'Jet',4,261.65,238.62,1267658,'A388'),\n  (1005,'A380-843F',101,'Jet',4,261.65,238.62,1300000,'A38F'),\n  (1006,'A.109 Airedale',102,'Piston',1,36.33,26.33,2750,'AIRD'),\n  (1007,'A.61 Terrier',102,'Piston',1,36,23.25,2400,'AUS6'),\n  (1008,'B.121 Pup',102,'Piston',1,31,23.17,1600,'PUP'),\n  (1009,'B.206',102,'Piston',2,55,33.67,7500,'BASS'),\n  (1010,'D.5-108 Husky',102,'Piston',1,36,23.17,2400,'D5'),\n  (1011,'Baron 56 TC Turbo Baron',103,'Piston',2,37.83,28,5990,'BE56'),\n  (1012,'Baron 58 (and current G58)',103,'Piston',2,37.83,29.83,5500,'BE58'),\n  (1013,'Beechjet 400 (same as MU-300-10 Diamond II)',103,'Jet',2,43.5,48.42,15780,'BE40'),\n  (1014,'Bonanza 33 (F33A)',103,'Piston',1,33.5,26.67,3500,'BE33'),\n  (1015,'Bonanza 35 (G35)',103,'Piston',1,32.83,25.17,3125,'BE35'),\n  (1016,'747-8F',104,'Jet',4,224.42,250.17,987000,'B748'),\n  (1017,'747-SP',104,'Jet',4,195.67,184.75,696000,'B74S'),\n  (1018,'757-300',104,'Jet',2,124.83,178.58,270000,'B753'),\n  (1019,'767-200',104,'Jet',2,156.08,159.17,315000,'B762'),\n  (1020,'767-200ER',104,'Jet',2,156.08,159.17,395000,'B762');<\/pre>\n<p>The <code>INSERT<\/code> statements first populate the <code>manufacturers<\/code> table and then the <code>airplanes<\/code> table. Be sure to run the statements in the order shown here because of the foreign key constraint.<\/p>\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>Frequently Asked Questions (FAQs)<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. How do you export MySQL query results to a CSV file?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use SELECT INTO OUTFILE with FIELDS TERMINATED BY \u2018,\u2019 to create a CSV file: SELECT * FROM table_name INTO OUTFILE \u2018\/path\/to\/output.csv\u2019 FIELDS TERMINATED BY \u2018,\u2019 ENCLOSED BY \u2018&#8221;\u2019 LINES TERMINATED BY \u2018n\u2019. The ENCLOSED BY clause wraps values in quotes (use OPTIONALLY ENCLOSED BY to quote only string columns). The file is created on the MySQL server, not your local machine.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. What does the secure-file-priv error mean in MySQL?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Error 1290 (\u201cThe MySQL server is running with the &#8211;secure-file-priv option\u201d) means MySQL restricts file operations to a specific directory. Run SHOW VARIABLES LIKE \u2018secure_file_priv\u2019 to see the allowed path, then use that directory in your INTO OUTFILE clause. If the variable is empty, file operations are unrestricted. If it\u2019s NULL, file operations are completely disabled and require a MySQL configuration change.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. Can SELECT INTO OUTFILE export to a remote machine?<\/h3>\n            <div class=\"faq-answer\">\n                <p>No. SELECT INTO OUTFILE creates the file on the MySQL server\u2019s filesystem only. To export to a remote machine, you need to either mount a remote filesystem on the server (e.g., NFS or SMB), use mysqldump with the &#8211;tab option, or use a client-side approach like mysql -e \u201cSELECT&#8230;\u201d &gt; file.csv from a remote terminal.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>Complete guide to MySQL SELECT INTO OUTFILE for exporting query results to CSV, TSV, and text files. Covers syntax, FIELDS and LINES clauses, file permissions, secure-file-priv settings, and working examples with custom delimiters.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,145792],"tags":[],"coauthors":[6779],"class_list":["post-97336","post","type-post","status-publish","format-standard","hentry","category-featured","category-mysql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97336","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=97336"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97336\/revisions"}],"predecessor-version":[{"id":110122,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97336\/revisions\/110122"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=97336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=97336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=97336"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=97336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}