mysql only execute insert if values exist in other table - mysql

There are a few questions that look a lot like the question below, but i can't find a proper answer.
I want to do an insert in table b, for example ID_b,ID_a, name, name2.
I only want to do the insert if the ID_a exists in table a
Simple question, leading to a headache.

You can use a single insert-select statement for this.
E.g., assume your values for [ID_b, ID_a, name, name2] are [1, 100, 'name', 'name2']:
INSERT INTO b (ID_b, ID_a, name, name2)
SELECT 1, ID_a, 'name', 'name2'
FROM a
WHERE ID_a = 100
If ID_a = 100 exists, the new row will be inserted. If it does not, zero rows will selected from table a, and thus, nothing will inserted into b.

Related

Insert data in mysql from multiple sources

I want to insert values from different sources. For example
insert into a (('id','name','add'),'college')
select from b where id = 1,'abc'
Here there is no timestamp field in table b
I would rewrite your query as follows:
insert into a (id, name, add, college)
select id, name, add, 'abc' from b where id = 1
With this query, the 4th column in a will be assigned a constant value of 'abc'.

multiple insert row if not exists (based on multiple columns)

Imagine an existing table with data (names are self explanatory):
id,name,telephone_1,telephone_2
i want to insert multiple new records with one INSERT (hopefully multiple new records with one insert -if thats a problem i could fall back to insert one-by-one), but i want a new row to be added ONLY if the telephone_1 OR the telephone_2 of the new record does NOT already exist either in telephone_1 OR the telehpone_2 of an existing record.
That means if we have existing data
1, Jimmy, 123, 456
i should not be able to add a
NULL,John,444,123
because John's telephone_2 exists already as telephone_1 of Jimmy.
I'm planning to let mysql do the heavy work instead of my program, but how can i do that? I have done something similar in the past using UNIQUE indexes, but the problem in this case is that the columns are 2. The telephone_1 should not collide with telephone_1 and also should not collide with telephone_2 (and same for telephone_2)
UPDATE-CLARIFICATION: The data i'm trying to insert are not from another table; they are generated on the fly from my program.
Suppose your table name is contacts, then try to insert record:
INSERT INTO contacts(name,telephone_1,telephone_2)
SELECT 'John', 444, 123
FROM contacts
WHERE telephone_1 NOT IN (444, 123)
AND telephone_2 NOT IN (444, 123)
LIMIT 1;
Trick there: if WHERE condition is false then SELECT returns no rows and record is not inserted.
Try here: http://sqlfiddle.com/#!2/5a6e0/1
Try this:
Insert into tableA select * from tableB where tableB.telephone_1 not in (select telephone_1 tableA union select telephone_2 tableA ) AND tableB.telephone_2 not in (select telephone_1 tableA union select telephone_2 tableA )
where
tableA is your main table where you want to insert new record.
tableB is other table from where you want to fetch record

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.

Copy multiple records using foreign keys

Suppose I have two tabels, A and B, each with three columns (A.id, A.title, A.text and B.id, B.a_id, B.text). B.a_id is a foreign key to relates to A.id. Now, suppose there is one record in A (1, 'foo', 'bar') and 2 records in B (1, 1, 'test') and (2, 1, 'test1').
My question is, is there a standard method of copying the record in A, and, at the same time copying all the records from B that relate to A. So suppose I create a new record in A (2, 'foo', 'bar') that's based on (1, 'foo', 'bar'), is there some sort of method that creates two new records in B (3, 2, 'test') and (4, 2, 'test1)?
I've never used triggers before, is this the correct moment to start doing that? Or is this a very stupid question?
this is not a stupid question. However, I believe that this is not possible with pure SQL, or only with some exotic syntax that I am not aware of. Copying rows is not the problem (assuming that id is auto_increment):
insert into A (title, text) select title, text from A where id = XY
However, then you need to find the last insert ID to duplicate the records in B. Let's see:
insert into B (a_id, text) select LAST_INSERT_ID(), text from B where a_id = XY
Hm... maybe this works, but I am a bit sceptical about the LAST_INSERT_ID(). Anyway, I don't think it can be done with just one statement.
Let me know how it goes
Tom

How do I select an ID by its result set or get a better data model?

I'm having a little trouble with a selection and I was figuring I could either look for help in solving the selection or find a better way to model my data. My tables are structured such that:
Table A( a_id, a2, a3, a4) pk: a_id
Table B( b_id, a_id, b3) pk: b_id, a_id
Table B can have any number of entries for each b_id, but only one for each b_id, a_id. I want to be able to reference the set for each b_id to check for their existence so that the set is not duplicated. For example, say I had a tuple in table C
Table C( c_id, b_id ) pk:c_id
with a reference to a b_id of 1. If another tuple was to be inserted into C which results in the insertion of the same set represented by a b_id of 1 into table B, I would want the new tuple to have a b_id of 1, as well, instead of inserting into table B and using that b_id.
edit:
See this sqlfiddle. Say I wanted to insert a new object which is represented by the following inserts:
INSERT INTO B VALUES (3, 1, 2);
INSERT INTO B VALUES (3, 2, 11;
INSERT INTO B VALUES (3, 3, 5);
INSERT INTO C VALUES (2,3);
How can I query the database (or restructure) so that I can realize that the sets in Table B represented by a b_id of 1 or 3 would be the same? I would then want to change my logic so that the object being inserted is represented by the single statement:
INSERT INTO C VALUES (2,1);
A real-world-like example:
Imagine a player in a game. Each player in the game is a tuple in Table C. Each player can where any number of clothes - Table B. A piece of clothing is defined by the part of the body it covers (Table A) and its color (b3)
I want to find the player wearing a specific set of clothing. Lets say that player wore that same set again - I shouldnt have to add more data to table B, I should be able to say he wore it last game, so we'll just reference that set of clothing
You need programming language eg PHP to loop all the conditions:
SELECT B.b_id, BB.num, count(*)
FROM B, (
SELECT b_id, count(*) num
FROM B
WHERE (a_id=1 and b3=1)
OR (a_id=2 and b3=11)
OR (a_id=3 and b3=5)
OR (a_id=4 and b3=6)
-- you need programming language eg php to loop all your set data here
GROUP BY 1
) as BB
WHERE B.b_id = BB.b_id
GROUP BY 1,2
HAVING count(*) = 4 and count(*) = BB.num
-- count(*) should be manually input to match above loop of OR
The sub-query get b_id and count, join back with B to match if they are exactly same.
Which means, you need to provide exactly same set of values [a_id, b3] to get correct value of b_id, not sub-set, not sup-set, exactly match.
In your example data, if you want to return bid=1, you need provide 3 sets of [aid,b3); if you want to return bid=2, you need to provide 4 sets of [aid,b3]
If b_id, a_id do not constitute a unique identity for table B then you don't really have a pk.
Anyways, adding UNIQUE (a_id, b3) to your table B definition will prevent the duplicate entry values:
INSERT INTO B VALUES (3, 1, 2);
INSERT INTO B VALUES (3, 2, 8);
INSERT INTO B VALUES (3, 3, 10);
A foreign key constraint would then prevent:
INSERT INTO C VALUES (2,3);
But I don't think this approach is sufficient for what you are trying to do. For example would the insert into B above be ok if the existing records for B included another record, say 1, 5, 20?