2010-11-02 7 views
19

Ich mag gerne wissen, ob es möglich ist, die folgenden mit einem einzigen SQLite-Anweisung zu tun:SQLite-Äquivalent row_number() über (Partition ...

Meine Tabelle sieht wie folgt aus:

|AnId|UserId|SomeDate|SomeData| 
|123 |A  |1/1/2010|aadsljvs| 
| 87 |A  |2/9/2010|asda fas| 
|193 |A  |2/4/2010|aadsljvs| 
|927 |A  |7/3/2010|aadsasdf| 
|816 |B  |1/1/2010|aa32973v| 
|109 |B  |7/5/2010|aaasfd10| 
| 39 |B  |1/3/2010|66699327| 
... 

Jede Reihe hat eine eindeutige ID, eine Benutzer-ID, einen Datetime-Wert, und einige anderen Daten.

ich Aufzeichnungen löschen möchte, damit ich die neuesten 10 Datensätze pro Benutzer halten, basierend auf SomeDate.

in SQL Server würde ich so etwas wie folgt verwenden:

delete d 
from data d 
inner join (
    select UserId 
     , AnId 
     , row_number() over (partition by UserId order by SomeDate desc) 
       as RowNum 
    from data 
) ranked on d.AnId = ranked.AnId 
where ranked.RowNum > 10 

Gibt es eine Möglichkeit, dies in SQLite zu tun? Der Randfall, bei dem es mehrere Datensätze mit dem gleichen SomeDate gibt, ist keine besondere Sorge, z. wenn ich alle diese Aufzeichnungen aufbewahre, wäre das in Ordnung.

Antwort

17

Ich weiß, Diese Frage ist alt, aber die folgende SQLite-Anweisung wird tun, wonach Rory ursprünglich in einer Anweisung gefragt hat: Löschen Sie alle Datensätze für eine bestimmte UserId, die nicht die 10 neuesten Datensätze für diese UserId sind (basierend auf SomeDate).

DELETE FROM data 
WHERE AnId IN (SELECT AnId 
       FROM data AS d 
       WHERE d.UserId = data.UserId 
       ORDER BY SomeDate DESC 
       LIMIT -1 OFFSET 10) 
0

Dies könnte unerschwinglich teuer sein (vielleicht tut es nur, wenn ein Benutzer einen neuen Datensatz einfügt?), Aber wie wäre es damit:

for user in users: 
    user-records = select * from records where user=user 
    if user-records.length > 10: 
    delete from records where user=user and date<user-records[10] 

(in einer Mischung aus SQL und Pseudo-Code)

+0

sicher, ich kann es prozedural tun, aber ich mag einen Weg, es in einem einzigen zu tun Aussage wenn möglich. Wenn es prozedural gemacht wird, wäre es auch möglich, eine einzelne Anweisung pro Benutzer zu verwenden, und nur für die Benutzer mit Datensätzen in der Tabelle – Rory

+0

Ah, yeah; Ich habe keine Ahnung. Aus Neugier, wie können Sie es in einer einzigen Anweisung pro Benutzer tun? – sbirch

+0

Nun, das ist die Frage! Die Syntax in der Frage zeigt, wie man es in SQL Server macht. Ich weiß nicht, ob dies in SQLite möglich ist. Ich vermute nicht. – Rory

0

Wenn Sie bereits die Antwort nicht haben. Wenn es eine Tabelle ist, dann brauchen Sie keine Joins. Sie können einfach verwenden:

Delete From data 
where AnId not in (Select AnId 
        from data 
        Order by SomeDate DESC 
        Limit 10) 
1

Ich brauchte die zweite Zeile für jedes „Objekt“ in einer Tabelle mit einem 1: Beziehung zu dem „Objekt“ Tisch zu holen.

Regel in SQL wird dies mit ROW_NUMBER erfolgen() OVER (PARTITION BY object_id ORDER BY primary_id DESC)

In SQLite Ich hatte mit dieser Voodoo Unterabfrage zu kommen um das gleiche Ergebnis zu erhalten

SELECT object_id, MAX(_id) 
FROM (SELECT object_id, _id 
FROM aTable 
EXCEPT 
SELECT object_id, MAX(_id) 
FROM aTable 
GROUP BY object_id) 
GROUP BY object_id; 

Hinweis: die _id ist der Primärschlüssel aTable und der Objekttisch hat eine 1-Beziehung mit der abgefragten Tabelle