Duplikate auf bestimmte Anzahl begrenzen

Doppelte Einträge sollten max. 3x drin sein, gibt es eine bessere Lösung als das?

SELECT DISTINCT et.code FROM xyz et WHERE et.timestamp > (TIMESTAMPADD(SECOND, -15, NOW()))
UNION ALL
SELECT DISTINCT et.code FROM xyz et WHERE et.timestamp > (TIMESTAMPADD(SECOND, -15, NOW()))
UNION ALL
SELECT DISTINCT et.code FROM xyz et WHERE et.timestamp > (TIMESTAMPADD(SECOND, -15, NOW()))

Danke für die Feedbacks.

Nein ist auch keine Lösung, wenn es nur 1 oder 2x drin ist wird es ebenfalls auf 3 vervielfacht. Ab > 3 sollte auf 3 begrenzt werden, drunter sollte die real in der Tabelle hinterlegte Menge ausgegeben werden.

…und die Zeitfunktionen sind ebenfalle ein Problem, hintereinander aufgerufen = Abweichung

limit oder LIMIT (10 Zeichen wieder: ()

Edit: Auf die schnelle finde ich das:

SELECT
    name, email, COUNT(*)
FROM
    users
GROUP BY
    name, email
HAVING 
    COUNT(*) > 1
LIMIT
    3

( https://stackoverflow.com/a/2594855 )

Aber das muss eben für ms sql (und der where-Klausel) angepasst werden.

Danke fürs schnelle Feedback!

Jedoch: Verstehe nicht ganz, ausserdem macht count(*) IMMER 1 Zeile mit dem Result Set - das kann man scheinbar drehen, wie man will

Noch mal:

Datenbank:
1
1
2
2
3
3

Query Ausgabe:

1
1
2
2
3
3

Datenbank:
1
1
1
2
2
2
3
3
3

Query Ausgabe:

1
1
1
2
2
2
3
3
3

Datenbank:
1
1
1
1
1
1
1
2
2
2
2
2
2
2
3
3
3
3
3
3
3

Query Ausgabe:

1
1
1
2
2
2
3
3
3

…ab grösser als 3 Duplikate werden diese auf 3 “gedeckelt”, so ist es viellecht einfacher zu verstehen.

Naja, du hast durch das mit den Timestamps eine unscharfe Bedingung… das müsstest du eben anpassen.

Mit der Zeit kann ich leider nicht spielen, scheinbar wird da nicht auf Millisekunden sondern nur auf Sekunden gespeichert. Dann kann ich leider nicht einfach die 3 jüngsten herauspicken. Es kann sein, dass gewisse Duplikate in der gleichen Sekunde gespeichert wurden

→ Meine zuerst gedachte Lösung geht nicht, auf Einträge welche 1 oder 2x vorkommen werden dabei auf 3 vervielfacht. Das sollte nicht sein, nur Deckelung ab > 3 auf 3…

Das hab ich mehr oder weniger verstanden… versuch es eben.

Gruppieren und Zählen ist eine Grund-Query (beliebiges WHERE mit Timestamp alles mit rein, hier irrelevant) :
A
B
B
C
C
C
D
D
D
D
->
A, 1
B, 2
C, 3
D, 4

von dieser dann alle einmal nehmen (A,B,C,D)
UNION
alle mit count > 1 (B, C, D)
UNION
alle mit count > 2 (C, D)

evtl. noch neu sortieren

->
A, B, B, C, C, C, D, D, D

1 „Gefällt mir“

Vielen Dank. Dass das theoretisch geht, ist mir soweit klar. Nur der Code, den es dazu braucht kann ich irgendwie nicht herleiten. (Man kann das halbe Internet absuchen und findet immer nur Count(*) und DISTINCT und solchen Sachen…)

Ok, mein Prof würde mir zwar den Hals umdrehen, aber wir habn:

  1. select * from Shippers;
ShipperID ShipperName Phone
1 Speedy Express (503) 555-9831
2 United Package (503) 555-3199
3 Federal Shipping (503) 555-9931
4 shipping federal (503) 555-9932
5 shipping 2 federal (503) 555-6932
6 shipping 2 federal (503) 555-9933
7 shipping 2 federal (503) 555-9934
8 shipping 2 federal (503) 555-9935
9 shipping 2 federal (503) 555-9936
10 shipping 2 federal (503) 555-9937
  1. select * from Shippers as a join (select ShipperName from Shippers group by ShipperName having count(*) > 1) as b on a.ShipperName = b.ShipperName limit 3;
ShipperID ShipperName Phone
5 shipping 2 federal (503) 555-6932
6 shipping 2 federal (503) 555-9933
7 shipping 2 federal (503) 555-9934

und

  1. select * from Shippers as a join (select ShipperName from Shippers group by ShipperName having count(*) > 1) as b on a.ShipperName = b.ShipperName where Phone like '%555-9%' limit 3;
ShipperID ShipperName Phone
6 shipping 2 federal (503) 555-9933
7 shipping 2 federal (503) 555-9934
8 shipping 2 federal (503) 555-9935

Das sollte es erklären und limitiert es also auf “bis zu” 3 Ergebnisse. (Ohne limit sind es 6 bzw 5 Ergebnisse).

“Ok, mein Prof würde mir zwar den Hals umdrehen, aber wir habn”

Hehe, vielen Dank, das hat soweit geklappt. (Klar, wenn man solche Sachen machen muss, dann ist mit der DB wohl was von Grund auf nicht in Ordnung!! ;-))

Et volià:

SELECT
a.timestamp AS timestamp,
a.code AS code
FROM enocean_temp
AS a
JOIN
(
SELECT
et2.code AS code
FROM
enocean_temp et2
GROUP BY
et2.code HAVING COUNT(*) > 1
)
AS b
ON a.code = b.code LIMIT 3;

1 „Gefällt mir“

Wunderbar, formatiert sieht es sogar schnieke aus. :smiley:

mit Hals umdrehen meinte ich natürlich, dass ich dort noch eine where-Klausel eingebaut habe (3.), was ja eigentlich nicht unbedingt so muss… :smiley:

schönen Abend

Noch mal vielen Dank und Dir auch einen schönen Abend!! :slight_smile:

besser statt Join Einschränkung: WHERE a.code in (Subquery mit count(*) > 1)


und was soll das bringen?
von Beispielen wie am Anfang
1
1
1
2
2
2
3
3
4
5

werden die einzelnen wie 4 und 5 ausgeschlossen und dann limit 3
-> das kann als Ergebnis 1, 1, 1 sein, aber auch 1, 2, 3 oder 2, 3, 3,


auf jeden Fall nur drei Ergebnisse und nicht alle Einträge, auch 4 + 5, auf maximal drei je Sorte begrenzt?..

Eine Tabelle mit den Einträgen

1
1
1
2
2
2
3
3
4
5

sollte* nach der Abfrage 1:1 bleiben, solange nicht mehr als 3x drin ist, wäre alles ok.

  • Es darf aber auch so sein, dass nicht mehr oder auch nicht weniger als 3 gleiche Datensätze mit dem Query ausgegeben werden.

scheint aber nicht zu klappen -> “zeile” ist im Resultset immer 1…

CASE/ELSE war verkehrt bei der Lösung, welche mir vorgeschlagen wurde:

SELECT * FROM (
SELECT
CASE code WHEN @c THEN
@curRow := 1
ELSE @curRow := @curRow + 1
END as zeile,
@code := code AS code
FROM enocean_temp
INNER JOIN (SELECT @curRow := 0, @code := MIN(CODE) FROM enocean_temp) r) x
WHERE zeile < 4;