2016-05-04 5 views
0

Ich habe 2 Abfragen, die getrennt voneinander funktionieren. Wenn sie ähnlich sind, möchte ich sie zu einer performanten Abfrage zusammenfassen. Scheint einfach, da die Where-Klauseln ähnlich sind. Aber die Funktionen sum, count und min gelten alle für verschiedene Zeilen und stehen im Weg.Konsolidieren Sie 2 Abfragen mit ähnlichen Where-Klauseln, aber unterschiedlichen Aggregatfunktionszielen

Kontext:

  • Benutzer können eine Position Note (oder Rate) und erhalten Punkte
  • Ein Benutzer kann Benutzer B beziehen und Empfehlungspunkte erhalten, wenn Benutzer B zuerst eine Punktzahl nach
  • Punkte verfallen einreicht ein bestimmtes Datum
  • Ziel ist es, eine Rangliste der Benutzer und ihre Gesamtpunkte für das Scoring und Verweisen für einen bestimmten Standort (Bereich/Land)
  • Positionsparameter sind mit harten v gefüllt Gültig für "Massachusetts", "United States" und das Ablaufdatum von scoreDateTime und sind in beiden Select-Subqueries leider doppelt vorhanden.

Frage:

Wie kann die Abfrage unter reorganisiert werden Einschränkungen zu kombinieren? Es muss eine Möglichkeit geben, mit einer Liste von Scores von einem bestimmten Ort nach einem bestimmten Datum zu beginnen. Die einzige Komplikation besteht darin, das erste Ergebnisdatum von Benutzer B zu erhalten und nur dann Benutzer A anzubieten, wenn es nach dem Ablaufdatum ist.

select scoring.userId, scoring.points + referring.points as leaderPoints 
from (
    select userId, sum(ratingPoints) as points 
    from  scores s, locations l 
    where s.locationId = l.locationId and 
      l.locationArea = 'Massachusetts' and 
      l.locationCountry = 'United States' and 
      s.scoreDateTime > '2016-04-16 18:50:53.154' and 
      s.userId != 0 
    group by s.userId 
) as scoring 

join (
    select u1.userId, count(*) * 20 as points 
    from users u0 
    join users u1 on u0.userId = u1.userId 
    join users u2 on u2.referredByEmail = u1.emailAddress 
    join scores s on u2.userId = s.userId 
    join locations l on s.locationId = l.locationId 
    where l.locationArea = 'Massachusetts' and 
      l.locationCountry = 'United States' and 
      scoreDateTime = (
       select min(scoreDateTime) 
       from scores 
       where userId = u2.userId 
      ) and 
      scoreDateTime >= '2016-04-16 18:50:53.154' 
    group by u1.userId 
) as referring on scoring.userId = referring.userId 
order by leaderPoints desc 
limit 10; 

Antwort

0

Dank Stan Shaw bewerben, aber ich war nicht in der Lage Ihre Anfrage zu bekommen auf MySQL zu arbeiten, um die Ergebnisse zu prüfen. Allerdings habe ich einen Sonderfall bemerkt, der von meiner ursprünglichen Anfrage nicht abgedeckt wurde. Ein Benutzer kann Bezugspunkte aus Bereichen erhalten, in denen er selbst keine Bewertungen abgegeben hat. Solange der neue Nutzer in diesem Bereich punktet, erhalten sie dort Bezugspunkte.

Hier ist die letzte Abfrage, die ich verwende. Ich war nicht in der Lage, die duplizierten where-Klauseln in einer Weise zu konsolidieren, die performant erschien.

select userId, sum(points) as leaderPoints 
from (

    select s.userId, sum(s.ratingPoints) as points 
    from  scores s, locations l 
    where s.locationId = l.locationId and 
      l.locationArea = 'Georgia' and 
      l.locationCountry = 'United States' and 
      s.scoreDateTime >= '2016-04-05 03:00:00.000' and 
      s.userId != 1 
    group by userId 

    union 

    select u1.userId, 20 as points 
    from  users u0, users u1, users u2, scores s, locations l 
    where u0.userId = u1.userId and 
      u2.referredByEmail = u1.emailAddress and 
      u2.userId = s.userId and 
      s.locationId = l.locationId and 
      l.locationArea = 'Georgia' and 
      l.locationCountry = 'United States' and 
      scoreDateTime >= '2016-04-05 03:00:00.000' and 
      scoreDateTime = (
       select min(scoreDateTime) 
       from scores 
       where userId = u2.userId 
      ) 

) as pointsEarned 
group by userId 
order by leaderPoints desc 
limit 10 
order by leaderPoints desc 
limit 100; 
0

Dies ist nicht getesteter Code, aber es sollte den Trick tun. Das Cross Apply ist für die Lesbarkeit gedacht ... es wird die Leistung beeinträchtigen, aber das scheint keine besonders prozessintensive Abfrage zu sein, also würde ich es behalten.

Bitte versuchen Sie es und lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben.

SELECT U.UserID, 
     ISNULL(SUM(CASE WHEN S.UserID IS NULL THEN 0 ELSE S.ratingPoints END), 0) AS [Rating Points], 
     ISNULL(SUM(CASE WHEN SS.userID IS NULL THEN 0 ELSE 20 END), 0) AS [Referral Points] 
FROM Users U 
LEFT OUTER JOIN scores S 
    ON S.userID = U.userID 
    AND S.scoreDateTime >= '2016-04-16 18:50:53.154' 
LEFT OUTER JOIN locations L 
    ON S.locationID = L.locationID 
    AND L.locationArea = 'Massachusetts' 
    AND L.LocationCountry = 'United States' 
LEFT OUTER JOIN Users U2 
    ON U2.referredByEmail = U.emailAddress 
LEFT OUTER JOIN scores SS 
    ON SS.userID = U2.userID 
LEFT OUTER JOIN locations LL 
    ON SS.locationID = LL.locationID 
    AND LL.locationArea = 'Massachusetts' 
    AND LL.locationCountry = 'United States' 
    AND SS.scoreDateTime >= '2016-04-16 18:50:53.154' 
    AND SS.scoreDateTime = 
     (
      SELECT MIN(scoreDateTime) 
      FROM scores 
      where userID = U2.userID 
     ) 
GROUP BY U.userID 

EDIT:

Modified Antwort zu entfernen Kreuz

+0

Ich benutze MySQL, wo anscheinend CROSS APPLY scheint nicht zu gelten. Ich hoffte, die Beschränkungen locationArea, locationCountry und scoreDateTime zu konsolidieren, wenn sie dupliziert werden. Die einzige Zeit, die ich außerhalb dieser Liste von Punkten erreiche, ist die min (scoreDateTime), um die erste Punktzahl datetime des verwiesenen Benutzers zu erhalten. Ich möchte nur Empfehlungsbonuspunkte vergeben, wenn dieses Datum nach dem Stichtag liegt. – jmelvin

+0

@jmelvin Ich habe die Antwort geändert, um Cross Apply zu entfernen. –

Verwandte Themen