2016-04-20 3 views
0

ich eine Selbst auszuführen versuche - auf einem Tisch sitzen, und suchen Sie nach allen Zeilen, die einen Satz übereinstimmen (Staat, office_type, office_class, Kreis), um Identifizieren Sie Bereiche von Daten, für die das Set keine Daten enthält.SQLAlchemy - Datumsbereich Gap Identifikationen, sind verantwortlich für Bereiche, die sich überlappen

Meine aktuelle Abfrage:

term_alias = aliased(schema.Term, name='term_alias') 
query = Session.query(schema.Term, term_alias).filter(schema.Term.office_type_id == term_alias.office_type_id).\ 
    filter(schema.Term.state_id == term_alias.state_id).\ 
    filter(schema.Term.office_class == term_alias.office_class).\ 
    filter(schema.Term.term_end < term_alias.term_begin).\ 
    filter(or_(schema.Term.district_id == term_alias.district_id, 
       schema.Term.district_id == None)).\ 
    group_by(schema.Term.term_end).\ 
    group_by(schema.Term.state_id).\ 
    group_by(schema.Term.office_class).\ 
    group_by(schema.Term.office_type_id).\ 
    having(schema.Term.term_end < func.min(term_alias.term_begin)).\ 
    having((term_alias.term_begin - schema.Term.term_end) > 1) 

Die Ergebnisse, die ich bekommen, sind nicht in vollem Umfang gültig.

Die hervorgehobene Zeile sollte nicht durchkommen.

enter image description here enter image description here

Wie Sie sehen können, ist dies nicht eigentlich eine Lücke. Der 1. Ausdruck und der 2. Ausdruck überlappen und sollten daher nicht als Lücke enthalten sein.

Ich habe ein paar Variationen über die obige Abfrage versucht, aber die richtigen Ergebnisse sind mir entgangen. Meine Frage ist, wie kann ich überlappende Daten berücksichtigen? und sicherzustellen, nur wahre Lücken gemeldet werden,


RAW SQL als gedruckte von print(query)

SELECT terms.id AS terms_id, terms.term_begin AS terms_term_begin, terms.term_en 
d AS terms_term_end, terms.term_served AS terms_term_served, terms.office_type_i 
d AS terms_office_type_id, terms.person_id AS terms_person_id, terms.state_id AS 
terms_state_id, terms.district_id AS terms_district_id, terms.removal_reason_id 
AS terms_removal_reason_id, terms.political_party_id AS terms_political_party_i 
d, terms.is_elected AS terms_is_elected, terms.is_holdover AS terms_is_holdover, 
terms.neat_race_id AS terms_neat_race_id, terms.office_class AS terms_office_cl 
ass, terms.notes AS terms_notes, terms.is_vacant AS terms_is_vacant, term_alias. 
id AS term_alias_id, term_alias.term_begin AS term_alias_term_begin, term_alias. 
term_end AS term_alias_term_end, term_alias.term_served AS term_alias_term_serve 
d, term_alias.office_type_id AS term_alias_office_type_id, term_alias.person_id 
AS term_alias_person_id, term_alias.state_id AS term_alias_state_id, term_alias. 
district_id AS term_alias_district_id, term_alias.removal_reason_id AS term_alia 
s_removal_reason_id, term_alias.political_party_id AS term_alias_political_party 
_id, term_alias.is_elected AS term_alias_is_elected, term_alias.is_holdover AS t 
erm_alias_is_holdover, term_alias.neat_race_id AS term_alias_neat_race_id, term_ 
alias.office_class AS term_alias_office_class, term_alias.notes AS term_alias_no 
tes, term_alias.is_vacant AS term_alias_is_vacant 
FROM terms, terms AS term_alias 
WHERE terms.office_type_id = term_alias.office_type_id AND terms.state_id = term 
_alias.state_id AND terms.office_class = term_alias.office_class AND terms.term_ 
end < term_alias.term_begin AND (terms.district_id = term_alias.district_id OR t 
erms.district_id IS NULL) GROUP BY terms.term_end, terms.state_id, terms.office_ 
class, terms.office_type_id 
HAVING terms.term_end < min(term_alias.term_begin) AND term_alias.term_begin - t 
erms.term_end > :param_1 

