sql >> Databasteknik >  >> RDS >> Mysql

kombinerar månatliga terminsdata till första månads tidsserier i MySQL

Det krävs mycket förkontroll, men i huvudsak var jag tvungen att bygga SQL-variabler baserade på ett steg i taget, som om det var i ett program med "låt X =något", "låt y =X + något annat" , etc. Genom att bygga de innersta @SQLVars-variablerna, när den första har deklarerats, kan den användas som grund för nästa variabel och så vidare... Först, här är hela frågan som du kan tillämpa på dina data som bygger baserat på vilket datum som helst. Om du känner till din data bättre kanske du måste finjustera den en del, men jag tror att det här kommer dig på god väg.

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

Resultatet av denna fråga ovan kommer att returnera en ENKEL post (baserat på aktuellt datum 31 januari) för att visaFirstMonth SecondMonth ThirdMonth FourthMonthQ (12 mars) U (12 april) V (12 maj) X (12 juni)

Nu, kapsla in detta i resten av din fråga för dina ticker-ID något liknande

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()

Om du tittar på de innersta @SqlVariables som nämnts tidigare är som ett gäng "låt x=något". Jag behöver alltid en grund för att börja, så jag får först den första dagen i en given månad till en variabel @FirstOfMonth genom att göra en sammanlänkning av vilket år som än är för det aktuella datumet + "-" + månaden för det aktuella datumet + "-01" för att alltid börja den första i månaden... ex:Idag är den 31 januari 2012 kommer att bygga ut en sträng av '2012-01-01' som i formatet år/månad/datum omedelbart känns igen av MySQL som ett datumformat vi kan utföra datumräkning på. Så nu har jag @FirstOfMonth ='2012-01-01'. Nu måste vi bestämma den första veckodagen som detta datum representerar den månad vi är i (därav @FDOW). Detta kommer att returnera ett värde från 1-7 (söndag =1, ons =4, lör =7).

Från detta måste vi nu beräkna när den andra onsdagen i månaden kommer att vara. Om veckodagen är söndag till (och inklusive) onsdag, är ANDRA onsdagen 12 dagar MINUS veckodagen. Ex:Söndag den 1 skulle vara ons 4, sedan ons 11... så 12 - 1 (söndag) =11. Om den första dagen i månaden VAR en ons, skulle det vara en dag i veckan =4, men 1:a i månaden =ons, andra ons =8, så 12 - 4 =8. Nu, om datumet var tor, fre eller lör som den första i månaden, skulle veckodagen vara 5, 6 eller 7 MINSTA datum för den första onsdagen skulle vara 7, den andra onsdagen skulle vara 14, så det här börjar med 19 - oavsett veckodag... 5, 6, 7... Ex:19 - 5 (torsdag den Vecka) =14, 19 - 6 (fredag ​​i veckan) =13, 19 - 7 (lör veckodag) =12. Så vi vet att den första onsdagen kommer att vara hela veckan ut, så den tidigaste skulle det be är 7:e och 14:e till skillnad från 1:a och 8:e (tidigast i månaden).

Nu när vi vet NÄR den 2:a onsdagen i månaden är, jämför det med det datum vi kör frågan baserat på (dvs:curdate() ). Om det aktuella datumet är PÅ eller FÖRE (via <=) ANDRA ONS i MÅNADEN (@SWOM), så vill vi bara hoppa över 1 månad... om vi är längre fram i månaden behöver vi hoppa över 2 månader.

Bygg ut datumen nu. Datumbasen för månad 1 är den första i innevarande månad PLUS ett intervall på hur många månader som helst att hoppa över. Månad 2 är en månad efter den första, månad 3 en efter månad 2 och månad 4 en efter månad 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 )

Så vi har äntligen alla fyra månader att arbeta med i en enda rad av ( välj ... ) sqlvars resultatuppsättning som visar något liknande

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

Slutligen, när dessa data visas ok, kan vi nu bygga ut de specifika strängarna du letar efter med respektive "Q", "U", "V" och "X" prefix plus den vänstra 3 i månadens namn med 2 siffra år.

Så, med detta att få alla datumintervall och strängar du förväntar dig, fråga detta mot din andra tabell som jag listade i initialen.

Jag hoppas att detta hjälper dig och öppnar dina ögon för ett helt nytt sammanhang för att lura SQL att... i huvudsak göra ett inline-program för att skapa många variabler och arbeta utifrån det... Ganska coolt va...

Och i ärlighetens namn är det första gången jag specifikt har provat den här tekniken, även om jag har gjort många frågor tidigare med SQLVars.




  1. Observer Overhead- och väntetypssymptom

  2. SQL TABELL

  3. Oracle SQL Injection Block med DBMS_ASSERT

  4. PLS-00201 identifierare 'PACKAGENAME.PROCEDURENAME' måste deklareras