sql >> Base de Datos >  >> RDS >> Mysql

combinar datos de futuros mensuales con series de tiempo del mes anterior en MySQL

Requiere mucha verificación previa, pero en esencia, tuve que construir variables SQL basadas en un paso a la vez, como si fuera un programa de "let X =something", "let y =X + somethingelse". , etc. Al construir las variables @SQLVars más internas, una vez que se declara la primera, se puede usar como base de la siguiente variable y así sucesivamente... Primero, aquí está la consulta completa que puede aplicar a sus datos que se construyen basado en cualquiera que sea la fecha actual. Si conoce mejor sus datos, es posible que deba modificarlos un poco, pero creo que esto lo ayudará a avanzar.

select
      CONCAT( 'Q (', LEFT( MonthName( DateBasis.dMonth1 ), 3 ), ' ', RIGHT( Year( DateBasis.dMonth1 ), 2 ), ')' ) as FirstMonth,
      CONCAT( 'U (', LEFT( MonthName( DateBasis.dMonth2 ), 3 ), ' ', RIGHT( Year( DateBasis.dMonth2 ), 2 ), ')' ) as SecondMonth,
      CONCAT( 'V (', LEFT( MonthName( DateBasis.dMonth3 ), 3 ), ' ', RIGHT( Year( DateBasis.dMonth3 ), 2 ), ')' ) as ThirdMonth,
      CONCAT( 'X (', LEFT( MonthName( DateBasis.dMonth4 ), 3 ), ' ', RIGHT( Year( DateBasis.dMonth4 ), 2 ), ')' ) as FourthMonth
   from   
      ( select @FirstOfMonth dFirstOfMonth,
               @FDOM nWeekDay,
               @SWOM nSecondWedOfMonth,
               @SkipMonths nSkip,
               @Month1 dMonth1,
               @Month2 dMonth2,
               @Month3 dMonth3,
               @Month4 dMonth4
           from
              ( select @FirstOfMonth := CONCAT( year(curdate()), '-', month( curdate()), '-01' ),
                       @FDOW := DayOfWeek( @FirstOfMonth ),
                       @SWOM := if( @FDOW <= 4, 12, 19) - @FDOW,
                       @SkipMonths := if( day( CurDate()) <= @SWOM, 1, 2 ),
                       @Month1 := date_add( @FirstOfMonth, interval 0 +  @SkipMonths month ),
                       @Month2 := date_add( @Month1, interval 1 month ),
                       @Month3 := date_add( @Month2, interval 1 month ),
                       @Month4 := date_add( @Month3, interval 1 month )
                       ) sqlvars
      ) DateBasis

El resultado de esta consulta anterior devolverá un registro ÚNICO (basado en la fecha actual del 31 de enero) para mostrarPrimerMes SegundoMes TercerMes CuartoMesQ (12 de marzo) U (12 de abril) V (12 de mayo) X (12 de junio)

Ahora, anide esto dentro del resto de su consulta para sus ID de ticker algo así como

SELECT hist.date, 
       hist.ticker_id, 
       hist.settle_price, 
       hist.volume 
   FROM 
      hist,
      ( entire select statement above ) FinalDates

   WHERE 
          hist.ticker_id IN ( FinalDates.FirstMonth,
                              FinalDates.SecondMonth,
                              FinalDates.ThirdMonth,
                              FinalDates.FourthMonth )
      and hist.trade_dt = curdate()

Si observa las @SqlVariables más internas como se mencionó anteriormente, es como un montón de "let x =something". Siempre necesito una base para comenzar, así que primero obtengo el primer día de un mes determinado en una variable @FirstOfMonth al hacer una concatenación de lo que sea el año de la fecha actual + "-" + mes de la fecha actual + "-01" para comenzar siempre en el primer día del mes... p. ej.:Hoy es 31 de enero de 2012 generará una cadena de '2012-01-01' que en formato de año/mes/fecha es reconocida inmediatamente por MySQL como formato de fecha en el que podemos realizar operaciones aritméticas. Así que ahora tengo @FirstOfMonth ='2012-01-01'. Ahora, necesitamos determinar el primer día de la semana que representa esta fecha del mes en el que estamos (por lo tanto, @FDOW). Esto devolverá un valor de 1 a 7 (domingo =1, miércoles =4, sábado =7).

