2010-04-27 1 views
7

Ich habe die folgende Tabellendefinition mit Beispieldaten. In der folgenden Tabelle Kunden Produkt & Daten sind SchlüsselfelderWie finden Sie N fortlaufende Datensätze in einer Tabelle mit SQL

Table One 
Customer Product Date   SALE 
    X   A  01/01/2010 YES 
    X   A  02/01/2010 YES 
    X   A  03/01/2010 NO 
    X   A  04/01/2010 NO 
    X   A  05/01/2010 YES 
    X   A  06/01/2010 NO 
    X   A  07/01/2010 NO 
    X   A  08/01/2010 NO 
    X   A  09/01/2010 YES 
    X   A  10/01/2010 YES 
    X   A  11/01/2010 NO 
    X   A  12/01/2010 YES 

In der obigen Tabelle, ich brauche die N oder> N aufeinander folgende Datensätze zu finden, wo es kein Verkauf, war Sale Wert ‚NO‘ Zum Beispiel wenn N 2, das die Ergebnismenge zurückkehren würde die folgenden

 Customer Product Date   SALE 
     X   A  03/01/2010 NO 
     X   A  04/01/2010 NO 
     X   A  06/01/2010 NO 
     X   A  07/01/2010 NO 
     X   A  08/01/2010 NO 

mir jemand mit einer SQL-Abfrage die gewünschten Ergebnisse helfen kann zu bekommen. Ich benutze SQL Server 2005. Ich begann mit ROW_NUMBER() UND PARTITION Klauseln zu spielen, aber kein Glück. Danke für jede Hilfe

+0

Haben Sie Zugriff auf das Tabellenschema? – munch

+0

Hallo, Ich habe Zugriff auf das Tabellenschema. – user320587

+0

Die Daten im Beispiel scheinen die Ersten des Monats zu sein. Sind die Daten tatsächlich so angeordnet oder handelt es sich nur um Beispieldaten? Wenn nicht, was bedeutet "konsekutiv" in diesem Zusammenhang. – MJB

Antwort

3

Sie müssen Ihre Tabelle gegen sich selbst anpassen, als ob dort 2 Tabellen waren. So verwenden Sie zwei Aliase, o1 und o2 auf den Tisch zu verweisen:

SELECT DISTINCT o1.customer, o1.product, o1.datum, o1.sale 
    FROM one o1, one o2 
    WHERE (o1.datum = o2.datum-1 OR o1.datum = o2.datum +1) 
    AND o1.sale = 'NO' 
    AND o2.sale = 'NO'; 
customer | product | datum | sale 
----------+---------+------------+------ 
X  | A  | 2010-01-03 | NO 
X  | A  | 2010-01-04 | NO 
X  | A  | 2010-01-06 | NO 
X  | A  | 2010-01-07 | NO 
X  | A  | 2010-01-08 | NO 

Bitte beachte, dass ich die Abfrage auf einer PostgreSQL-Datenbank durchgeführt - vielleicht unterscheidet sich die Syntax auf MS-SQL-Server, vielleicht an dem Alias ​​‚FROM vielleicht, und vielleicht können Sie nicht auf diese Weise hinzufügen/subtrahieren.

+0

Hallo Stefan, Ihr Vorschlag funktioniert perfekt. Wie gehe ich mit dem N aufeinanderfolgenden Fall um? – user320587

+0

Ich fürchte, ich bekomme diesen N-Teil Ihrer Frage genau jetzt. Hm. Trickreich. Sie möchten N = 16 oder N = 375 spezifizieren und erhalten ein analoges Ergebnis für mindestens 16 oder 375 Daten? Von welchen Ns reden wir? Ich brauche mehr Platz und füge eine zusätzliche Antwort hinzu. –

+0

Hallo Stefan, das N ist variabel. Dieses N wird vom Benutzer zur Laufzeit der Abfrage angegeben. Ich konnte mir dafür eine Lösung einfallen lassen und werde sie bald posten. Vielen Dank für Ihre Hilfe. Ich schätze es. Javid – user320587

0

Ok, wir brauchen eine variable Antwort. Wir suchen nach einem Datum, wo wir N folgende Daten haben, alle mit dem Verkaufsfeld sind NEIN.

SELECT d1.datum 
FROM one d1, one d2, i 
WHERE d1.sale = 'NO' AND d2.sale = 'NO' 
    AND d1.datum = (d2.datum - i) 
    AND i > 0 AND i < 4 
GROUP BY d1.datum 
HAVING COUNT (*) = 3; 

Dies gibt uns das Datum, das wir für die Unterabfrage verwenden.

