2017-03-08 6 views
0

Wir haben ein System in Django geschrieben, um Patienten für klinische Studien rekrutiert verfolgen. Tabellen werden verwendet, um die Anzahl der monatlich rekrutierten Patienten während eines Geschäftsjahres zu erfassen; Das Blatt enthält also nur 12 Monate Daten, obwohl eine Studie über Jahre laufen könnte.Wählen Sie die letzten Zeilen in Django ORM mit Gruppierung

Es gibt eine Tabelle in einer Django-Datenbank, in die die Tabellenblätter jeden Monat importiert werden. Die Daten umfassen den Monat/das Jahr, eine Anzahl von Patienten und einige andere Felder. Jeder Import enthält alle Daten der Vormonate; Damit müssen Sie sicherstellen, dass auf dem Importblatt seit dem letzten Import keine Daten geändert wurden.

Zum Beispiel kann die Importtabelle mit zwei Einfuhren (die ersten bis Januar und die zweiten bis Februar) würde wie folgt aussehen:

id | study_id | data_date | patient_count | [other fields] --> 
100  5456 2016-04-01    10  ... 
101  5456 2016-05-01    8  ... 
102  5456 2016-06-01    5  ... 
    ... all months in between ... 
109  5456 2016-01-01    12  ... 
110  5456 2016-02-01   NULL  ... 
111  5456 2016-03-01   NULL  ... 
112  5456 2016-04-01    10  ... 
113  5456 2016-05-01    8  ... 
114  5456 2016-06-01    5  ... 
    ... all months in between ... 
121  5456 2016-01-01    12  ... 
122  5456 2016-02-01    6  ... 
123  5456 2016-03-01   NULL  ... 

Die anderen Felder enthalten einen Fremdschlüssel zu einer anderen Tabelle der umschließende tatsächliche Studienidentifikationsnummer (iras_number), also muss ich mich damit verbinden, um die Zeilen für eine bestimmte Studie auszuwählen.

Ich möchte die letzten Werte von data_date und patient_count für eine Studie, die mehr als ein Haushaltsjahr erstrecken kann, so habe ich versucht, diese Abfrage (iras_number wird an die Funktion übergeben diese Abfrage durchführen):

totals = ImportStudyData.objects.values('data_date', 'patient_count') \ 
     .filter(import_study__iras_number=iras_number) \ 
     .annotate(max_id=Max('id')).order_by() 

jedoch erzeugt dies eine SQL-Abfrage, die patient_count im GROUP BY enthält, in doppelten Zeilen resultierenden:

data_date | patient_count | max_id 
2016-04-01    10  100 
2016-04-01    10  112 
2016-05-01    8  101 
2016-05-01    8  113 
    ... 
2016-01-01    12  109 
2016-01-01    12  121 
2016-02-01   NULL  110 
2016-02-01    6  122 

Wie wähle ich die neuesten data_date und patient_count aus der Tabelle mit dem ORM?

Wenn ich die SQL geschrieben haben würde ich eine innere Auswahl der max(id) von data_date gruppierte tun und dass dann beitreten verwenden oder eine IN Abfrage verwenden, die Felder I aus der Tabelle benötigen auszuwählen; als solche:

SELECT data_date, patient_count 
FROM importstudydata 
WHERE id IN (
    SELECT MAX(id) AS "max_id" 
    FROM importstudydata INNER JOIN importstudy 
     ON importstudydata.import_study_id = importstudy.id 
    WHERE importstudy.iras_number = 5456 
    GROUP BY importstudydata.data_date 
) 
ORDER BY data_date ASC 

Ich habe versucht, ein inneres wählen Sie erstellen, um die SQL-Abfrage zu replizieren, aber die innere Auswahl kehrt mehr als ein Feld (Spalte) a bewirkt, dass die Abfrage fehlschlagen:

totals = ImportStudyData.objects.values('data_date', 'patient_count') \ 
     .filter(id__in=ImportStudyData.objects.values('data_date') \ 
         .filter(import_study__iras_number=iras_number) \ 
         .annotate(max_data_id=Max('id')) 

Nun kann ich die innere Auswahl nicht erhalten, nur die max(id) gruppiert von `data_date 'zurückzugeben und es in einer einzigen SQL-Abfrage durchgeführt werden.

Antwort

0

Vorerst zu einer Reihe von Schritten, um die Abfrage in ich Aufspalten das Ergebnis möchte ich zu erhalten.

Zuerst habe ich Abfrage für die jüngste id aller Zusammenhang mit der Studie Reihen

id_qry = ImportStudyData.objects.values('data_date')\ 
    .filter(import_study__iras_number=iras_number)\ 
    .annotate(max_id=Max('id')) 

Um eine Liste nur die Zahlen, das Datum Strippen, verwende ich Liste Verständnis:

id_list = [x['max_id'] for x in id_qry] 
Diese Liste

wird dann als Filter für die endgültige Abfrage verwendet, um die Anzahl der Patienten zu erhalten

totals = ImportStudyData.objects.values('data_date', 'patient_count') \ 
     .filter(id__in=id_list) 

Es trifft zweimal auf die Datenbank und ist rechenintensiver, aber im Moment funktioniert es und ich muss weitermachen.

Ich werde auf dieses Problem zu einem späteren Zeitpunkt zurückkommen.

-1

Verwendung: verschieden = True

totals = ImportStudyData.objects.values('data_date', 'patient_count').filter(import_study__iras_number=iras_number).annotate(max_id=Max('id')).order_by('data_date').distinct() 
+0

Wenn ich 'distinct = True' im Annotate-Aufruf hinzufüge, bekomme ich den Fehler '' bool 'object hat kein Attribut' resolve_expression''. Muss der 'distinct' Parameter Teil der' max' Funktionsparameter sein? – Tony

+0

Das Verschieben von "distinct" an das Ende des Abfrage-Strings bedeutet, dass es zur Ausführung der SQL-Anweisung führt, aber es gibt immer noch Duplikate zurück, da "distinct" auf alle Felder angewendet wird ('data_date',' patient_count' und 'max_id')) die bereits verschieden sind. – Tony

Verwandte Themen