Det kræver en del forhåndskontrol, men i bund og grund var jeg nødt til at bygge SQL-variabler baseret på et trin ad gangen, som om det var i et program med "lad X =noget", "lad y =X + noget andet" , osv. Ved at bygge de inderste @SQLVars-variabler, når først den første er erklæret, kan den bruges som grundlag for den næste variabel og så videre... For det første er her den fulde forespørgsel, som du kan anvende på dine data, der bygger baseret på hvad den aktuelle dato er. Hvis du kender dine data bedre, bliver du måske nødt til at finjustere dem, men jeg tror, det kommer dig godt på vej.
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 af denne ene forespørgsel ovenfor returnerer en ENKEL post (baseret på den aktuelle dato 31. januar) for at viseFirstMonth SecondMonth ThirdMonth FourthMonthQ (12. marts) U (12. april) V (12. maj) X (12. juni)
Indsæt nu dette i resten af din forespørgsel efter dine ticker-id'er, noget lignende
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()
Hvis du ser på de inderste @SqlVariables er som nævnt tidligere som en flok "lad x=noget". Jeg har altid brug for et grundlag for at begynde, så jeg får først den første dag i en given måned ind i en variabel @FirstOfMonth ved at lave en sammenkædning af, hvad året er for den aktuelle dato + "-" + måned for den aktuelle dato + "-01" for altid at starte den første i måneden... eks:I dag er den 31. januar, 2012 vil bygge en streng af '2012-01-01', som i år/måned/dato-format genkendes med det samme af MySQL som et datoformat vi kan udføre datoregning på. Så nu har jeg @FirstOfMonth ='2012-01-01'. Nu skal vi bestemme den første ugedag, denne dato repræsenterer den måned, vi er i (deraf @FDOW). Dette vil returnere en værdi fra 1-7 (søndag =1, ons =4, lør =7).
Ud fra dette skal vi nu beregne, hvornår den 2. onsdag i måneden bliver. Hvis ugedagen er søndag til (og med) onsdag, er ANDEN onsdag 12 dage MINUS ugedagen. Eks.:Søndag den 1 ville være onsdag den 4., så onsdag den 11... så 12 - 1 (søndag) =11. Hvis den første dag i måneden VAR en onsdag, ville det være en dag i ugen =4, men 1. i måneden =ons, den anden ons =8, så 12 - 4 =8. Hvis datoen nu var tor, fre eller lør som den første i måneden, ville ugedagen være 5, 6 eller 7 MINIMUM datoen for den første onsdag ville være 7, den anden onsdag ville være 14, så dette starter med 19 - uanset ugedag... 5, 6, 7... Eks:19 - 5 (torsdag d. Uge) =14, 19 - 6 (fredag i ugen) =13, 19 - 7 (lør ugedag) =12. Så vi ved, at den første onsdag vil være hele ugen ud, så det tidligst ville be er 7. og 14. i modsætning til 1. og 8. (tidligst i måneden).
Nu hvor vi ved, HVORNÅR den 2. onsdag i måneden er, skal du sammenligne det med den dato, vi kører forespørgslen på (dvs. curdate() ). Hvis den aktuelle dato er ON eller FØR (via <=) ANDEN ON i MÅNED (@SWOM), så vil vi kun springe over 1 måned... hvis vi er længere henne i måneden, skal vi springe 2 måneder over.
Byg nu datoerne ud. Datogrundlaget for måned 1 er den første i den aktuelle måned PLUS et interval på hvor mange måneder der skal springes over. Måned 2 er en måned efter den første, måned 3 en efter måned 2, og måned 4 en efter måned 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 endelig alle 4 måneders basis at arbejde med i en enkelt række af (vælg ...) sqlvars resultatsæt, der viser noget lignende
@Month1 @Month2 @Month3 @Month4
2012-03-01 2012-04-01 2012-05-01 2012-06-01 ... the four months out
Endelig, når disse data vises i orden, kan vi nu udbygge de specifikke strenge, du leder efter, med de respektive "Q", "U", "V" og "X" præfikser plus de venstre 3 i månedens navn med de 2 cifferår.
Så med dette får alle de datointervaller og strenge, du forventer, skal du forespørge dette mod din anden tabel, som jeg anførte i initialen.
Jeg håber, at dette hjælper dig og åbner dine øjne for en helt ny kontekst til at narre SQL til... i det væsentlige at lave et inline-program for at skabe mange variabler og operere ud fra det... Ret cool huh...
Og i al sandhed er det første gang, jeg specifikt har prøvet denne teknik, selvom jeg tidligere har lavet mange forespørgsler ved hjælp af SQLVars.