2

I have in my sql database 2 tables, a table called club and a table called players, they are connected by one to many relationships, the query in node.js works fine but i can not get the last insert of table club , i need to it for insert in the foreign key in the table players

here what i have tried in node.js:



       module.exports={
 create:(data,callback)=>{
  var myArray = new Array();
 /* for(let item of data.players) {
    console.log(item.firstname);
}*/

data.players.forEach((player) => {
  console.log(player.id);
  console.log(player);
  var playerModel ={
    id : player.id,
    firstname : player.firstname,
    lastname : player.lastname,
    position : player.position,
    price : player.price,
    appearences : player.appearences,
    goals : player.goals,
    assists : player.assists,
    cleansheets : player.cleansheets,
    redcards : player.redcards,
    yellowcards : player.yellowcards,
    image : player.image,
    clubid : player.clubid,
  };
  console.log("model"+playerModel.position);
  myArray.push(playerModel);
});
var id;
 
 pool.query(
      'insert into club(userid,name,price) values(?,?,?)',
   [
        data.userid,
        data.name,
        data.price
      ],
    
      (error,result) => {
        if(error){
          callback(error);
         
        }
     /*   id = result.insertId;
        console.error(result);
        console.log(result+"  result");*/
        
        console.log(result.insertId);
        return callback(null,result.insertId);
      },

      
    );



    for(var item of myArray){
    pool.query(
      
      'insert into players(id,firstname,lastname,position,price,appearences,goals,assists,cleansheets,redcards,yellowcards,image,clubid) values (?,?,?,?,?,?,?,?,?,?,?,?,?)',
       [ 
       item.id,
       item.firstname,
       item.lastname,
       item.position,
       item.price,
       item.appearences,
       item.goals,
       item.assists,
       item.cleansheets,
       item.redcards,
       item.yellowcards,
       item.image,
       (
        'select top 1 id from club order by id desc'
        )
       ],
      
 
     (error,results,fields)=>{
       if(error){
         callback(error);
       }
       return callback(null,results);
     },
    );
    }
  },
     

no idea about how to do this

Fares Ben Slama
  • 93
  • 4
  • 15
  • 1
    Send 2 queries as one batch query, and use LAST_INSERT_ID() MySQL function in 2nd query. Execute the batch as single transaction. – Akina Apr 28 '21 at 09:09
  • 1
    understood nothing literally , how to do this in pratics? – Fares Ben Slama Apr 28 '21 at 09:11
  • actually this is a node.js problem , you can see that i retrieved the last inserted id in a value id = results.insertId, but outside the first query it will be undefined , How to place that variable id without getting undefined in the second query??? i mean to pass this value to the second insert – Fares Ben Slama Apr 30 '21 at 10:38

4 Answers4

3

If I understand this correctly, a subquery should work here.

-- first insert the club from paraterized query
insert into club (clubid, name, price) 
values (? , ? , ?);


-- then use a subquery to find the last inserted club id
insert into
   players (id, firstname, lastname, position, price, appearences, goals, assists, cleansheets, redcards, yellowcards, image, clubid) 
values
   (
       ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , 
      (
         select clubid 
         from club 
         order by clubid desc
         limit 1
      )
   )
;

Apart from that, an insert statement doesn't give you any data back. If you are looking to get the ID from the first call in NodeJS, you need to run a batch statement. 1 insert and 1 select, in the same batch of statements that is sent to the SQL server. See more for multi statement config here. node-mysql multiple statements in one query

const pool = mysql.createConnection({multipleStatements: true});
pool.query(`
  insert into club(userid,name,price) values(?,?,?);
  select clubid from club order by clubid desc limit 1;
  `
  , params
  , function(err, results) {
  if (err) throw err;
    // now the id will be the second item of the batch statement result
    const myId = results[1]
});
)

Based on both things, you could combine them, actually.

pool.query(`
  insert into club(userid,name,price) values(?,?,?);
  insert into players (id, firstname, lastname, position, price, appearences, goals, assists, cleansheets, redcards, yellowcards, image, clubid) 
  values
   (
       ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , 
      (
         select clubid 
         from club 
         order by clubid desc
         limit 1
      )
   );
  `
  , params
)

You could also create yourself a stored procedure for this purpose.