A partir de esto, ahora necesitamos calcular cuándo será el segundo miércoles del mes. Si el día de la semana es de domingo a miércoles (incluido), el SEGUNDO miércoles es 12 días MENOS el día de la semana. Ej:el domingo 1 sería el miércoles 4, luego el miércoles 11... entonces 12 - 1 (domingo) =11. Si el primer día del mes FUE un miércoles, sería un día de la semana =4, pero el 1 del mes =miércoles, el segundo miércoles =8, entonces 12 - 4 =8. Ahora, si la fecha fuera jueves, viernes o sábado como el primero del mes, el día de la semana sería un 5, 6 o 7 La Fecha MÍNIMA del primer Miércoles sería el 7, el segundo Miércoles sería el 14, así que esto comienza con el 19 - cualquier día de la semana... 5, 6, 7... Ej:19 - 5(Jue Día de semana) =14, 19 - 6 (viernes, día de la semana) =13, 19 - 7 (sábado, día de la semana) =12. Por lo tanto, sabemos que el primer miércoles será la semana completa, por lo que cuanto antes be es el 7 y el 14 en lugar del 1 y el 8 (el primero del mes).

Ahora que sabemos CUÁNDO es el segundo miércoles del mes, compárelo con la fecha en la que estamos ejecutando la consulta (es decir, curdate() ). Si la fecha actual es EN o ANTES (a través de <=) el SEGUNDO MIÉRCOLES del MES (@SWOM), entonces solo queremos omitir 1 mes... si estamos más adelante en el mes, debemos omitir 2 meses.

Ahora, construya las fechas. La base de la fecha para el Mes 1 es el primero del mes actual MÁS un intervalo de la cantidad de meses que desee omitir. El mes 2 es un mes después del primero, el mes 3 uno después del mes 2 y el mes 4 uno después del mes 3.

@FirstOfMonth := CONCAT( year(curdate()), '-', month( curdate()), '-01' ),
@FDOW := DayOfWeek( @FirstOfMonth ),
@SWOM := if( @FDOM <= 4, 12, 19) - @FDOM,
@SkipMonths := if( day( CurDate()) <= @SWOM, 1, 2 ),
@Month1 := date_add( @FirstOfMonth, interval 0 +  @SkipMonths month ),
@Month2 := date_add( @Month1, interval 1 month ),
@Month3 := date_add( @Month2, interval 1 month ),
@Month4 := date_add( @Month3, interval 1 month )

Así que finalmente tenemos la base de 4 meses para trabajar en una sola fila de (seleccionar...) conjunto de resultados de sqlvars que muestra algo como

@Month1     @Month2     @Month3     @Month4
2012-03-01  2012-04-01  2012-05-01  2012-06-01 ... the four months out

Finalmente, una vez que estos datos parecen correctos, ahora podemos construir las cadenas específicas que está buscando con los respectivos prefijos "Q", "U", "V" y "X" más el 3 izquierdo del nombre del mes con el 2 dígito del año.

Entonces, con esto obteniendo todos los rangos de fechas y cadenas que espera, consulte esto contra su otra tabla como enumeré en la inicial.

Espero que esto te ayude y te abra los ojos a un contexto completamente nuevo para engañar a SQL para... en esencia, hacer un programa en línea para crear muchas variables y operar a partir de eso... Genial, eh...

Y con toda sinceridad, esta es la primera vez que pruebo específicamente esta técnica, aunque he realizado muchas consultas en el pasado usando SQLVars.