Hinweise:

  • habe ich 'Datum' statt Datum, weil Datum ein reserviertes Schlüsselwort auf postgresql ist.

  • In Oracle können Sie eine virtuelle Tabelle Dummy verwenden, die alles enthält, was Sie fragen, wie 'SELCT foo von Dual WHERE foo in (1, 2, 3);' was dir 1, 2, 3 geben wird, wenn ich mich richtig erinnere. Abhängig vom Hersteller, könnte es andere Tricks geben, um eine Sequenz 1 zu N zu bekommen. Ich habe eine Tabelle i mit Spalte i erstellt und sie mit den Werten 1 bis 100 gefüllt, und ich erwarte, dass N nicht 100 überschreitet; Seit einigen Versionen enthält postgresql eine Funktion 'generate_series (from, to)', die das Problem ebenfalls lösen könnte und Ähnlichkeiten mit Lösungen für Ihre spezifische Datenbank haben könnte. Aber Tabelle I sollte herstellerunabhängig arbeiten.

  • wenn N == 17, Sie 3 Plätze ändern müssen, von 3 bis 17.

Die letzte Abfrage wird:

SELECT o4.* 
FROM one o3, one o4 
WHERE o3.datum = (
    SELECT d1.datum 
    FROM one d1, one d2, i 
    WHERE d1.sale = 'NO' AND d2.sale = 'NO' 
     AND d1.datum = (d2.datum - i) 
     AND i > 0 AND i <= 3 
    GROUP BY d1.datum 
    HAVING COUNT (*) = 3) 
AND o4.datum <= o3.datum + 3 
AND o4.datum >= o3.datum; 
customer | product | datum | sale 
----------+---------+------------+------ 
X  | A  | 2010-02-06 | NO 
X  | A  | 2010-02-07 | NO 
X  | A  | 2010-02-08 | NO 
X  | A  | 2010-02-09 | NO 
+0

Oh, ich erwähne, dass dies nur exakte Übereinstimmungen liefert, wo N = 3, nicht N> = 3. –

1

Ein anderer Ansatz, von Munchs inspiriert letzte Linie.

Get - für ein bestimmtes Datum das erste Datum mit JA später als das und das letzte Datum mit JA früher als das. Diese bilden die Grenze, wo unsere Termine passen soll.

SELECT (o1.datum), 
    MAX (o3.datum) - MIN (o2.datum) AS diff 
FROM one o1, one o2, one o3 
WHERE o1.sale = 'NO' 
AND o3.datum < 
    (SELECT MIN (datum) 
    FROM one 
    WHERE datum >= o1.datum 
    AND SALE = 'YES') 
AND o2.datum > 
    (SELECT MAX (datum) 
    FROM one 
    WHERE datum <= o1.datum 
    AND SALE = 'YES') 
GROUP BY o1.datum 
HAVING MAX (o3.datum) - MIN (o2.datum) >= 2 
ORDER BY o1.datum; 

Vielleicht ist es eine Art von Optimierung benötigt, weil Tabelle eine 5-mal in der Abfrage beteiligt ist. :)

+0

-1 Zur impliziten 'where' Syntax – Johan

+0

Mögen Sie es einfach nicht, oder haben Sie begründete Argumente dagegen? –

+0

A. es ist verwirrend, B. Sie können nicht sagen, welche sind die Join-Kriterien und welche die Filterkriterien, C. es ist fehleranfällig ein Fehler und Sie haben eine Cross-Join, D. Es erlaubt nicht für Links Joins. E. Es ist inkonsistent, Sie machen innere Joins mit impliziter Syntax, müssen aber Outer Joins mit expliziter Syntax F ausführen. Es folgt nicht Best Practices G. Es erschwert es dem Abfrageoptimierer, effizienten Code zu erzeugen (besonders auf SQL Server). – Johan

0

Danke an alle für die Veröffentlichung Ihrer Lösung.Dachte, ich würde auch meine Lösung mit allen teilen. Ich habe diese Lösung von einem anderen Mitglied des SQL Server Central-Forums erhalten. Ich werde definitiv keine Anerkennung für diese Lösung bekommen.

DECLARE @CNT INT 
SELECT @CNT = 3 

SELECT * FROM 
(
    SELECT 
    [Customer], [Product], [Date], [Sale], groupID, 
    COUNT(*) OVER (PARTITION BY [Customer], [Product], [Sale], groupID) AS groupCnt 
    FROM 
    (
    SELECT 
     [Customer], [Product], [Date], [Sale], 
     ROW_NUMBER() OVER (PARTITION BY [Customer], [Product] ORDER BY [Date]) 
     - ROW_NUMBER() OVER (PARTITION BY [Customer], [Product], [Sale] ORDER BY [Date]) AS groupID 
    FROM 
     [TableSales] 
) T1 
) T2 
WHERE 
    T2.[Sale] = 'NO' AND T2.[groupCnt] >= @CNT 
+0

Diese Abfrage kann sehr, sehr langsam sein (N^3 Abfragen, wenn die Datenbank sie nicht optimieren kann) – Nicole

Verwandte Themen