Lo que necesito es una fecha para el próximo día (lunes, martes, Miércoles…) después de la fecha de hoy.

El usuario puede seleccionar qué día siguiente que ellos quieren y que se almacena como un entero en una tabla. «Me llaman el próximo martes (3)»

Sunday = 1
Monday = 2
Tuesday = 3
...

Así que mi mesa se parece a esto.

UserID, NextDayID

Lo que he llegado es:

select dateadd(dd,(7 - datepart(dw,GETDATE()) + NextDayID ) % 7, getdate())

Parece que funciona y volverá a la fecha de hoy si usted pide que para la próxima que cualquier día de hoy es que puedo agregar a la semana si es necesario.

Lo que me pregunto es, ¿es una buena solución o hay algo que me estoy perdiendo?

OriginalEl autor Josh | 2013-09-20

4 Comentarios

  1. 18

    1) la solución utiliza un no-determinista de la función: datepart(dw...) . Debido a este aspecto, el cambio de DATEFIRST configuración le da diferentes resultados. Por ejemplo, usted debe tratar de:

    SET DATEFIRST 7;
    your solution;

    y, a continuación,

    SET DATEFIRST 1;
    your solution;

    2) Siguiente solución es independiente de DATEFIRST/LANGUAGE configuración:

    DECLARE @NextDayID INT  = 0 -- 0=Mon, 1=Tue, 2 = Wed, ..., 5=Sat, 6=Sun
    SELECT DATEADD(DAY, (DATEDIFF(DAY, @NextDayID, GETDATE()) / 7) * 7 + 7, @NextDayID) AS NextDay

    Resultado:

    NextDay
    -----------------------
    2013-09-23 00:00:00.000

    Esta solución se basa en la siguiente propiedad de DATETIME tipo:

    • Día 0 = 19000101 = Mon

    • Día 1 = 19000102 = Tue

    • Día 2 = 19000103 = Wed

    • Día 5 = 19000106 = Sat

    • Día 6 = 19000107 = Sol

    Así, la conversión de INT valor de 0 a DATETIME da 19000101.

    Si quieres encontrar la siguiente Wednesday, a continuación, usted debe comenzar a partir del día 2 (19000103/Wed), calcular los días entre el día 2 y el día actual (20130921; 41534 días), dividir por 7 (con el fin de obtener el número de semanas completas; 5933 semanas), múltiples 7 (41531 fays; con el fin de obtener el número de días – semanas entre la primera Wednesday/19000103 y el último Wednesday) y, a continuación, añadir 7 días (una semana; 41538 días; con el fin de obtener la siguiente Wednesday). Añadir a este número (41538 días) a la fecha de comienzo: 19000103.

    Nota: mi fecha actual es 20130921.

    Editar #1:

    DECLARE @NextDayID INT;
    SET @NextDayID = 1; -- Next Sunday
    SELECT DATEADD(DAY, (DATEDIFF(DAY, ((@NextDayID + 5) % 7), GETDATE()) / 7) * 7 + 7, ((@NextDayID + 5) % 7)) AS NextDay

    Resultado:

    NextDay
    -----------------------
    2013-09-29 00:00:00.000 

    Nota: mi fecha actual es 20130923.

    Me gusta que la solución mejor sólo deseo que podría utilizar el Sol como el primer día de la semana. ¿Tienes una sugerencia para hacer eso? Puedo usar el lunes como el primer día de la semana si es necesario.
    Edición #1 que me consigue los mismos resultados que la mía, pero me gusta más porque no tengo el uso de la no-determinista de la función como usted ha dicho (yo no era consciente de que parte de datepart/datefirst hasta ahora), y me permite mantener los días en un fácil entender el orden para el usuario final. Gracias bogdan.

    OriginalEl autor Bogdan Sahlean

  2. 0

    Un calendario de mesa es una alternativa al uso de un montón de funciones de fecha y fecha de la aritmética. Un mínimo de calendario de mesa para este problema en particular podría ser algo como esto.

    2013-09-20  Fri
    2012-09-21  Sat
    2012-09-22  Sun
    2012-09-23  Mon
    2012-09-24  Tue
    ...

    Para una consulta para obtener el próximo lunes podría tener este aspecto.

    select min(cal_date)
    from calendar
    where cal_date > current_date
      and day_of_week = 'Mon';

    En la práctica, usted probablemente querrá mucho más columnas en el calendario de la tabla, porque vas a encontrar una gran cantidad de usos.

    También, el código que utiliza un calendario de la tabla general puede ser visto para ser obviamente correcta. La lectura de el código anterior es simple: seleccionar el mínimo de fecha de calendario de que a partir de hoy y que cae en lunes. Es bastante raro ver el código que depende de las funciones de fecha y fecha de la aritmética a la que evidentemente correcta.

    Un calendario de la tabla en PostgreSQL

    ¿La actualización de la tabla anual, a continuación, o sólo te llene con 100 años de datos?
    Rellenar con 100 años de datos. Con más de 50 años de datos, que es lo que tengo en este equipo, la consulta se ejecuta en .050 ms. Buenos índices son importantes.

    OriginalEl autor Mike Sherrill ‘Cat Recall’

  3. 0

    La siguiente función permite generar la tabla sobre la marcha…así es como yo suelo hacerlo…no me gusta la idea de un perm fecha de tabla…parece innecesario, pero cada persona y cada situación son diferentes 🙂

    CREATE function [dbo].[fxDateTable]
    (
        @begindate datetime = null
    ,   @enddate datetime = null
    )
    RETURNS @dates TABLE
    (
                EventDate datetime primary key not null
    )
    as
    begin
        select @enddate = isnull(@enddate, getdate())
        select @begindate = isnull(@begindate, dateadd(day, -3, @enddate))
    
        insert @dates
        select dateadd(day, number, @begindate)
        from 
            (select distinct number from master.dbo.spt_values
             where name is null
            ) n
        where dateadd(day, number, @begindate) < @enddate
    
        return
    end

    OriginalEl autor Ron Hudson

  4. 0

    Es una vieja pregunta. Pero estoy seguro de que la publicación de una mejor solución de la pena.

    -- 0 = 1st Mon, 1 = 1st Tue, 2 = 1st Wed, ..., 5 = 1st Sat, 6 = 1st Sun
    -- 7 = 2nd Mon, 8 = 2nd Tue, ...
    declare @NextDayID int = 0, @Date date = getdate()
    
    select cast (cast (
        -- last Monday before [Date] inclusive, starting from 1900-01-01
        datediff (day, @NextDayID % 7, @Date) / 7 * 7
        -- shift on required number of days
        + @NextDayID + 7
        as datetime) as date)

    Esta solución es la mejora de la solución de @Bogdan Sahlean.
    Puede operar @NextDayID que es mayor que 6.
    Así que usted puede, por ejemplo, encontrar 2do lunes a partir de hoy.

    Siguiente consulta muestra que mi solución funciona correctamente.

    select [Date]
    , convert (char(5), [0], 10) as Mon1
    , convert (char(5), [1], 10) as Tue1
    , convert (char(5), [2], 10) as Wed1
    , convert (char(5), [3], 10) as Thu1
    , convert (char(5), [4], 10) as Fri1
    , convert (char(5), [5], 10) as Sat1
    , convert (char(5), [6], 10) as Sun1
    , convert (char(5), [7], 10) as Mon2
    , convert (char(5), [8], 10) as Tue2
    from (
    select [Date], NextDayID
    , cast (cast (
    datediff (day, NextDayID % 7, [Date]) / 7 * 7 -- last Monday before [Date] inclusive, starting from 1900-01-01
    + NextDayID + 7 -- shift on required number of days
    as datetime) as date) as NextDay
    from (
    select datefromparts (2018, 5, dt) as [Date]
    from (values(14),(15),(16),(17),(18),(19),(20))t_(dt)
    ) d
    cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8))nd(NextDayID)
    ) t
    pivot (
    min (NextDay) for NextDayID in ([0], [1], [2], [3], [4], [5], [6], [7], [8])
    ) pvt

    Resultado:

    Date       | Mon1  | Tue1  | Wed1  | Thu1  | Fri1  | Sat1  | Sun1  | Mon2  | Tue2
    -----------+-------+-------+-------+-------+-------+-------+-------+-------+------
    2018-05-14 | 05-21 | 05-15 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-22
    2018-05-15 | 05-21 | 05-22 | 05-16 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
    2018-05-16 | 05-21 | 05-22 | 05-23 | 05-17 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
    2018-05-17 | 05-21 | 05-22 | 05-23 | 05-24 | 05-18 | 05-19 | 05-20 | 05-28 | 05-29
    2018-05-18 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-19 | 05-20 | 05-28 | 05-29
    2018-05-19 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-20 | 05-28 | 05-29
    2018-05-20 | 05-21 | 05-22 | 05-23 | 05-24 | 05-25 | 05-26 | 05-27 | 05-28 | 05-29

    Esta solución no depende de @@datefirst.

    OriginalEl autor GriGrim

Dejar respuesta

Please enter your comment!
Please enter your name here