Ich versuche, den letzten Wert der Spielerguthaben in einem bestimmten Zeitfenster abzurufen.

Ich habe eine transactions Tabelle.

Das Spielerguthaben ist nicht das Maximum oder das Minimum.

SELECT  project_id, 
        player_id,
        FIRST_VALUE(balance) OVER (PARTITION BY player_id ORDER BY event_arrival_time DESC) AS balance
FROM transactions
WHERE event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
        AND project_id='aaa' 
GROUP BY project_id, player_id

Ich erhalte Werte, aber wenn ich sie mit der Abfrage eines einzelnen Spielers teste, erhalte ich ein anderes Guthaben und sehe das angegebene Ergebnisguthaben irgendwo in der Mitte des Zeitraums.

Wenn ich diese Abfrage mehrmals ausführe, erhalte ich auch einen anderen Kontostand, da die unterschiedliche Transaktion ausgewählt wird (es handelt sich um einen Unterschied von 10 Minuten).

SELECT * 
FROM transacitions
where event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
        AND project_id='aaa' and player_id = 'player1'
ORDER BY event_arrival_time desc

Ich möchte eine Liste der Spieler in diesem Zeitraum und deren letzten Kontostand erhalten (nicht den MAX-Wert - möglicherweise das maximale Datum).

0
Ido Barash 23 Feb. 2020 im 12:45

3 Antworten

Beste Antwort

Entfernen Sie die GROUP BY -Klausel und verwenden Sie bei Bedarf DISTINCT in SELECT:

SELECT DISTINCT 
  project_id, 
  player_id,
  FIRST_VALUE(balance) OVER (PARTITION BY player_id ORDER BY event_arrival_time DESC) AS balance
FROM transactions
WHERE event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
  AND project_id='aaa'
2
forpas 23 Feb. 2020 im 10:12

Sie müssen filtern, nicht aggregieren.

Sie können dies mit einer korrelierten Unterabfrage tun:

SELECT project_id, player_id, balance
FROM transactions t
WHERE event_arrival_time = (
    SELECT MAX(t1. event_arrival_time)
    FROM transactions t1
    WHERE 
        t1.player_id = t.player_id
        AND t1.event_arrival_time >= '2019-12-02'
        AND t1.event_arrival_time < '2019-12-03'
        AND t1.project_id = 'aaa' 
    )

Für die Leistung möchten Sie einen Index für (project_id, player_id, event_arrival_time). Sie können auch einen abdeckenden Index versuchen: (project_id, player_id, event_arrival_time, balance); Mit einem solchen Index würde die Datenbank möglicherweise die gesamte Abfrage ausführen, indem sie nur den Index betrachtet, ohne tatsächlich auf die zugrunde liegenden Daten zuzugreifen.

Sie können auch Fensterfunktionen verwenden:


SELECT project_id, player_id, balance
FROM (
    SELECT 
        t.*,
        RANK() OVER(PARTITION BY player_id ORDER BY event_arrival_time DESC) rn
    FROM transactions t
    WHERE
        event_arrival_time >= '2019-12-02'
        AND event_arrival_time < '2019-12-03'
        AND project_id='aaa'
) t
WHERE rn = 1


1
GMB 23 Feb. 2020 im 14:20

Ich denke das sollte funktionieren. Ohne Probe schwer zu sagen.

SELECT
     t.project_id,
     t.player_id,
     GROUP_CONCAT(t.balance) AS Balance -- supposed to have single value
FROM transacitions t
LEFT JOIN transactions t2 ON t.project_id = t2.project_id AND t.player_id = t2.player_id
AND t.event_arrival_time < t2.event_arrival_time
where t2.player_id IS NULL
AND t.event_arrival_time BETWEEN '2019-12-02 00:00:00' AND '2019-12-03 23:59:59'
GROUP BY t.project_id, t.player_id
ORDER BY t.event_arrival_time desc
0
Nae 23 Feb. 2020 im 10:12