Jaarlijkse data vinden met Rails 3.1 ActiveRecord-query's

Ik ben een Rails 3.1-project aan het bouwen waarbij een van mijn modellen een verjaardagsattribuut bevat. Ik heb geprobeerd een zoekopdracht te vinden die in essentie alle gebruikers met een verjaardag binnen een bepaald bereik vindt. Het probleem is dat dit deel van de applicatie niet echt om het geboortejaar geeft, alleen de maand en de dag. Helaas heeft Google hier niet veel aan gehad.

Weet iemand hoe te zoeken naar alle records waarvan het verjaardagskenmerk 'een verjaardag heeft' binnen een bepaald datumbereik? Ik hoop dat dat logisch is!

3

2 antwoord

Het lijkt erop dat je op zoek bent naar EXTRACT :

M.where(%q{
    array[extract(month from d)::int, extract(day from d)::int] between array[?, ?] and array[?, ?]
}, lower_month, lower_day, upper_month, upper_day)

waar M uw model is, is bday de verjaardagskolom en de bovenste en onderste variabelen bevatten de grenzen van de maand en de dag. U kunt ook INTERSECT gebruiken:

M.find_by_sql([%q{
    select * from ms where array[? ,?] <= array[extract(month from bday)::int, extract(day from bday)::int]
    intersect
    select * from ms where array[?, ?] >= array[extract(month from bday)::int, extract(day from bday)::int]
}, lower_month, lower_day, upper_month, upper_day])

Nog een andere versie zou to_char gebruiken :

M.where(
    "to_char(bday, 'MM') || to_char(bday, 'DD') between ? and ?",
    '%2.2d%2.2d' % [lower_month, lower_day],
    '%2.2d%2.2d' % [upper_month, upper_day]
)

Je zou dezelfde resultaten kunnen krijgen met een grote lelijke stapel CASE-uitspraken (zodat je alleen de dag-van-maand zou beschouwen aan de grenzen van de maand) maar het kruispunt is (IMO) schoner en gemakkelijker te lezen. Met behulp van de arrays (PostgreSQL) kunt u de maand/dag-paren met elkaar vergelijken als afzonderlijke eenheden in plaats van afzonderlijk.

5
toegevoegd
Werkt dit over meerdere maanden (bijv. 10/31-11/4)? Wanneer ik bijvoorbeeld het eerste deel van de zoekopdracht voor 31-10 uitvoer, wordt alleen verjaardagen opgehaald die plaatsvinden op of na de 31e (dat wil zeggen, slechts enkele maanden met 31 dagen en niet 11/1, 11/2, enzovoort). Dus mijn kruispunt blijft '0' draaien, ook al heb ik verjaardagen tussen die tijd. Ook krijg ik een 'verkeerd aantal argumenten (5 voor 2)' van de Rails-console wanneer ik de query laad zoals beschreven in dit antwoord.
toegevoegd de auteur JHo, de bron
@mu Dat laatste 'to_char' werkt perfect. Dank je. Een veel eenvoudigere en flexibelere manier om komende verjaardagen en jubilea te vinden in Rails dan elke andere benadering die ik heb gevonden.
toegevoegd de auteur JHo, de bron
@Andrew: Ik heb oorspronkelijk dezelfde fout gemaakt die je waarschijnlijk deed en ik moet goed zijn in dit spul :) Het afleiden van een query op basis van een beperkte gegevensset is vol gevaar en daarom controleren we elkaars werk.
toegevoegd de auteur mu is too short, de bron
@JHo: Er waren enkele ontbrekende haakjes in de find_by_sql oproep, sorry daarvoor. Ik denk dat je misschien gelijk hebt over de randkoffer, ik kom er weer bovenop en kom vanavond weer op je terug.
toegevoegd de auteur mu is too short, de bron
@JHo: Je had gelijk, bedankt dat je wees op de hersenschade. Ik heb bijgewerkt met een aantal betere opties met, hopelijk, minder hersenschade.
toegevoegd de auteur mu is too short, de bron
@JHo: Ik vind de to_char ook leuk, dat is gewoon een andere " ISO -8601 datums zijn de beste omdat ze correct sorteren als strings "trick.
toegevoegd de auteur mu is too short, de bron
Super goed. Ik was alleen aan het testen met een aantal records en de vorige query leek te werken, maar nu kan ik zien waar die verkeerde resultaten zou geven. Heel erg bedankt! Ik ben geen SQL-goeroe, dus ik heb altijd hulp nodig bij dit soort dingen.
toegevoegd de auteur Andrew, de bron

Er zijn verschillende datum-functies in sql. Sommige halen de dag/maand eruit (onafhankelijk van het jaar). Ik ben er vrij zeker van dat er een is die alleen de "dag van het jaar" retourneert (dus 1 tot 365) (en als dat niet het geval is, zou je er een kunnen schrijven) - in welk geval je dat zou kunnen gebruiken en alle rijen zou pakken die hun dag van het jaar binnen een klein bereik van degene die je nu in handen hebt.

0
toegevoegd
U kunt schrikkeljaarproblemen echter wel tegenkomen met extract (doy from bday) , waarschijnlijk het veiligst om de dag van de maand en maand apart te beschouwen.
toegevoegd de auteur mu is too short, de bron
@Andrew: Weet je zeker dat het werkt als een charme? Je moet alleen naar de dag van de maand kijken als het maandnummer gelijk is aan de bovenste of de onderste maand (ik geef toe dat ik die fout heb gemaakt in mijn oorspronkelijke poging).
toegevoegd de auteur mu is too short, de bron
Geweldig. Uiteindelijk heb ik het uittreksel gebruikt en maand en dag van de maand afzonderlijk bekeken, en het werkt als een charme!
toegevoegd de auteur Andrew, de bron