none
Por favor, como posso montar esta query? RRS feed

  • Pergunta

  • Caros amigos,

    Eu tenho uma tabela com mais ou menos a seguinte estrutura:

    id_localidade    id_produto    custo
    1                     2                 1.3
    1                     2                 1.6
    1                     2                 1.5
    2                     4                 2.1
    2                     4                 2.3
    2                     4                 2.2

    Eu gostaria de fazer uma SELECT que me retornasse os seguintes registros:

    id_localidade    id_produto    custo
    1                     2                 1.5
    2                     4                 2.2

    Ou seja, o último valor (na ordem de inserção na tabela) para cada combinação de localidade e produto.

    Eu estou tentando:

    SELECT id_localidade, id_produto, ??? FROM tabela GROUP BY id_localidade, id_produto, com isso eu agrupo os campos id_localidade e id_produto, mas não conheço nenhuma função que retorna o último custo encontrado.

    Eu até consegui fazer com uma subquery nesse ???, mas ela fica muito, muito lenta.

    Alguém sabe me dizer como posso montar essa query?

    Obrigado.

    []'s!
    quinta-feira, 8 de janeiro de 2009 17:16

Respostas

  • Olá Jônatas,

     

    Nesse caso é possível, pois, através do ID, podemos afirmar que o "último" é o que tem o maior ID sem depender da ordem física dos registros (que não temos nenhum controle). Veja o exemplo:

     

    Code Snippet

    declare @t table (id int, id_localidade int, id_produto int, custo decimal(2,1))

    insert into @t values (1,1,2,1.3)

    insert into @t values (2,1,2,1.6)

    insert into @t values (3,1,2,1.5)

    insert into @t values (4,2,4,2.1)

    insert into @t values (5,2,4,2.3)

    insert into @t values (6,2,4,2.2)

     

    select t.*

    from @t as t

    inner join (

    select id_localidade, id_produto, max(id) as ultimo_id

    from @t group by id_localidade, id_produto) as u

    on t.id_localidade = u.id_localidade and

    t.id_produto = u.id_produto and

    t.id = u.ultimo_id

    order by t.id

     

    [ ]s,

     

    Gustavo

    http://gustavomaiaaguiar.spaces.live.com

    sexta-feira, 9 de janeiro de 2009 10:06
  • Olá Jônatas,

     

    Visto que essa dúvida está muito recorrente, montei uma explicação detalhada no meu blog.

     

    Como retornar o último registro por grupo ?

    http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!277.entry

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

    segunda-feira, 12 de janeiro de 2009 21:58

Todas as Respostas

  • Olá Jônatas Guimarães,

     

    Da forma como está exposto, sua consulta não é possível de ser realizada.

    Um banco de dados recupera seus dados com base em conjuntos e pode realizar seus filtros com base em determinados critérios. O conjunto {1, 2, 3} é semelhante ao conjunto {2, 1, 3} pois ambos possuem os mesmos membros. Uma vez que a ordem de um conjunto não importe e que não haja nenhum critério para estipular o último custo não é possível retornar a posição desejada.

     

    Só poderemos elaborar a consulta se houver algum critério que diga que o custo 1.5 é o último para a combinação id_localidade 1 e id_produto 2. Não podemos confiar na ordem de inserção física. Se esse critério não existir, não será possível recuperar essa informação de forma confiável.

     

    Normalmente há um identificador seqüencial ou uma coluna de data. Nenhuma dessas está presente ?

     

    [ ]s,

     

    Gustavo

    http://gustavomaiaaguiar.spaces.live.com

     

    quinta-feira, 8 de janeiro de 2009 17:28
  • É SQL Server 2005?

    Caso seja positivo, tente adaptar o código que escrevi abaixo.

     

    Caso você não tenha uma coluna indicando qual é o ultimo registro inserido, pode criar uma usando o ROW_Number...

     

    declare @Tab table(id_localidade Int, id_produto Int, custo Float)

    insert into @Tab(id_localidade, id_produto, custo)

    values(1,2,1.3)

    insert into @Tab(id_localidade, id_produto, custo)

    values(1,2,1.6)

    insert into @Tab(id_localidade, id_produto, custo)

    values(1,2,1.5)

    insert into @Tab(id_localidade, id_produto, custo)

    values(2,4,2.1)

    insert into @Tab(id_localidade, id_produto, custo)

    values(2,4,2.3)

    insert into @Tab(id_localidade, id_produto, custo)

    values(2,4,2.2)

     

    declare @Tab_2 table(ROW Int, id_localidade Int, id_produto Int, custo Float)

     

    insert into @Tab_2

    select ROW_NUMBER() OVER(PARTITION BY id_localidade ORDER BY id_produto DESC) ROW, *

    from @Tab

     

    select a.* from @Tab_2 a

    inner join (select MAX(row) row, id_localidade, id_produto

    from @Tab_2

    group by id_localidade, id_produto) as b

    on a.id_localidade = b.id_localidade

    and a.id_produto = b.id_produto

    and a.Row = b.Row

    order by ID_Localidade, ID_Produto

     

     

    Sabe que achei que ficou bem confuso? rs... bom.. já serve para dar o caminho das pedras.. se tiver alguma dúvida é só falar..

    quinta-feira, 8 de janeiro de 2009 18:43
  • Agradeço desde já a ajuda Gustavo.

    Posso colocar um identificador sim, ficaria algo assim:

    id    id_localidade    id_produto    custo
    1     1                     2                 1.3
    2     1                     2                 1.6
    3     1                     2                 1.5
    4     2                     4                 2.1
    5     2                     4                 2.3
    6     2                     4                 2.2


    Não sei se é exatamente isto que você está falando, mas se for, mesmo desta forma, como eu consigo obter o que eu preciso?

    Grato.

    []'s

    Jônatas
    sexta-feira, 9 de janeiro de 2009 02:27
  • Olá Jônatas,

     

    Nesse caso é possível, pois, através do ID, podemos afirmar que o "último" é o que tem o maior ID sem depender da ordem física dos registros (que não temos nenhum controle). Veja o exemplo:

     

    Code Snippet

    declare @t table (id int, id_localidade int, id_produto int, custo decimal(2,1))

    insert into @t values (1,1,2,1.3)

    insert into @t values (2,1,2,1.6)

    insert into @t values (3,1,2,1.5)

    insert into @t values (4,2,4,2.1)

    insert into @t values (5,2,4,2.3)

    insert into @t values (6,2,4,2.2)

     

    select t.*

    from @t as t

    inner join (

    select id_localidade, id_produto, max(id) as ultimo_id

    from @t group by id_localidade, id_produto) as u

    on t.id_localidade = u.id_localidade and

    t.id_produto = u.id_produto and

    t.id = u.ultimo_id

    order by t.id

     

    [ ]s,

     

    Gustavo

    http://gustavomaiaaguiar.spaces.live.com

    sexta-feira, 9 de janeiro de 2009 10:06
  • Olá Jônatas,

     

    Visto que essa dúvida está muito recorrente, montei uma explicação detalhada no meu blog.

     

    Como retornar o último registro por grupo ?

    http://gustavomaiaaguiar.spaces.live.com/blog/cns!F4F5C630410B9865!277.entry

     

    [ ]s,

     

    Gustavo Maia Aguiar

    http://gustavomaiaaguiar.spaces.live.com

    segunda-feira, 12 de janeiro de 2009 21:58