Pegar o ultimo ID Gravado <Resolvido>

Pessoal estou usando banco de dados postgresSQL e nele tenho uma tabela chamada empresa que possue um campo idempres que é auto incremete ou (Serial no postgre) e o banco de dados tem concorrencia, mais de uma pessoa pode dazer a mesma transação.

Eu preciso fazer um insert na tabela empresa e pegar o idempresa que foi gerado e mandar para outra tabela.

Eu fiz uma aplicação do tipo controle e nela no evento onValidateSuccess fiz assim:

/**

  • Insert a record on another table
    */

// SQL statement parameters
$insert_table_empresa = ‘empresa’; // Table name
$insert_fields_empresa = array( // Field list, add as many as needed
‘razao_social’ => “’{razao_social}’”,
‘nome_fantasia’ => “’{nome_fantasia}’”,
‘cnpj’ => “’{cnpj}’”,
‘cep’ => “’{cep}’”,
‘logradouro’ => “’{logradouro}’”,
‘numero’ => “’{numero}’”,
‘bairro’ => “’{bairro}’”,
‘cidade’ => “’{cidade}’”,
‘complemento’ => “’{complemento}’”,
‘uf’ => “’{uf}’”,
‘ramo_de_atividade’ => “’{ramo_de_atividade}’”,
‘tel1’ => “’{tel1}’”,
‘tel2’ => “’{tel2}’”,
‘email’ => “’{email_da_empresa}’”,
‘data_do_cadastro’ => “’{data_do_cadastro}’”,
);

// Insert record 1ª forma de pegar o idempresa é usar o comando RETURNING Currval(‘serial_seq_empresa_idempresa’)
$insert_sql_empresa = “INSERT INTO " . $insert_table_empresa
. " (” . implode(", “, array_keys($insert_fields_empresa)) . “)”
. " VALUES (” . implode(", ", array_values($insert_fields_empresa)) . “) RETURNING Currval(‘serial_seq_empresa_idempresa’)”;

sc_exec_sql($insert_sql_empresa);

Segunda forma que usei foi:
$insert_sql_empresa = “INSERT INTO " . $insert_table_empresa
. " (” . implode(", “, array_keys($insert_fields_empresa)) . “)”
. " VALUES (” . implode(", ", array_values($insert_fields_empresa)) . “) RETURNING idempresa”;

sc_exec_sql($insert_sql_empresa);

como pegar este retorno?

Se eu executar o comando direto no banco funciona:
Exemplo direto no banco:
INSERT INTO empresa (razao_social, nome_fantasia, cnpj, cep, logradouro, numero, bairro, cidade, complemento, uf, ramo_de_atividade, tel1, tel2, email, data_do_cadastro) VALUES (‘zvadvf’, ‘’, ‘18659920000181’, ‘37980000’, ‘w35wetrwer’, ‘2341’, ‘’, ‘Cássia’, ‘’, ‘MG’, ‘’, ‘35354112880’, ‘’, ‘ffwfewfwef@hotmail.com’, ‘20151204’) RETURNING Currval(‘serial_seq_empresa_idempresa’)

ou
INSERT INTO empresa (razao_social, nome_fantasia, cnpj, cep, logradouro, numero, bairro, cidade, complemento, uf, ramo_de_atividade, tel1, tel2, email, data_do_cadastro) VALUES (‘zvadvf’, ‘’, ‘18659920000181’, ‘37980000’, ‘w35wetrwer’, ‘2341’, ‘’, ‘Cássia’, ‘’, ‘MG’, ‘’, ‘35354112880’, ‘’, ‘werwerwer@hotmail.com’, ‘20151204’) RETURNING idempresa

sc_lookup(ds,“SELECT LAST_RECORD_ID”);

Haroldo,
Está não é uma função somente do mysql?
Postgresql tem last_insert_id()?

Recorri ao manual do postgresql:
http://www.postgresql.org/docs/9.4/static/functions-sequence.html
Neste caso acho que terá que usar “currval”.
Exemplo:
SELECT CURRVAL( pg_get_serial_sequence(‘nome_da_sua_tabela’,‘id_nome_da_coluna’)); -> para uma sequência específica
SELECT lastval(); -> para qualquer sequência

A questão de concorrência:
Imagina comigo: eu tenho a tabela empresa com o idempresa que é auto increment(serial no postgres) eu tenho que fazer o insert nela pegar o idempresa gerado e mandar para tabela sec_empresa que tem uma fk_idempresa.
o padrão seria ( insert into empresa (nome) values (empresax)), ai ele iria criar o idempresa = 1 nome=empresax, teria que pegar este idempresa=1 e fazer um ( insert into sec_empresa (fk_idempresa) values (1)), isso funcionaria.

Agora vamos a ideia do nextval e currval:

//aqui como so uma pessoa esta adicionando e não tem concorrência funciona
$oserial = SELECT nextval(‘serial_seq_empresa_idempresa’ ); (imagina que a variavel $oserial vai ser 1)
( insert into empresa (nome) values (empresax)) //vai colocar o serial 1
( insert into sec_empresa (fk_idempresa) values ($oserial)) //vai colocar o serial 1
muito bom é isso mesmo que eu preciso.

