none
SQL server - Cómo seleccionar el primer registro de varios repetidos y ejecutar formula para ese registro?

    Question

  • Hola,
    Tengo la siguiente información:

    ARTICULO   DISPONIBLE   BODEGA   
    XXCC                 10           01
    XXCC                 15           02
    ASFGR                 5           01
    FJJHYT                 8           01                
    FJJHYT                20          02  

    Realicé una consulta donde coloca una columna con el valor unitario para los artículos,

    SELECT P.ARTICULO, P.DISPONIBLE, P.BODEGA, (P.VL*4) AS VALUNIT
    FROM PRECIOART P INNER JOIN
        PRECIOART R ON P.ARTICULO=R.ARTICULO
    WHERE P.ARTICULO=R.ARTICULO

    el resultado debe ser el siguiente:



    ARTICULO   DISPONIBLE   BODEGA  VALUNIT 
    XXCC                 10           01                10
    XXCC                 15           02
    ASFGR                 5           01                 20
    FJJHYT                 8           01                 30
    FJJHYT                20          02                  

    Es decir en la columna VALUNIT solo debe colocar la información en el primer registro encontrado.
    Pero al ejecutar el select, en la columna VALUNIT le esta colcando el calculo a todos los registros...

    Existe alguna forma para poder colocar ese calculo como es requerido?

    Muchas gracias

    Wednesday, April 22, 2009 5:06 PM

Answers

  • Karlier, definitavemente con la instruccion ROW_NUMBER() me hubiera ahorrado lineas y creacion de tabla temporal, pero finalmente pude sacar la información como era requerida.
    Tomando como referencia la página que me enviaste

    Cree la tabla temporal con un campo que sirviera como id, inserté la información de los artículos, posteriormente realice la consulta.
    No soy muy diestro en sql, pero comparto la consulta por si alguien requiere realizar algo similar o mejorarla.


    SELECT T1.ARTICULO,T1.DISPONIBLE ,T1.BODEGA,
    CONSECUTIVO =
    (
     SELECT COUNT(DISTINCT T2.IDITEM)
     FROM DBO.TABLAART T2
     WHERE T2.ARTICULO = T1.ARTICULO
     AND T2.IDITEM <= T1.IDITEM
    )
    ,
    VALUNIT=
    CASE WHEN (
     SELECT COUNT(DISTINCT T2.IDITEM)
     FROM DBO.TABLAART T2
     WHERE T2.ARTICULO = T1.ARTICULO
    AND T2.IDITEM <= T1.IDITEM
    )=1
    THEN (P.VL*4) ELSE '0' END
    FROM DBO.TABLAART T1
    ORDER BY T1.ARTICULO

    Con esta consulta, solo el articulo con consecutivo= 1 tomará el valor del cálculo de la columna VALUNIT

    • Marked as answer by OSCAR_AM Friday, April 24, 2009 5:13 PM
    Friday, April 24, 2009 5:12 PM

