Wymaga to dużo wstępnego sprawdzenia, ale w istocie musiałem budować zmienne SQL w oparciu o jeden krok na raz, tak jakby to było w programie „niech X =coś”, „niech y =X + coś innego” , itd. Budując najbardziej wewnętrzne zmienne @SQLVars, po zadeklarowaniu pierwszej zmiennej, może ona zostać użyta jako podstawa następnej zmiennej itd. Po pierwsze, oto pełne zapytanie, które możesz zastosować do swoich danych budujących na podstawie aktualnej daty. Lepiej znając swoje dane, być może będziesz musiał je trochę poprawić, ale myślę, że to pomoże ci na dobrej drodze.
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
Wynik tego jednego zapytania powyżej zwróci POJEDYNCZY rekord (na podstawie bieżącej daty 31 stycznia), aby pokazać Pierwszy miesiąc Drugi miesiąc Trzeci miesiąc Czwarty miesiąc Q (12 marca) U (12 kwietnia) V (12 maja) X (12 czerwca)
Teraz umieść to w pozostałej części zapytania dla identyfikatorów giełdowych, na przykład
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()
Jeśli spojrzysz na najbardziej wewnętrzne @SqlVariables, jak wspomniano wcześniej, jest to jak wiązka „niech x=coś”. Zawsze potrzebuję podstawy, aby zacząć, więc najpierw dostaję pierwszy dzień danego miesiąca do zmiennej @FirstOfMonth, łącząc rok bieżącej daty + "-" + miesiąc bieżącej daty + "-01", aby zawsze zaczynać się od pierwszego dnia miesiąca... Np.:Dzisiaj jest 31 stycznia 2012 zbuduje ciąg "2012-01-01", który w formacie rok/miesiąc/data jest natychmiast rozpoznawany przez MySQL jako format daty możemy wykonać arytmetykę daty. Więc teraz mam @FirstOfMonth ='2012-01-01'. Teraz musimy określić pierwszy dzień tygodnia, który ta data reprezentuje w miesiącu, w którym się znajdujemy (stąd @FDOW). Spowoduje to zwrócenie wartości od 1-7 (niedziela =1, środa =4, sobota =7).
Na tej podstawie musimy teraz obliczyć, kiedy będzie druga środa miesiąca. Jeśli dzień tygodnia to od niedzieli do (włącznie) środy, DRUGA środa to 12 dni MINUS dzień tygodnia. Np.:pierwsza niedziela to środa czwartej, potem środa jedenasta... więc 12 - 1 (niedziela) =11. Gdyby pierwszym dniem miesiąca była środa, byłby to dzień tygodnia =4, ale 1. dzień miesiąca =środa, druga środa =8, więc 12 - 4 =8. Teraz, jeśli pierwszym dniem miesiąca jest czwartek, piątek lub sobota, dniem tygodnia będzie 5, 6 lub 7 MINIMALNA data pierwszej środy to 7, druga środa to 14, więc zaczyna się od 19 - niezależnie od dnia tygodnia... 5, 6, 7... Np.:19 - 5 (czw dzień Tydzień) =14, 19 - 6 (Piątek Dzień Tygodnia) =13, 19 - 7 (Sobota Dzień Tygodnia) =12. Wiemy więc, że pierwsza środa będzie miała cały tydzień, więc najwcześniej be jest 7. i 14. w przeciwieństwie do 1. i 8. (najwcześniejszy miesiąc).
Teraz, gdy wiemy, KIEDY przypada druga środa miesiąca, porównaj to z datą, na podstawie której wykonujemy zapytanie (np. curdate() ). Jeśli aktualna data jest WŁĄCZONA lub PRZED (przez <=) DRUGA ŚRODA MIESIĄCA (@SWOM), to chcemy pominąć tylko ponad 1 miesiąc... jeśli jesteśmy dalej w miesiącu, musimy pominąć 2 miesiące.
Teraz zbuduj daty. Podstawą daty dla miesiąca 1 jest pierwszy dzień bieżącego miesiąca PLUS odstęp dowolnej liczby miesięcy do pominięcia. Miesiąc 2 to jeden miesiąc po pierwszym, miesiąc 3 – ostatni miesiąc 2, a miesiąc 4 – ostatni miesiąc 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 )
Więc w końcu mamy wszystkie 4 miesiące do pracy w jednym wierszu (wybierz ...) zbioru wyników sqlvars pokazujących coś takiego
@Month1 @Month2 @Month3 @Month4
2012-03-01 2012-04-01 2012-05-01 2012-06-01 ... the four months out
Wreszcie, gdy te dane wydają się prawidłowe, możemy teraz zbudować określone ciągi, których szukasz, z odpowiednimi przedrostkami „Q”, „U”, „V” i „X” plus lewą 3 nazwę miesiąca z 2 cyfra roku.
Tak więc, pobierając wszystkie oczekiwane zakresy dat i ciągi, przeprowadź zapytanie względem drugiej tabeli, jak wymieniłem na początku.
Mam nadzieję, że to ci pomoże i otworzy oczy na zupełnie nowy kontekst, w którym można nakłonić SQL do… w istocie wykonania wbudowanego programu do tworzenia wielu zmiennych i operowania nimi… Całkiem fajnie huh…
I prawdę mówiąc, jest to pierwszy raz, kiedy specjalnie wypróbowałem tę technikę, chociaż w przeszłości wykonałem wiele zapytań za pomocą SQLVars.