none
Atribuir valor de Select em uma variavel RRS feed

  • Pergunta

  • Sou iniciante em VB.NET e SQLSERVER e tenho a seguinte duvida:
    Como faço para atribuir o valor de um Select dentro de uma variavel em uma procedure? Isso é possível?

    EX:
    @IdFuncionario = Select MAX(id_funcionario) from tb_funcionario

    Tem como eu fazer uma atribuição assim dentro de uma procedure, pois preciso desse valor para inserir em outra tabela, desse jeito não esta funcionando, o que estou fazendo de errado? Ou não é possivel fazer uma atribuição desta forma?


    quarta-feira, 14 de maio de 2008 19:30

Respostas

  •  

    tenta assim

     

     declare @IdFuncionario int

     

      Select @IdFuncionario = MAX(id_funcionario) from tb_funcionario

    quarta-feira, 14 de maio de 2008 19:36
  • Olá RF.NET,

     

    É possível sim. Há duas formas. Ex:

     

    Code Snippet

    CREATE TABLE #tblTMP (VALOR INT, NOME VARCHAR(20))

    INSERT INTO #tblTMP VALUES (1,'Nome 1')

    INSERT INTO #tblTMP VALUES (2,'Nome 2')

     

     

    Você pode fazer

     

    Code Snippet

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SET @VALOR = (SELECT VALOR FROM #tblTMP WHERE VALOR = 1)

    SET @NOME = (SELECT NOME FROM #tblTMP WHERE VALOR = 1)

     

     

    Ou

     

    Code Snippet

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SELECT @VALOR = VALOR, @NOME = NOME FROM #tblTMP WHERE VALOR = 1

    SELECT @VALOR, @NOME

     

     

    A segunda forma nesse caso é bem mais performática, já que ao invés de fazer duas pesquisas fez apenas uma. No entanto considere a seguinte situação

     

    Code Snippet

    -- Gera um erro

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SET @VALOR = (SELECT VALOR FROM #tblTMP)

    SET @NOME = (SELECT NOME FROM #tblTMP)

     

    -- Permite uma resposta

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SELECT @VALOR = VALOR, @NOME = NOME FROM #tblTMP

    SELECT @VALOR, @NOME

     

     

    Nesse caso, um SELECT trará dois registros e portanto dois valores. Como estamos falando de uma variável que deve ser atômica (um valor), a opção de SET é mais segura por avisar do erro enquanto a opção de SELECT permitirá um erro que pode levar a problemas futuros (não dá pra saber qual valor o SELECT iria pegar nesse caso).

     

    Por isso recomendo fazer as atribuições sempre com SET (esse é ANSI Compliance) e deixar o SELECT apenas para casos de recuperações de múltiplos valores na mesma linha.

     

    [ ]s,

     

    Gustavo

    quarta-feira, 14 de maio de 2008 19:51

Todas as Respostas

  •  

    tenta assim

     

     declare @IdFuncionario int

     

      Select @IdFuncionario = MAX(id_funcionario) from tb_funcionario

    quarta-feira, 14 de maio de 2008 19:36
  • A variavel ja foi declarada, mas quando eu tento executar o código aparece o seguinte erro:

    Incorrect syntax near the keyword 'Select'.
    quarta-feira, 14 de maio de 2008 19:45
  • Olá RF.NET,

     

    É possível sim. Há duas formas. Ex:

     

    Code Snippet

    CREATE TABLE #tblTMP (VALOR INT, NOME VARCHAR(20))

    INSERT INTO #tblTMP VALUES (1,'Nome 1')

    INSERT INTO #tblTMP VALUES (2,'Nome 2')

     

     

    Você pode fazer

     

    Code Snippet

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SET @VALOR = (SELECT VALOR FROM #tblTMP WHERE VALOR = 1)

    SET @NOME = (SELECT NOME FROM #tblTMP WHERE VALOR = 1)

     

     

    Ou

     

    Code Snippet

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SELECT @VALOR = VALOR, @NOME = NOME FROM #tblTMP WHERE VALOR = 1

    SELECT @VALOR, @NOME

     

     

    A segunda forma nesse caso é bem mais performática, já que ao invés de fazer duas pesquisas fez apenas uma. No entanto considere a seguinte situação

     

    Code Snippet

    -- Gera um erro

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SET @VALOR = (SELECT VALOR FROM #tblTMP)

    SET @NOME = (SELECT NOME FROM #tblTMP)

     

    -- Permite uma resposta

    DECLARE @VALOR INT, @NOME VARCHAR(20)

    SELECT @VALOR = VALOR, @NOME = NOME FROM #tblTMP

    SELECT @VALOR, @NOME

     

     

    Nesse caso, um SELECT trará dois registros e portanto dois valores. Como estamos falando de uma variável que deve ser atômica (um valor), a opção de SET é mais segura por avisar do erro enquanto a opção de SELECT permitirá um erro que pode levar a problemas futuros (não dá pra saber qual valor o SELECT iria pegar nesse caso).

     

    Por isso recomendo fazer as atribuições sempre com SET (esse é ANSI Compliance) e deixar o SELECT apenas para casos de recuperações de múltiplos valores na mesma linha.

     

    [ ]s,

     

    Gustavo

    quarta-feira, 14 de maio de 2008 19:51
  • Aqui esta o código em que eu estou trabalhando, talvez fique mais facil de entender o que eu quero

    Code Snippet
    ALTER PROC  [RH].[spu_Colaborador_Ins]
       (@txt_tipoPessoa as char(1),
        @txt_pessoa as varchar(200),
        @IdPessoaRelacionada as Integer = null,
        @IdTipoRelacionamento as Integer,
        @IdPessoa as Integer = -1,
        @IdDepartamento as integer,
        @IdCargo as integer,
        @dtInicio as datetime = null,
        @dtFim as datetime = null)
    as

        declare @retorno varchar(800)

    if(@IdPessoa = -1) -- insert
    begin

        set @retorno = 'Cadastrando Colaborador'

         exec  [Pessoa].[spu_Pessoa_ins]
        @txt_tipoPessoa = @txt_tipoPessoa ,
        @txt_pessoa  = @txt_pessoa,
        @IdPessoaRelacionada = @IdPessoaRelacionada,
        @IdTipoRelacionamento = @IdTipoRelacionamento,
        set @IdPessoa = (Select MAX(id_pessoa) from pessoa.tb_pessoa)
     


    end
    if(@IdPessoa > -1 )
    begin

       set @retorno = 'Alterando Colaborador'
        update rh.tb_DepartamentoCargo set dt_fim = dateadd(day,-1,@dtInicio)  where id_pessoa =  @IdPessoa and dt_fim is null

      insert into rh.tb_DepartamentoCargo
        (id_pessoa, id_departamento, id_cargo, dt_inicio, dt_fim)
        values (@IdPessoa, @IdDepartamento, @IdCargo, @dtInicio, @dtFim)

     
    end

    select @IdPessoa as IdPessoa, @retorno as Mensagem



    quarta-feira, 14 de maio de 2008 20:04
  • Essa  [Pessoa].[spu_Pessoa_ins] e uma outra Procedure em que faço o insert nas outras duas tabelas
    quarta-feira, 14 de maio de 2008 20:06
  • Olá,

     

    Acho que temos uma vírgula sobrando. Ao invés de

     

    exec  [Pessoa].[spu_Pessoa_ins]
        @txt_tipoPessoa = @txt_tipoPessoa ,
        @txt_pessoa  = @txt_pessoa,
        @IdPessoaRelacionada = @IdPessoaRelacionada,
        @IdTipoRelacionamento = @IdTipoRelacionamento,
        set @IdPessoa = (Select MAX(id_pessoa) from pessoa.tb_pessoa)

     

    Tente

     

    exec  [Pessoa].[spu_Pessoa_ins]
        @txt_tipoPessoa = @txt_tipoPessoa ,
        @txt_pessoa  = @txt_pessoa,
        @IdPessoaRelacionada = @IdPessoaRelacionada,
        @IdTipoRelacionamento = @IdTipoRelacionamento,
        set @IdPessoa = (Select MAX(id_pessoa) from pessoa.tb_pessoa)

     

    [ ]s,

     

    Gustavo

     

    quarta-feira, 14 de maio de 2008 20:08
  • Mas tem uma virgula ali aonde vc mostrou, ele continua apontando:

    Incorrect syntax near the keyword 'set'
    quarta-feira, 14 de maio de 2008 20:18
  • Oi,

     

    Esqueci de retirá-la na segunda parte. Retire a vírgula que está em vermelho e tente novamente.

     

    [ ]s,

     

    Gustavo

     

    quarta-feira, 14 de maio de 2008 20:29
  • Vlw pela dica, deu certo mesmo ...

    Pra mim que to começando esse forum vai ser util ...
    Vlw mesmo !!!
    quarta-feira, 14 de maio de 2008 20:34
  • Mas eu estava pensando essa forma tbm serve, caso varios usuarios cadastrem ao mesmo tempo?
    quarta-feira, 14 de maio de 2008 20:39
  • Olá RF.NET,

     

    Seja bem vindo. Fique a vontade para postar dúvidas de SQL Server.

    Pedimos também que sempre que uma resposta ajudá-lo que você a classifique.

     

    Isso ajudára a resposta a ser encontrada mais rapidamente nos mecanismos de busca além de beneficiar o autor da solução.

     

    [ ]s,

     

    Gustavo

     

    quarta-feira, 14 de maio de 2008 20:41
  • Pq ela pega o ultimo ID cadastrado, mas ela me da certeza, de que esse ultimo ID, fui eu que cadastrei?
    quarta-feira, 14 de maio de 2008 20:41
  • Olá RF.NET,

     

    Infelizmente da forma como está, não é possível ter essa garantia (a menos que ninguém esteja inserindo junto com você). Essa é uma das fortes limitações de implementações do tipo MAX + 1. Você teria que utilizar um mecanismo de Identity ou então partir para níveis de bloqueios mais fortes para garantir que é o seu ID (o que não recomendo).

     

    No caso do Identity, é possível garantir o retorno do valor que você inseriu através do @@identity. Posso postar um exemplo se você quiser.

     

    [ ]s,

     

    Gustavo

     

    quarta-feira, 14 de maio de 2008 20:55
  • Se vc postasse me ajudaria muito, eu agradeceria ...
    quarta-feira, 14 de maio de 2008 21:00
  • Pq a minha intenção na verdade não é pegar o ultimo cadastrado e sim e pegar esse que eu acabei de cadastrar de inicio pensei que pegar o ultimo seria util, mas vi que preciso de outra forma ...
    quarta-feira, 14 de maio de 2008 21:12
  • Ok, vamos lá,

     

    - Abra uma janela (chamarei de J1) e digite o seguinte código:

    Code Snippet

    -- Cria uma tabela

    CREATE TABLE tblTMP (CODIGO INT IDENTITY(1,1), NOME VARCHAR(20))

    -- Insere um registro

    INSERT INTO tblTMP (NOME) VALUES ('Algum Nome')

     

     

    -- Abra outra janela (chamarei de J2) e digite o seguinte código

    Code Snippet

    -- Insere um registro

    INSERT INTO tblTMP (NOME) VALUES ('Outro Nome')

     

     

    -- Volte para J1 e digite o código

    Code Snippet

    -- Traz erroneamente o maior código como 2 (o código digitado foi 1)

    SELECT MAX(CODIGO) AS MAIORCODIGO FROM tblTMP

    -- Recupera corretamente o ID

    SELECT @@Identity

     

     

    Observe que dessa forma, independente de quantos usuários concorrentes existirem, você pegará o valor que você inseriu. Para aprender mais sobre Identity verifique o link abaixo:

     

    http://www.plugmasters.com.br/sys/materias/836/1/SQL-Server%3A-Gera%E7%E3o-de-seq%FCenciais-de-forma-autom%E1tica

     

    [ ]s,

     

    Gustavo

    quarta-feira, 14 de maio de 2008 21:56
  • VLW, muito obrigado, vc me ajudou bastante!!!
    quarta-feira, 14 de maio de 2008 22:13
  • Gustavo vlw, ja aprendi algumas coisas importantes nessas dicas que vc me deu, mas assim,  ainda continuo tendo problemas com essa procedure, pq o Select @@Identity está me retornando um valor nulo, eu testei ele aqui, e em outras ocasiões eu consegui usa-lo e entender a sua utilidade, mas não sei se estou utilizando ele de maneira errada, ou ainda esta faltando algo para que ele funcione na minha procedure, o modo como estou utilizando o Select @@Identity está assim:

    Code Snippet

    exec  [Pessoa].[spu_Pessoa_ins]
        @txt_tipoPessoa = @txt_tipoPessoa ,
        @txt_pessoa  = @txt_pessoa,
        @IdPessoaRelacionada = @IdPessoaRelacionada,
        @IdTipoRelacionamento = @IdTipoRelacionamento
        set @IdPessoa = (Select @@Identity)


    quinta-feira, 15 de maio de 2008 15:42
  • Olá RF.NET,

     

    Eu imaginei que você fosse chegar nessa situação, mas estamos desfocando o Post já que a dúvida original não era essa. Você poderia postar um novo post ? Esse já está muito carregado.

     

    [ ]s,

     

    Gustavo

     

    quinta-feira, 15 de maio de 2008 17:23