All replies

  • Hola.

    Tienes dos opciones. Si siempre es la BODEGA "01" la que debe llevar el valor, es más fácil:

    SELECT P.ARTICULO, P.DISPONIBLE, P.BODEGA, 
    case P.BODEGA when '01' then (P.VL*4) end AS VALUNIT
    FROM PRECIOART P INNER JOIN
        PRECIOART R ON P.ARTICULO=R.ARTICULO
    WHERE P.ARTICULO=R.ARTICULO 
    Por cierto, el "where" que pones es redundante, no hace falta que lo pongas. 

    Si no siempre es '01', si no la menor de las del artículo, se complica un poco, aunque no mucho. Debes agrupar antes y cruzar la tabla. Sería más o menos así. Primero hay que saber cuál es la mínima bodega para cada artículo:

    SELECT P.ARTICULO, min(P.BODEGA) as minBODEGA, 
    FROM PRECIOART P INNER JOIN
        PRECIOART R ON P.ARTICULO=R.ARTICULO
    GROUP BY P.ARTICULO
    Eso lo cruzas con tu consulta original y cuando la bodega sea la mínima, pues le calculas la función:

    SELECT P.ARTICULO, P.DISPONIBLE, P.BODEGA, 
    case when P.BODEGA = G.minBODEGA then (P.VL*4) end AS VALUNIT
    FROM PRECIOART P INNER JOIN
        PRECIOART R ON P.ARTICULO=R.ARTICULO
    WHERE P.ARTICULO=R.ARTICULO INNER JOIN
    (SELECT P.ARTICULO, min(P.BODEGA) as minBODEGA, 
    FROM PRECIOART P INNER JOIN
        PRECIOART R ON P.ARTICULO=R.ARTICULO
    GROUP BY P.ARTICULO) G on P.ARTICULO = G.ARTICULO
    Y eso sería. Lo he hecho a mano alzada, a lo mejor hay algún error de sintaxis.

    Alberto López Grande

    Wednesday, April 22, 2009 7:01 PM
    Moderator
  • Hola OSCAR_AM

    Creo que esto es más simplificado:

    SELECT ROW_NUMBER() OVER
           (PARTITION BY ARTICULO ORDER BY BODEGA DESC) AS 'Row_Number',
           ARTICULO, DISPONIBLE, BODEGA, 
           CASE 
             WHEN ROW_NUMBER() OVER
                  (PARTITION BY ARTICULO ORDER BY BODEGA DESC) = 1 
               THEN VL *4
             ELSE NULL
           END VALUNIT
      FROM PRECIOART
    
    
    Contempla que tu bodega sea o no '01'

    Nota: puedes eliminar si deseas la columna 'Row_Number', la deje para ilustrar mejor el ejemplo.

    Saludos :)
    Anwar Karlier - MCTS SQL 2005
    • Edited by Karlier Wednesday, April 22, 2009 9:14 PM formato
    Wednesday, April 22, 2009 9:10 PM
  • Anwar gracias por tu respuesta, infortunadamente tengo sql 2000, y no tiene la función ROW_NUMBER ()
    Estoy buscando el equivalente en SQL 2000.
    Nuevamente muchas gracias.
    Thursday, April 23, 2009 3:04 PM
  • Alberto gracias por responder, me ha dado algunas ideas, estaré realizando las pruebas y comentaré el resultado.

    Oscar_AM
    Thursday, April 23, 2009 3:07 PM
  • Oscar revisa este link: http://www.sqlusa.com/bestpractices/sequencesubset/ (es la alternativa a la función ROW_NUMBER() de 2005)

    Puedes hacer tu secuencia primero, depositarlo en una temporal y luego simplemente hacer el CASE.

    Suerte!
    Anwar Karlier - MCTS SQL 2005
    Thursday, April 23, 2009 3:22 PM
  • Karlier, definitavemente con la instruccion ROW_NUMBER() me hubiera ahorrado lineas y creacion de tabla temporal, pero finalmente pude sacar la información como era requerida.
    Tomando como referencia la página que me enviaste

    Cree la tabla temporal con un campo que sirviera como id, inserté la información de los artículos, posteriormente realice la consulta.
    No soy muy diestro en sql, pero comparto la consulta por si alguien requiere realizar algo similar o mejorarla.


    SELECT T1.ARTICULO,T1.DISPONIBLE ,T1.BODEGA,
    CONSECUTIVO =
    (
     SELECT COUNT(DISTINCT T2.IDITEM)
     FROM DBO.TABLAART T2
     WHERE T2.ARTICULO = T1.ARTICULO
     AND T2.IDITEM <= T1.IDITEM
    )
    ,
    VALUNIT=
    CASE WHEN (
     SELECT COUNT(DISTINCT T2.IDITEM)
     FROM DBO.TABLAART T2
     WHERE T2.ARTICULO = T1.ARTICULO
    AND T2.IDITEM <= T1.IDITEM
    )=1
    THEN (P.VL*4) ELSE '0' END
    FROM DBO.TABLAART T1
    ORDER BY T1.ARTICULO

    Con esta consulta, solo el articulo con consecutivo= 1 tomará el valor del cálculo de la columna VALUNIT

    • Marked as answer by OSCAR_AM Friday, April 24, 2009 5:13 PM
    Friday, April 24, 2009 5:12 PM