Agora vamos pensar com concorrência
João e Maria apertão o botão ao mesmo tempo para cadastrar sua empresa:
$oserial = SELECT nextval(‘serial_seq_empresa_idempresa’ ); (para o joão a variavel $oserial vai ser 1, como maria veio depois vai ser 2)
na hora que eu fizer o insert ( insert into empresa (nome) values (empresax)) do joão que veio na frente na tabela empresa recebera o id 2 porque toda vez que eu executo o comando $oserial = SELECT nextval(‘serial_seq_empresa_idempresa’ ); ele altera o valor da sequencia automaticamente.
ai vai ficar assim:
joão
( insert into empresa (nome) values (empresax)) //vai colocar o serial 2
( insert into sec_empresa (fk_idempresa) values ($oserial)) //vai colocar o serial 1

Maria
( insert into empresa (nome) values (empresax)) //vai colocar o serial 3
( insert into sec_empresa (fk_idempresa) values ($oserial)) //vai colocar o serial 2

se meu pensamento estiver errado me corrijam por favor.

Para evitar isso, na hora de dar o insert grava também a sessão Id do PHP ela é única por usuário acessando o seu sistema,
ai você recupera o registro gerado usando a seção no where:
$a = session_id();

Poderia me passar o seu pensamento, fiquei sem entender como fazer esta lógica.
Seria assim?

$oserial = SELECT nextval(‘serial_seq_empresa_idempresa’ );
$a = session_id();//depois que eu pegar o id da sessão não sei o que fazer, vc falou para colocar no where.

insert into empresa (nome) values (empresax)
insert into sec_empresa (fk_idempresa) values ($oserial)

Esse $a = session_id você vai gravar ele no banco em um novo campo, ai quando você pegar o maior número gerado, você puxa ele junto com o ID no banco, que ele vai te trazer
o ID máximo correto somente daquele usuário no momento que ele deu o INSERT, isso para evitar que 2 usuários gravem o registro ao mesmo tempo e peguem o mesmo ID.

Segundo sua ideia eu fiz o seguinte:
//eu pego o id da sesão e gravo no banco de dados para eliminar concorrencia
$id_da_sessao=session_id();
/**

  • Insert a record on another table
    */

// SQL statement parameters
$insert_table_empresa = ‘empresa’; // Table name
$insert_fields_empresa = array( // Field list, add as many as needed
‘razao_social’ => “’{razao_social}’”,
‘nome_fantasia’ => “’{nome_fantasia}’”,
‘cnpj’ => “’{cnpj}’”,
‘cep’ => “’{cep}’”,
‘logradouro’ => “’{logradouro}’”,
‘numero’ => “’{numero}’”,
‘bairro’ => “’{bairro}’”,
‘cidade’ => “’{cidade}’”,
‘complemento’ => “’{complemento}’”,
‘uf’ => “’{uf}’”,
‘ramo_de_atividade’ => “’{ramo_de_atividade}’”,
‘tel1’ => “’{tel1}’”,
‘tel2’ => “’{tel2}’”,
‘email’ => “’{email_da_empresa}’”,
‘data_do_cadastro’ => “’{data_do_cadastro}’”,
‘sessao_id_temp’ => “’{$id_da_sessao}’”,
);

$insert_sql_empresa = ‘INSERT INTO ’ . $insert_table_empresa
. ’ (’ . implode(’, ‘, array_keys($insert_fields_empresa)) . ‘)’
. ’ VALUES (’ . implode(’, ‘, array_values($insert_fields_empresa)).’)’;

sc_exec_sql($insert_sql_empresa);

/** Selecting a field from another table*/

// Check for record
$check_sql_empresa = “SELECT idempresa”
. " FROM empresa"
. " WHERE sessao_id_temp = ‘" . $id_da_sessao . "’";
sc_lookup(rs_empresa, $check_sql_empresa);

if (isset({rs_empresa[0][0]})) {

$id_empresa = {rs_empresa[0][0]};
$insert_table_sec_user  = 'sec_users';
$insert_fields_sec_user = array(   // Field list, add as many as needed
	'login' => "'{login}'",
	'active' => "'{Active}'",
	'priv_admin' => "'{Priv_Admin}'",
	'pswd' => "'{pswd}'",
	'name' => "'{name}'",
	'email' => "'{email}'",
	'empresa_idempresa' => "' $id_empresa'",
);

$insert_sql_sc_user = 'INSERT INTO ' . $insert_table_sec_user
	. ' ('   . implode(', ', array_keys($insert_fields_sec_user))   . ')'
	. ' VALUES ('    . implode(', ', array_values($insert_fields_sec_user)) . ')';

sc_exec_sql($insert_sql_sc_user);

}else{
// No row found
//para eu estudar - agora deveria eu colocar aqui um delet caso falhe a inserção no banco sec_users?
}

sc_commit_trans();
sc_redir(‘app_sec_Login’);

Olha se era esta sua ideia.

Sim é isso mesmo.

O postgresql já faz isso por sessão !! ou seja os insert de joão não vai interferir nos insert de maria.

Se o João fez insert e recebeu 1
e logo depois maria fez insert e recebeu 2
se joão fizer o nextval ou currval ate o mesmo o lastval vai receber 3, 1 e 1
note que ele recebeu 3 pelo nextval. mas ate ele fazer outro insert o currval e o lastval vai voltar 1
não importando quantos insert a maria fez.

Interessante.

@Paulo Reis, sabes se o SQL server tbm faz isso?

Abraço