Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie konvertiere ich dieses komplexe SQL in eine Django-Modellabfrage?

BEARBEITEN: Ich habe es geschafft, die Lösung mit Django-Unterabfragen zu reformieren.

Wir können die Abfrage mit Djangos aggregates with SubQuery expressions :

  1. Erstellen Sie eine Unterabfrage, um den niedrigsten close abzurufen für jedes symbol :

    from django.db.models import OuterRef, Subquery, Min     
    
    lows = StockHistory.objects.filter(
        stock=OuterRef('stock'), 
        trading_date__gte='2017-05-04'
    ).values('stock__symbol')
    .annotate(low=Min('close'))
    .filter(trading_date__gte='2018-04-30')
    
    • Aufschlüsselung:

      • filter den Abfragesatz, um nur die Aktien mit trading_date >= '2017-05-04' zu erhalten .
      • "GRUPPE NACH" stock__symbol (Beispiele für gruppieren nach in Djnago:GROUP BY ... MIN/MAX , GROUP BY ... COUNT/SUM ).
      • annotate die niedrigste (low ) Preis für jedes Element.
      • filter den Abfragesatz erneut, um nur die Objekte mit einem low zu erhalten Feld, das am trading_date >= '2018-04-30' auftritt .
    • Zwischenergebnis:

      Obwohl wir zu diesem Zeitpunkt kein Ergebnis erhalten können, sieht die Unterabfrage so aus:

      [
          {'stock__symbol': 'A', 'low': Decimal('105.00000')},            
          {'stock__symbol': 'C', 'low': Decimal('90.00000')}
      ]
      

      Uns fehlt das trading_date .

  2. Verwenden Sie die Unterabfrage, um die spezifische StockHistory abzurufen Objekte:

    StockHistory.objects.filter(
        stock__symbol=Subquery(lows.values('stock__symbol')),
        close=Subquery(lows.values('low')),
        trading_date__gte='2018-04-30'
    ).values('stock__symbol', 'trading_date', 'close')
    .order_by('stock__symbol')
    
    • Aufschlüsselung:

      • lows.values('stock__symbol') und lows.values('low') rufen die entsprechenden Werte aus der Unterabfrage ab.
      • filter den Abfragesatz gegen die lows Unterabfragewerte. Auch filter gegen das angegebene Datum, um niedriges close zu eliminieren Preise vor diesem Datum.
      • Erhalten Sie die angegebenen values .
      • Ordnen Sie das Ergebnis nach stock__symbol (standardmäßig ascending ).
    • Ergebnis:

      [
          {
              'close': Decimal('105.00000'), 
              'trading_date': datetime.date(2018, 5, 3), 
              'stock__symbol': 'A'
          }, 
          {
              'close': Decimal('90.00000'), 
              'trading_date': datetime.date(2018, 5, 4), 
              'stock__symbol': 'C'
          }
      ]