The Fool
  • 16,715
  • 5
  • 52
  • 86
  • So in that way the last insert id value will be in second part of my batch?? i respect this way and i will try it , but in general , how to pass a variable from a first part of batch to a second part? why inside the first batch a console.log of the value of id gives me the value i need but outside it the console.log(id) gives me undefined?? – Fares Ben Slama Apr 30 '21 at 10:51
  • Again, you need to run 2 queries in you first nodejs call. A insert will never bring you any id or data back You need to select it. https://stackoverflow.com/questions/23266854/node-mysql-multiple-statements-in-one-query – The Fool Apr 30 '21 at 10:52
  • 1
    i had an error in your solution , Code:ERR_Truncated_Wrong_Value_FOR_FIELD, and an sql message that says incorrect integer value, and in your solution i will update my answer – Fares Ben Slama Apr 30 '21 at 11:00
  • the name of the primary key in table club is id – Fares Ben Slama Apr 30 '21 at 11:02
  • i have added example for batch statement now. – The Fool Apr 30 '21 at 11:21
  • 1
    Doesn't node.js mysql API return the insert ID after insert query, in result, as per https://www.w3schools.com/nodejs/nodejs_mysql_insert.asp ? Doing a SELECT to get last inserted ID becomes more inefficient the larger the table. – Gnudiff Apr 30 '21 at 14:03
  • You are right, but it only works for 1 row at a time and it needs to be an identity column with auto increment. Is now the question do you want to still do it with batch like I show or do you want to grab the id and call the driver method a second time. – The Fool Apr 30 '21 at 17:24
  • 1
    I also wonder how the driver gets this id, maybe there is another implicit select statement anyways. Since insert usually dont return any value. – The Fool Apr 30 '21 at 17:27
  • @TheFool, because mysql2 is a drop in replacement for mysql/mysqljs, (i.e. it adds on promises to the original package iirc), the package shares a lot of the features of node-mysql. One such feature is that the query method holds an 'insertId' method. Use It seems best to store the method in a variable and use Object.entries() to find that properties mapped location. – DeltaFlyer Sep 20 '21 at 02:48
2

Create a multi-query batch, like

INSERT INTO table1 (column1, column2, column3) VALUES (?, ?, ?);
INSERT INTO table2 (column1, reference_column, column3) VALUES (?, LAST_INSERT_ID(), ?);

Execute using a method which:

  1. supports multi-query batch execution
  2. executes the batch as a transaction

The parameters are provided to this method as one solid data array (for shown code it will contain 5 values, first 3 will be inserted into 1st query and all another toi 2nd one). id value assigned by 1st query will be automatically retrieved by the function and inserted into 2nd query.


I don't know what is the method with described properties in Node.JS. But it must exist..

Akina
  • 39,301
  • 5
  • 14
  • 25
  • 1
    so all i have to do is to replace the variable forignkey by LAST_INSERT_ID()? the problem is that i never heard before of something called batch query , here why i said i never understood what you said – Fares Ben Slama Apr 28 '21 at 09:19
  • are you sure that this applies on node.js? – Fares Ben Slama Apr 28 '21 at 09:22
  • 1
    @FaresBenSlama This is a look from database server side. I don't know how this is implemented on the client side but it cannot be non-implemented. – Akina Apr 28 '21 at 09:27
  • node.JS is not that easy to implement a solution like this , i am sure the solution is related to callback, thank you for the help and god help me with it – Fares Ben Slama Apr 28 '21 at 09:29
0

An alternate way to figure this out was placing the initial query holding the first INSERT statement into a variable:

const first_insert = db.query('INSERT')...

Then returning the variable at the end of the first promise, and then finding the property values of the variable (since it returns a javascript object afterall):

.then((first_insert) => {
   console.log(Object.entries(first_insert)); //returns array
   console.log(first_insert[0]); 
/*returns contents of first index of previously returned array, you'll see an object with a insertId property, thats what you need*/
   console.log(first_insert[0].insertId) 
/*this is the value you need to pass to each following statement*/
/*store that value in a variable that you declarre before any of the db methods, I named mine pk*/
   pk = first_insert[0].insertId
/*Now use that variable for the foreign key and to correspond with the placeholder in whatever queries you use*/
}
DeltaFlyer
  • 461
  • 2
  • 8
  • 17
0

How to use this in NodeJS, oracle ? My Error is Error: ORA-00933: SQL command not properly ended.

-- first insert the club from paraterized query

INSERT INTO club (clubid, name, price) 
VALUES (? , ? , ?);

-- then use a subquery to find the last inserted club id

INSERT INTO
   players (id, firstname, lastname, position, price, appearences, goals, assists, cleansheets, redcards, yellowcards, image, clubid) 
VALUES
   (
       ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , 
      (
         SELECT clubid 
         FROM club 
         ORDER BY clubid desc
         LIMIT 1
      )
   )
;
Sebastian
  • 2,472
  • 1
  • 18
  • 31
  • Hi, why duplicate the accepted answer? Please read [how to answer](https://stackoverflow.com/help/how-to-answer) – pierpy Jun 04 '23 at 07:59
  • Creates a race condition. Imagine two processes running in parallel. Both execute the `INSERT INTO club` query and then both execute the second query. Both will use the `clubid` of the last executed `INSERT`. Plus: Not all SQL DBs use sequential primary keys. – Sebastian Jun 05 '23 at 10:26
  • Oracle's bind placeholder syntax is not '?'. Refer to the node-oracledb [Using Bind Variables](https://node-oracledb.readthedocs.io/en/latest/user_guide/bind.html) documentation. – Christopher Jones Jun 06 '23 at 22:57