Insert in MYSQL multiple rows with one common value - mysql

I'm trying to do a select from one table and insert the return values into another table with a common value representing the search parameter using the insert/select function. For simplicities sake instead of...
INSERT INTO tbl_name (a,b) VALUES (1,1,1), (4,5,6);
I want to do something like this....
INSERT INTO tbl_name (a,b) VALUES (1), (4,5,6);
Except where the second column b has several hundred values and 'a' is the common value. I've tried using SET for 'a' but either this can't be done or I can't get the syntax correct. The reason I'm doing this is to avoid building up an insert function in PHP. Here is the best I have....
INSERT INTO tbl_name
(a,b)
SET a = '1'
SELECT c
FROM tbl_name2
WHERE `d` LIKE '%word%'

I might be missing the point, but doing:
INSERT INTO tbl_name (a,b) (SELECT 1,c FROM tbl_name2 WHERE d like '%word%';);
will do the job.

OK I FIGURED IT OUT, already typed all of this, might as well post the answer for everyone.
INSERT INTO tbl_name
(a,b)
SELECT "2", c
FROM tbl_name2
WHERE d LIKE '%word%'

Related

Can I loop through a table inserting a value from each row in an insert statment? [duplicate]

I am trying to INSERT INTO a table using the input from another table. Although this is entirely feasible for many database engines, I always seem to struggle to remember the correct syntax for the SQL engine of the day (MySQL, Oracle, SQL Server, Informix, and DB2).
Is there a silver-bullet syntax coming from an SQL standard (for example, SQL-92) that would allow me to insert the values without worrying about the underlying database?
Try:
INSERT INTO table1 ( column1 )
SELECT col1
FROM table2
This is standard ANSI SQL and should work on any DBMS
It definitely works for:
Oracle
MS SQL Server
MySQL
Postgres
SQLite v3
Teradata
DB2
Sybase
Vertica
HSQLDB
H2
AWS RedShift
SAP HANA
Google Spanner
Claude Houle's answer: should work fine, and you can also have multiple columns and other data as well:
INSERT INTO table1 ( column1, column2, someInt, someVarChar )
SELECT table2.column1, table2.column2, 8, 'some string etc.'
FROM table2
WHERE table2.ID = 7;
I've only used this syntax with Access, SQL 2000/2005/Express, MySQL, and PostgreSQL, so those should be covered. It should also work with SQLite3.
To get only one value in a multi value INSERT from another table I did the following in SQLite3:
INSERT INTO column_1 ( val_1, val_from_other_table )
VALUES('val_1', (SELECT val_2 FROM table_2 WHERE val_2 = something))
Both the answers I see work fine in Informix specifically, and are basically standard SQL. That is, the notation:
INSERT INTO target_table[(<column-list>)] SELECT ... FROM ...;
works fine with Informix and, I would expect, all the DBMS. (Once upon 5 or more years ago, this is the sort of thing that MySQL did not always support; it now has decent support for this sort of standard SQL syntax and, AFAIK, it would work OK on this notation.) The column list is optional but indicates the target columns in sequence, so the first column of the result of the SELECT will go into the first listed column, etc. In the absence of the column list, the first column of the result of the SELECT goes into the first column of the target table.
What can be different between systems is the notation used to identify tables in different databases - the standard has nothing to say about inter-database (let alone inter-DBMS) operations. With Informix, you can use the following notation to identify a table:
[dbase[#server]:][owner.]table
That is, you may specify a database, optionally identifying the server that hosts that database if it is not in the current server, followed by an optional owner, dot, and finally the actual table name. The SQL standard uses the term schema for what Informix calls the owner. Thus, in Informix, any of the following notations could identify a table:
table
"owner".table
dbase:table
dbase:owner.table
dbase#server:table
dbase#server:owner.table
The owner in general does not need to be quoted; however, if you do use quotes, you need to get the owner name spelled correctly - it becomes case-sensitive. That is:
someone.table
"someone".table
SOMEONE.table
all identify the same table. With Informix, there's a mild complication with MODE ANSI databases, where owner names are generally converted to upper-case (informix is the exception). That is, in a MODE ANSI database (not commonly used), you could write:
CREATE TABLE someone.table ( ... )
and the owner name in the system catalog would be "SOMEONE", rather than 'someone'. If you enclose the owner name in double quotes, it acts like a delimited identifier. With standard SQL, delimited identifiers can be used many places. With Informix, you can use them only around owner names -- in other contexts, Informix treats both single-quoted and double-quoted strings as strings, rather than separating single-quoted strings as strings and double-quoted strings as delimited identifiers. (Of course, just for completeness, there is an environment variable, DELIMIDENT, that can be set - to any value, but Y is safest - to indicate that double quotes always surround delimited identifiers and single quotes always surround strings.)
Note that MS SQL Server manages to use [delimited identifiers] enclosed in square brackets. It looks weird to me, and is certainly not part of the SQL standard.
Two approaches for insert into with select sub-query.
With SELECT subquery returning results with One row.
With SELECT subquery returning results with Multiple rows.
1. Approach for With SELECT subquery returning results with one row.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
VALUES ('DUMMY1', (SELECT <field> FROM <table_name> ),'DUMMY2');
In this case, it assumes SELECT Sub-query returns only one row of result based on WHERE condition or SQL aggregate functions like SUM, MAX, AVG etc. Otherwise it will throw error
2. Approach for With SELECT subquery returning results with multiple rows.
INSERT INTO <table_name> (<field1>, <field2>, <field3>)
SELECT 'DUMMY1', <field>, 'DUMMY2' FROM <table_name>;
The second approach will work for both the cases.
To add something in the first answer, when we want only few records from another table (in this example only one):
INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4)
VALUES (value1, value2,
(SELECT COLUMN_TABLE2
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);
Instead of VALUES part of INSERT query, just use SELECT query as below.
INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
Most of the databases follow the basic syntax,
INSERT INTO TABLE_NAME
SELECT COL1, COL2 ...
FROM TABLE_YOU_NEED_TO_TAKE_FROM
;
Every database I have used follow this syntax namely, DB2, SQL Server, MY SQL, PostgresQL
This can be done without specifying the columns in the INSERT INTO part if you are supplying values for all columns in the SELECT part.
Let's say table1 has two columns. This query should work:
INSERT INTO table1
SELECT col1, col2
FROM table2
This WOULD NOT work (value for col2 is not specified):
INSERT INTO table1
SELECT col1
FROM table2
I'm using MS SQL Server. I don't know how other RDMS work.
This is another example using values with select:
INSERT INTO table1(desc, id, email)
SELECT "Hello World", 3, email FROM table2 WHERE ...
Just use parenthesis for SELECT clause into INSERT. For example like this :
INSERT INTO Table1 (col1, col2, your_desired_value_from_select_clause, col3)
VALUES (
'col1_value',
'col2_value',
(SELECT col_Table2 FROM Table2 WHERE IdTable2 = 'your_satisfied_value_for_col_Table2_selected'),
'col3_value'
);
Simple insertion when table column sequence is known:
Insert into Table1
values(1,2,...)
Simple insertion mentioning column:
Insert into Table1(col2,col4)
values(1,2)
Bulk insertion when number of selected columns of a table(#table2) are equal to insertion table(Table1)
Insert into Table1 {Column sequence}
Select * -- column sequence should be same.
from #table2
Bulk insertion when you want to insert only into desired column of a table(table1):
Insert into Table1 (Column1,Column2 ....Desired Column from Table1)
Select Column1,Column2..desired column from #table2
from #table2
Here is another example where source is taken using more than one table:
INSERT INTO cesc_pf_stmt_ext_wrk(
PF_EMP_CODE ,
PF_DEPT_CODE ,
PF_SEC_CODE ,
PF_PROL_NO ,
PF_FM_SEQ ,
PF_SEQ_NO ,
PF_SEP_TAG ,
PF_SOURCE)
SELECT
PFl_EMP_CODE ,
PFl_DEPT_CODE ,
PFl_SEC ,
PFl_PROL_NO ,
PF_FM_SEQ ,
PF_SEQ_NO ,
PFl_SEP_TAG ,
PF_SOURCE
FROM cesc_pf_stmt_ext,
cesc_pfl_emp_master
WHERE pfl_sep_tag LIKE '0'
AND pfl_emp_code=pf_emp_code(+);
COMMIT;
Here's how to insert from multiple tables. This particular example is where you have a mapping table in a many to many scenario:
insert into StudentCourseMap (StudentId, CourseId)
SELECT Student.Id, Course.Id FROM Student, Course
WHERE Student.Name = 'Paddy Murphy' AND Course.Name = 'Basket weaving for beginners'
(I realise matching on the student name might return more than one value but you get the idea. Matching on something other than an Id is necessary when the Id is an Identity column and is unknown.)
You could try this if you want to insert all column using SELECT * INTO table.
SELECT *
INTO Table2
FROM Table1;
I actually prefer the following in SQL Server 2008:
SELECT Table1.Column1, Table1.Column2, Table2.Column1, Table2.Column2, 'Some String' AS SomeString, 8 AS SomeInt
INTO Table3
FROM Table1 INNER JOIN Table2 ON Table1.Column1 = Table2.Column3
It eliminates the step of adding the Insert () set, and you just select which values go in the table.
This worked for me:
insert into table1 select * from table2
The sentence is a bit different from Oracle's.
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;
This works on all DBMS
For Microsoft SQL Server, I will recommend learning to interpret the SYNTAX provided on MSDN. With Google it's easier than ever, to look for syntax.
For this particular case, try
Google: insert site:microsoft.com
The first result will be http://msdn.microsoft.com/en-us/library/ms174335.aspx
scroll down to the example ("Using the SELECT and EXECUTE options to insert data from other tables") if you find it difficult to interpret the syntax given at the top of the page.
[ WITH <common_table_expression> [ ,...n ] ]
INSERT
{
[ TOP ( expression ) [ PERCENT ] ]
[ INTO ]
{ <object> | rowset_function_limited
[ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
}
{
[ ( column_list ) ]
[ <OUTPUT Clause> ]
{ VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n ]
| derived_table <<<<------- Look here ------------------------
| execute_statement <<<<------- Look here ------------------------
| <dml_table_source> <<<<------- Look here ------------------------
| DEFAULT VALUES
}
}
}
[;]
This should be applicable for any other RDBMS available there. There is no point in remembering all the syntax for all products IMO.
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT COLUMN_NAME
FROM ANOTHER_TABLE_NAME
WHERE CONDITION;
Best way to insert multiple records from any other tables.
INSERT INTO dbo.Users
( UserID ,
Full_Name ,
Login_Name ,
Password
)
SELECT UserID ,
Full_Name ,
Login_Name ,
Password
FROM Users_Table
(INNER JOIN / LEFT JOIN ...)
(WHERE CONDITION...)
(OTHER CLAUSE)
select *
into tmp
from orders
Looks nice, but works only if tmp doesn't exists (creates it and fills). (SQL sever)
To insert into existing tmp table:
set identity_insert tmp on
insert tmp
([OrderID]
,[CustomerID]
,[EmployeeID]
,[OrderDate]
,[RequiredDate]
,[ShippedDate]
,[ShipVia]
,[Freight]
,[ShipName]
,[ShipAddress]
,[ShipCity]
,[ShipRegion]
,[ShipPostalCode]
,[ShipCountry] )
select * from orders
set identity_insert tmp off
IF you want to insert some data into a table without want to write column name.
INSERT INTO CUSTOMER_INFO
(SELECT CUSTOMER_NAME,
MOBILE_NO,
ADDRESS
FROM OWNER_INFO cm)
Where the tables are:
CUSTOMER_INFO || OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS || CUSTOMER_NAME | MOBILE_NO | ADDRESS
--------------|-----------|--------- || --------------|-----------|---------
A | +1 | DC || B | +55 | RR
Result:
CUSTOMER_INFO || OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS || CUSTOMER_NAME | MOBILE_NO | ADDRESS
--------------|-----------|--------- || --------------|-----------|---------
A | +1 | DC || B | +55 | RR
B | +55 | RR ||
If you go the INSERT VALUES route to insert multiple rows, make sure to delimit the VALUES into sets using parentheses, so:
INSERT INTO `receiving_table`
(id,
first_name,
last_name)
VALUES
(1002,'Charles','Babbage'),
(1003,'George', 'Boole'),
(1001,'Donald','Chamberlin'),
(1004,'Alan','Turing'),
(1005,'My','Widenius');
Otherwise MySQL objects that "Column count doesn't match value count at row 1", and you end up writing a trivial post when you finally figure out what to do about it.
If you create table firstly you can use like this;
select * INTO TableYedek From Table
This metot insert values but differently with creating new copy table.
In informix it works as Claude said:
INSERT INTO table (column1, column2)
VALUES (value1, value2);
Postgres supports next:
create table company.monitor2 as select * from company.monitor;

Mysql Insert if not exist in two column

I looked into MySQL duplicate key but cant figure it out.
I have a table like below:
id series chapter path(can be unique)
I want only insert data and not update. Lets say I have data like below:
seri:Naruto, klasor:567 ==> If both of these exist in table then do not insert.
seri:Naruto, klasor:568 ==> If Naruto exist but 568 does not exist then do insert.
How can I achieve this?
Easiest way would be to define unique index with two columns on that table:
ALTER TABLE yourtable ADD UNIQUE INDEX (seri,klasor);
You may also define two column primary key, which would work just as well.
Then use INSERT IGNORE to only add rows when they will not be duplicates:
INSERT IGNORE INTO yourtable (seri, klasor) VALUES ('Naruto',567);
INSERT IGNORE INTO yourtable (seri, klasor) VALUES ('Naruto',568);
Edit: As per comments, you can't use UNIQUE INDEX which complicates things.
SET #seri='Naruto';
SET #klasor=567;
INSERT INTO yourtable
SELECT seri,klasor FROM (SELECT #seri AS seri, #klasor AS klasor)
WHERE NOT EXISTS (SELECT seri, klasor FROM yourtable WHERE seri=#seri AND klasor=#klasor);
You may use the above query with two local variables or convert it to single statement by replacing the local variables with actual values.
Better way would be to use stored procedure:
CREATE PROCEDURE yourinsert (vseri VARCHAR(8), vklasor INT)
BEGIN
DECLARE i INT;
SELECT COUNT(*) INTO i FROM yourtable WHERE seri=vseri AND klasor=vklasor;
IF i=0 THEN
INSERT INTO yourtable (seri,klasor) VALUES (vseri, vklasor);
END IF;
END;
This would allow you to perform the INSERT using:
CALL yourinsert('Naruto',567);
INSERT INTO table_name (seri, klasor) VALUES ('Naruto',567)
WHERE NOT EXISTS( SELECT seri,klasor FROM table_name WEHERE seri='Naruto' AND klasor=567
)
Hope this helps..

MySQL: Select from coma separated list / list as table? "SELECT a FROM (1, 2, 3)"

Is it possible to do something like this (obviously this syntax does not work):
SELECT a FROM (1, 2, 3)
to get this:
| a |
+---+
| 1 |
| 2 |
| 3 |
?
That is I want to make rows from coma separated list, without using any table, or at least without creating table in db (maybe this is possible using something like temporary table?).
Maybe it is possible to get column of given values without using select, that is using some other sql statment? If it is not possible in MySQL, but possible in some other SQL it still would be interesting to know.
SELECT 1 a UNION ALL SELECT 2 a UNION ALL SELECT 3 a;
Would a temporary table be an option? Then I would have a suggestion which, admittedly, has more than 1 query:
-- DROP TEMPORARY TABLE tmp_list IF EXISTS;
CREATE TEMPORARY TABLE tmp_list (a INT);
INSERT INTO tmp_list (a) VALUES (1), (2), (3);
SELECT a FROM tmp_list;
If it is not possible in MySQL, but possible in some other SQL it still would be interesting to know.
In standard SQL this would be something like this
select *
from ( values (1), (2), (3) ) t
This works at least in PostgreSQL and DB2.
In PostgreSQL you can give the column a name by extending the alias (not sure if that column aliasing is part of the SQL standard).
select *
from ( values (1), (2), (3) ) t (id)
The following is an alternative to the above using a common table expression.
with my_values (id) as (
values (1), (2), (3)
)
select *
from my_values;
Since MariaDB v10.3.3 and MySQL v8.0.19 you can now do exactly that!
See docs: MariaDB, MySQL
MariaDB:
WITH mylist (a) AS (VALUES (1),(2),(3))
SELECT a FROM mylist
I used a WITH here because MariaDB doesn't supply nice column names for VALUES .... You can use it in a union without column names:
SELECT 1 AS a UNION ALL VALUES (2),(3)
And although the docs don't appear to mention it, you can even use it as a top-level query:
VALUES (1),(2),(3) ORDER BY 1 DESC
The actual column names are in fact the just first row of values, so you can even do this (though it's inelegant, and you can run into duplicate column name errors):
SELECT `4` AS a FROM (VALUES (4),(5),(6)) mylist
MySQL:
I don't have an instance of MySQL v8.0.19 to test against right now, but according to the docs [EDIT: Tested successfully on MySQL v8.0.23 using dbfiddle.uk, see links in comment #2] either of these should work:
SELECT column_0 AS a FROM (VALUES ROW(1), ROW(2), ROW(3)) mylist
SELECT a FROM (VALUES ROW(1), ROW(2), ROW(3)) mylist(a)
Unlike MariaDB, MySQL supplies automatic column names column_0, column_1, column_2, etc., and also supports renaming all of a subquery's columns when referencing it.
I'm not sure, but this dev worklog page seems to suggest that MySQL has also implemented [EDIT: not implemented yet, as of v8.0.26] the shorter sytax (omitting "ROW", like MariaDB), or that they might at some poiint in the near future.

INSERT INTO with SubQuery MySQL

I have this Statement:
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
VALUES (1, 2, (SELECT item_costprice FROM qa_items WHERE item_code = 1));
I'm trying to insert a value copy the same data of item_costprice, but show me the error:
Error Code: 1136. Column count doesn't match value count at row 1
How i can solve this?
Use numeric literals with aliases inside a SELECT statement. No () are necessary around the SELECT component.
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
SELECT
/* Literal number values with column aliases */
1 AS item_code,
2 AS invoice_code,
item_costprice
FROM qa_items
WHERE item_code = 1;
Note that in context of an INSERT INTO...SELECT, the aliases are not actually necessary and you can just SELECT 1, 2, item_costprice, but in a normal SELECT you'll need the aliases to access the columns returned.
You can just simply e.g.
INSERT INTO modulesToSections (fk_moduleId, fk_sectionId, `order`) VALUES
((SELECT id FROM modules WHERE title="Top bar"),0,-100);
I was disappointed at the "all or nothing" answers. I needed (again) to INSERT some data and SELECT an id from an existing table.
INSERT INTO table1 (id_table2, name) VALUES ((SELECT id FROM table2 LIMIT 1), 'Example');
The sub-select on an INSERT query should use parenthesis in addition to the comma as deliminators.
For those having trouble with using a SELECT within an INSERT I recommend testing your SELECT independently first and ensuring that the correct number of columns match for both queries.
Your insert statement contains too many columns on the left-hand side or not enough columns on the right hand side. The part before the VALUES has 7 columns listed, but the second part after VALUES only has 3 columns returned: 1, 2, then the sub-query only returns 1 column.
EDIT: Well, it did before someone modified the query....
As a sidenote to the good answer of Michael Berkowski:
You can also dynamically add fields (or have them prepared if you're working with php skripts) like so:
INSERT INTO table_a(col1, col2, col3)
SELECT
col1,
col2,
CURRENT_TIMESTAMP()
FROM table_B
WHERE b.col1 = a.col1;
If you need to transfer without adding new data, you can use NULL as a placeholder.
If you have multiple string values you want to add, you can put them into a temporary table and then cross join it with the value you want.
-- Create temp table
CREATE TEMPORARY TABLE NewStrings (
NewString VARCHAR(50)
);
-- Populate temp table
INSERT INTO NewStrings (NewString) VALUES ('Hello'), ('World'), ('Hi');
-- Insert desired rows into permanent table
INSERT INTO PermanentTable (OtherID, NewString)
WITH OtherSelect AS (
SELECT OtherID AS OtherID FROM OtherTable WHERE OtherName = 'Other Name'
)
SELECT os.OtherID, ns.NewString
FROM OtherSelect os, NewStrings ns;
This way, you only have to define the strings in one place, and you only have to do the query in one place. If you used subqueries like I initially did and like Elendurwen and John suggest, you have to type the subquery into every row. But using temporary tables and a CTE in this way, you can write the query only once.

Execute INSERT if table is empty?

Is there a way to do an insert under a count condition, something like:
INSERT INTO my_table (colname) VALUES('foo') IF COUNT(my_table) < 1
Basically I want to insert a single default record if the table is currently empty. I'm using mysql.
Use SELECT instead of VALUES to be able to expand the query with a WHERE clause.
EXISTS is a better & faster test than COUNT
INSERT INTO my_table (colname)
SELECT 'foo'
WHERE NOT EXISTS (SELECT * FROM my_table)
One way would be to place a unique key on a column. Then execute a REPLACE:
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name [(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
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
This is easier to read:
INSERT INTO my_table (colname)
SELECT 'foo' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM my_table);
The lack of a VALUES is mitigated by the SELECT FROM DUAL which will provide the values. the FROM DUAL is not always required, but it doesn't hurt to include it for that weird configurations where it is required (like the installation of Percona I am using).
The NOT EXISTS is faster than doing a count which can be slow on a table with a large number of rows.