SQLFiddle in seinem aktuellen Zustand: http://sqlfiddle.com/#!9/3e030/1

Antwort

1

Ihre Anfrage nicht in der Lage ist, Überschneidungen zu handhaben, wie kann aus dem einfachen Vergleich gesehen werden.

auf Ihre Daten Sehen, ich würde Suche mit folgenden Schritte ausführen:

  1. Suche Lücke begins: durch alle solche Term, für die Suche nach dem Tag nach Term.term_end ist nicht von keinem anderen Term (ordnungsgemäßer bedeckt office_type/office_class/state/district)
  2. Für jede gefundene Lücke begin finden Sie ein Lückenende durch Finden der frühesten Term Instanz, die nach der Lücke begin beginnt.

kam ich auf die folgende Umsetzung:

TE = aliased(Term, name='TE') # gap period start (end of last before gap) 
TO = aliased(Term, name='TO') # other term for check of TE 
TS = aliased(Term, name='TS') # start of the next period after gap 

# condition for the existance of TE: no other periods overlaping with the next 
# day after TE.term_end 

# define an alias for the `TE.term_end + 1 day` (engine specific) 
# gap_sdate = TE.term_end 
gap_sdate = func.date(TE.term_end, text("'+1 days'")) # sqlite version 
# gap_sdate = func.ADDDATE(TE.term_end, 1)) # mysql version 

# subquery which checks if there are Terms covering next day after term_end 
subq = (
    session 
    .query(TO.id) 
    .filter(and_(
     TE.office_type_id == TO.office_type_id, 
     TE.state_id == TO.state_id, 
     or_(TE.district_id == TO.district_id, 
      and_(TE.district_id == None, TO.district_id == None) 
      ), 
     TE.office_class == TO.office_class, 
    )) 
    .filter(TO.id != TE.id) 
    .filter(TO.term_begin <= gap_sdate) 
    .filter(or_(TO.term_end == None, TO.term_end >= gap_sdate)) 
) 

# query to find the gaps 
q = (
    session 
    .query(
     TE.office_type_id, 
     TE.state_id, 
     TE.district_id, 
     TE.office_class, 
     gap_sdate.label("vacant_from"), 
     func.date(func.min(TS.term_begin), text("'-1 days'")).label("vacant_till"), # sqlite version 
     # func.ADDDATE(func.min(TS.term_begin), -1).label("vacant_till"), # mysql version 
    ) 
    .join(TS, and_(
     TE.office_type_id == TS.office_type_id, 
     TE.state_id == TS.state_id, 
     or_(TE.district_id == TS.district_id, 
      and_(TE.district_id == None, TS.district_id == None) 
      ), 
     TE.office_class == TS.office_class, 
    )) 
    # filters for gap start 
    .filter(TE.term_end != None) 
    .filter(~subq.exists()) 
    # filters for gap end 
    .filter(TE.id != TS.id) 
    .filter(TS.term_begin > gap_sdate) 
    .group_by(TE) 
) 

gaps = q.all() 
for gap in gaps: 
    print(gap) 
+0

Wow !!!! Ich kam nicht einmal näher ... Ich kann dir nicht genug für deine Hilfe danken. Es sieht so aus, als würde es mit minimalen Tests arbeiten. Ich muss die ganze Arbeit durchkämmen, damit ich sie richtig verstehen kann. Nochmals vielen Dank, dass Sie sich die Zeit genommen haben, mir dabei zu helfen. – Busturdust

+0

Ihre Kommentare und Erklärungen sind 10x besser als alles, was ich sonst wo gefunden habe. Ich wünschte, ich könnte +1000 geben. Danke noch einmal. – Busturdust

Verwandte Themen