none
Usar CASE en funciones escalares de sql server 2008 RRS feed

  • Pregunta

  • Un saludo.

    Estoy tratando de desarrollar una función escalar que devuelva las horas nocturnas (van desde las 22:00 a las 6:00) entre 2 fechas. Me sería muy útil usar algo parecido al SELECT CASE de vb.net, pero no sé como hacerlo. Hace muchos años, lo hice en VBA. Era algo así:

             Select Case TimeValue(Entrada)
                Case #12:00:00 AM# To #5:59:00 AM#
                    Nocturnidad = (DateDiff("N", TimeValue(Entrada), #6:00:00 AM#)) / 60
               
                    Select Case TimeValue(Salida)
                        Case #12:00:00 AM# To #6:00:00 AM#
                            Nocturnidad = Nocturnidad + ((DateDiff("N", #6:00:00 AM#, TimeValue(Salida)))) / 60
                            Exit Function
                       
                        Case #10:00:00 PM# To #11:59:00 PM#
                            Nocturnidad = Nocturnidad + ((DateDiff("N", #10:00:00 PM#, TimeValue(Salida)))) / 60
                            Exit Function
                       
                        Case Else
                            Exit Function
                    End Select
               
                Case #10:00:00 PM# To #11:59:00 PM#
                    Nocturnidad = (DateDiff("N", TimeValue(Entrada), #10:00:00 PM#)) / 60
                    Nocturnidad = Nocturnidad + ((DateDiff("N", #10:00:00 PM#, TimeValue(Salida)))) / 60
                    Exit Function
               
                Case #6:00:00 AM# To #9:59:00 PM#
                    Select Case TimeValue(Salida)
                        Case #10:00:00 PM# To #11:59:00 PM#
                            Nocturnidad = Nocturnidad + ((DateDiff("N", #10:00:00 PM#, TimeValue(Salida)))) / 60
                            Exit Function
                        Case Else
                            Exit Function
                    End Select
            End Select

    Como es bastante compleja porque hay que manejar varios tramos horarios, ¿Alguien puede indicarme como transcribirlo?

    Gracias.

     


    Miguel Ángel Muñoz


    lunes, 21 de julio de 2014 11:15

Respuestas

Todas las respuestas

  • En TSQL Tambien existe el Case, se aplica a los select, la documentacion y sintaxis la tienes aqui

    http://msdn.microsoft.com/es-es/library/ms181765.aspx

    lunes, 21 de julio de 2014 12:28
  • Gracias por la respuesta, pero la verdad es que creo que no me va a servir. Tendré que usar el IF. En cuanto intento establecer valores de variables dentro de las sentencias CASE me da un error. Ejemplo:

    declare  @Inicio smalldatetime, 
    @Fin smalldatetime, 
    @Parcial as decimal(6,2), 
    @HEntrada time(7), 
    @HSalida time(7)
    	set @Inicio = '1/7/2014 22:10'
    	set @Fin = '1/7/2014 23:00'
    	set @HEntrada =@Inicio 
    	set @HSalida =@Fin 
    
    
    	SET @Parcial =
    	CASE 
          WHEN @HEntrada <= '5:59'  THEN				  
    		CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
          WHEN @HEntrada <= '21:59'  THEN  
    		CONVERT(DECIMAL,((DateDiff(MI , '22:00', @HSalida ))))
          WHEN @HEntrada <= '00:00'  THEN  
    		CONVERT(DECIMAL,(DateDiff(MI , @HENTRADA, '22:00'))) / 60           
    	END

    Esto me vale para ir controlando las horas de entrada, pero como también debo controlar las de salida, cuando intento lo siguiente, provoca un error

          WHEN @HEntrada <= '5:59'  THEN				  
    		CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
    		if @HSalida >'06:00'
    			CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
    
    Al parecer no se pueden insertar líneas de código entre las sentencias CASE, lo que lo hace inútil para mi propósito. ¿Estoy en lo cierto?


    Miguel Ángel Muñoz

    lunes, 21 de julio de 2014 15:37
  • Por favor sé más especifico que no somos adivinos, que error te aparece? y a que te refieres cuando dices "no puedo insertar lineas de código entre las sentencias CASE"?

    El case en SQL se para bifurcar resultados del select, si lo que pretendes es bifurcar el código que se debe ejecutar debes anidar IF ELSE IF..

    No se si es lo que quiere lograr, pero si estas esperando que ese script retorne algun dato, podría ser esto?

    declare  @Inicio smalldatetime, 
    @Fin smalldatetime, 
    @Parcial as decimal(6,2), 
    @HEntrada time(7), 
    @HSalida time(7)
    	set @Inicio = '1/7/2014 22:10'
    	set @Fin = '1/7/2014 23:00'
    	set @HEntrada =@Inicio 
    	set @HSalida =@Fin 
    
    
    	SET @Parcial =
    	CASE 
          WHEN @HEntrada <= '5:59:59'  THEN				  
    		CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
          WHEN @HEntrada <= '21:59:59'  THEN  
    		CONVERT(DECIMAL,((DateDiff(MI , '22:00', @HSalida ))))
          WHEN @HEntrada <= '23:59:59'  THEN  
    		CONVERT(DECIMAL,(DateDiff(MI , @HENTRADA, '22:00'))) / 60           
    	end
        
    	select @Parcial

    lunes, 21 de julio de 2014 18:07
  • Ronald, si sobre lo que has propuesto, hago este cambio

    	SET @Parcial =
    	CASE 
          WHEN @HEntrada <= '5:59:59'  THEN				  
    		CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
    		if @HSalida >'06:00' --intento controlar cualquier otra variable
    			set @Parcial =22
          WHEN @HEntrada <= '21:59:59'  THEN  
    		CONVERT(DECIMAL,((DateDiff(MI , '22:00', @HSalida ))))
          WHEN @HEntrada <= '23:59:59'  THEN  
    		CONVERT(DECIMAL,(DateDiff(MI , @HENTRADA, '22:00'))) / 60           
    	end

    me lanza este error:

    Mens. 156, Nivel 15, Estado 1, Lnea 16

    Sintaxis incorrecta cerca de la palabra clave 'if'.

    Mens. 156, Nivel 15, Estado 1, Lnea 18

    Sintaxis incorrecta cerca de la palabra clave 'WHEN'.

    Insisto, en que aparte de bifurcar con cada WHEN tal condición, debo controlar otros valores de las variables para seguir bifurcando.


    Miguel Ángel Muñoz

    lunes, 21 de julio de 2014 18:19
  •  crea mas rangos para conseguir eso

    declare  @Inicio smalldatetime, 
    @Fin smalldatetime, 
    @Parcial as decimal(6,2), 
    @HEntrada time(7), 
    @HSalida time(7)
    	set @Inicio = '1/7/2014 22:10'
    	set @Fin = '1/7/2014 23:00'
    	set @HEntrada =@Inicio 
    	set @HSalida =@Fin 
    
    
    	SET @Parcial =
    	CASE 
          WHEN @HEntrada <= '5:59:59'  THEN				  
    		CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60 
    	  when @HSalida >= '06:00' and @HEntrada < '21:59:59' then 
    			22 
          WHEN @HEntrada <= '21:59:59'  THEN  
    		CONVERT(DECIMAL,((DateDiff(MI , '22:00', @HSalida ))))
          WHEN @HEntrada <= '23:59:59'  THEN  
    		CONVERT(DECIMAL,(DateDiff(MI , @HENTRADA, '22:00'))) / 60           
    	end
        
    	select @Parcial
    El problema que yo veo es que solapas horarios, en tus preguntas, armando bien los rangos de horas sin solaparlos, debería solucionar el problema.


    lunes, 21 de julio de 2014 18:49
  • En realidad, estoy modificando la función basándome en la que desarrollé hace años en VBA. Lo estoy haciendo de una forma parecida a la que propones, pero con sentencias IF:

    --ENTRADAS ENTRE LAS 00:00 Y LAS 5:59
    	IF (@HEntrada BETWEEN '00:00' AND '5:59') and (@HSalida BETWEEN '00:00' AND '06:00') --ENTRE 00:00 Y 5:59 (CON NOCTURNIDAD)
    			SET @PARCIAL = isnull(@PARCIAL,0) + CONVERT(DECIMAL,((DateDiff(MI , @HEntrada, @HSalida)))) / 60
    	IF (@HEntrada BETWEEN '00:00' AND '5:59') and (@HSalida BETWEEN '6:00' AND '22:00')
    			SET @Parcial  = CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60
    	IF (@HEntrada BETWEEN '00:00' AND '5:59') and (@HSalida > '22:00')
    			SET @Parcial  = (CONVERT(DECIMAL,(DateDiff(MI , @HEntrada, '6:00'))) / 60 ) + CONVERT(DECIMAL,((DateDiff(MI, '22:00', @HSalida)))) / 60
    

    Ahora sí me está funcionando correctamente, aunque la forma que has descrito es mucho más elegante. Lo que ocurre es que no estoy acostumbrado a trabajar con este tipo de condicionales en SQL. Tendré que practicar bastante y acostumbrarme.

    Muy agradecido por tu ayuda, Ronald.


    Miguel Ángel Muñoz

    lunes, 21 de julio de 2014 19:14
  • Antes de terminar, ¿sería mucha molestia que me indicaras cómo se escribe este mismo bloque con CASE? Si sigo tu ejemplo, igual me queda claro y lo termino de esa forma. En cualquier caso, no es mi intención molestarte más. Gracias de nuevo.

    Miguel Ángel Muñoz

    lunes, 21 de julio de 2014 19:18