2016-10-18 8 views
2

Ich habe eine Tabelle teams mit 30 Zeilen und hat eine Handvoll Statistiken als Attribute gespeichert. Zum Beispiel Ziele für, Ziele gegen usw. und ich habe eine Ansicht erstellt, die rank() verwendet und die Datensätze gut sortiert. Hier ist eine verkürzte Abfrage Beispiel und die daraus resultierende Tabelle:Wie Konto Postgresql Rang() Bindungen

SELECT name, 
    points, 
    rank() OVER (ORDER BY points DESC) AS point_tank 
FROM teams; 


     name   | points | point_rank 
-----------------------+-----------+---------------- 
Team 1    |  14 |    1 
Team 2    |  11 |    2 
Team 3    |   9 |    3 
Team 4    |   9 |    3 

Ich mag würde eine zusätzliche Spalte hinzufügen, die boolean zurückgeben würde, basierend auf, ob der Rang ist eine Krawatte. zB Team 3 und Team 4 in diesem Beispiel. Es könnte in etwa so aussehen:

  name   | points | point_rank  | tie 
-----------------------+-----------+----------------+---------------- 
Team 1    |  14 |    1 |   false 
Team 2    |  11 |    2 |   false 
Team 3    |   9 |    3 |   true 
Team 4    |   9 |    3 |   true 

Irgendwelche Ideen hier? Oder nähere ich mich dem hier falsch und missbrauchen Rang()? Danke im Voraus!

Antwort

3

Sie einen CTE verwenden könnte und dann verwenden, um die Verzögerung/Blei-Funktionen Check für krawatten:

with ranked as (
    SELECT name, 
     points, 
     rank() OVER (ORDER BY points DESC) AS point_rank 
    FROM teams 
) 
select name, points, point_rank, 
     ( point_rank = lag(point_rank, 1, -1::bigint) over (order by point_rank) 
     or point_rank = lead(point_rank, 1, -1::bigint) over (order by point_rank) 
     ) as is_tie 
from ranked; 

der Standardwert für die Verzögerung und Leitfunktion für die erste und letzte Zeile benötigt wird, zu vermeiden es für null zu überprüfen.

Beispiel: http://rextester.com/SCLH63446

+0

Danke, das funktioniert, und es hat mir geholfen, zu verstehen CTEs besser. –

2

Eine Möglichkeit wäre, Ihre aktuelle Abfrage in einer gemeinsamen Tabelle Ausdruck zu bringen und es dann zu identifizieren, zu benutzen, die Reihen sind doppelt:

WITH cte AS (
    SELECT name, 
      points, 
      rank() OVER (ORDER BY points DESC) AS point_rank 
    FROM teams; 
) 

SELECT cte.name, 
     cte.points, 
     cte.point_rank 
     CASE WHEN t.point_rank IS NOT NULL THEN 'false' ELSE 'true' END AS tie 
FROM cte 
LEFT JOIN 
(
    SELECT point_rank 
    FROM cte 
    GROUP BY point_rank 
    HAVING COUNT(*) = 1 
) t 
    ON cte.point_rank = t.point_rank 
0
SELECT name 
    , points 
    , rank() OVER (rrr) AS point_rank 
    -- , count(*) OVER (ppp) AS ppp_cnt 
    , rank() OVER (pp2) AS sub_rank 
    , (COUNT(*) OVER (ppp) > 1) AS is_tie 
FROM teams 
WINDOW ppp AS (PARTITION BY points) 
     , pp2 AS (PARTITION BY points ORDER BY ctid) 
     , rrr AS (ORDER BY points DESC) 
ORDER BY points DESC 
     ; 

Ergebnis (Ich habe zwei zusätzliche Reihen):


DROP SCHEMA 
CREATE SCHEMA 
SET 
CREATE TABLE 
INSERT 0 6 
    name | points | point_rank | sub_rank | is_tie 
--------+--------+------------+----------+-------- 
Team_1 |  14 |   1 |  1 | f 
Team_2 |  11 |   2 |  1 | f 
Team_3 |  9 |   3 |  1 | t 
Team_4 |  9 |   3 |  2 | t 
Team_5 |  5 |   5 |  1 | t 
Team_6 |  5 |   5 |  2 | t 
(6 rows) 
+0

Das 'ORDER BY ctid 'scheint fischig zu sein, da sich das ctid ändert wenn die Zeile aktualisiert wird (und HOT updates können nicht benutzt werden) –

+0

Ja, es ist fischig, aber es soll nicht stabil sein, es wird nur zur Disambiguierung verwendet die Bindungen in den "sub_rank". Sie können jedoch stattdessen den Teamnamen oder -nummer oder das Abonnementdatum verwenden. – joop