2010-04-19 15 views
5

Dato questi dati in SQL Server 2005:SQL Tricky - Selezionare i numeri non adiacenti

SectionID Name 
1   Dan 
2   Dan 
4   Dan 
5   Dan 
2   Tom 
7   Tom 
9   Tom 
10  Tom 

Come dovrei selezionare i record in cui l'Idsezione deve essere + -2 o più da un'altra sezione per lo stesso nome.

Il risultato sarebbe:

1 Dan 
4 Dan 
2 Tom 
7 Tom 
9 Tom 

Grazie per la lettura!

+2

Hmm, tu dici "1 Dan" è nei risultati e quindi "2 Dan" non lo è, ma perché non è che "2 Dan" è nei risultati e quindi "1 Dan" non lo è? Penso che tu abbia assunto qualche ordine qui, che in realtà non fa SQL. Cosa vuoi veramente raggiungere? – wilth

+0

@wilth, SQL può riconoscere operatori relazionali come Unreason

+0

@Daniel, cosa vorresti tornare se tu avessi anche (3, Dan) nel tavolo di partenza? Vorresti registrare (1, Dan) e (3, Dan) o solo il primo? L'unica condizione è che la differenza tra gli ID selezionati debba essere maggiore di 1 (o ci sono condizioni aggiuntive)? Se questa è l'unica condizione, cosa vuoi fare in caso di sequenza come: 5, 6, 7, 8, 10, 11, 12? (ha due soluzioni, una che inizia con 5 ha 4 elementi nella risposta, ma se inizi con 6 puoi selezionare 5 elementi); come distinguere? – Unreason

risposta

3
SELECT * 
FROM mytable a 
WHERE NOT EXISTS 
    (SELECT * 
    FROM mytable b 
    WHERE a.Name = b.Name 
    AND a.SectionID = b.SectionID + 1) 
+0

+1 Soluzione semplice e corretta. Un indice composito su '(SectionID, Name)' sarà molto vantaggioso per questa query. – Tomalak

+1

quindi se si dispone di dati: '1 Tom 2 Tom 3 Tom 4 Tom' si otterrebbe zero record indietro. Che sospetto non sia corretto. – ninesided

+0

@nineided, non proprio - la query restituisce tutti i record dalla tabella a dove per il seziono non vi è alcun record nella stessa tabella con sectionid meno di uno (quindi nel tuo esempio contatore 1 Tom verrebbe restituito). – Unreason

0

Ecco LEFT JOIN variante della risposta di Anthony (rimuove consecutivi id dai risultati)

SELECT a.* 
FROM mytable a 
    LEFT JOIN mytable b ON a.Name = b.Name AND a.SectionID = b.SectionID + 1 
WHERE b.SectionID IS NULL 

EDIT: Poiché non v'è un'altra interpretazione della questione (semplicemente ottenere risultati in cui ID sono più di 1 numero a parte) qui è un altro tentativo di risposta:

WITH alternate AS (
SELECT sectionid, 
     name, 
     EXISTS(SELECT a.sectionid 
       FROM mytable b 
       WHERE a.name = b.name AND 
        (a.sectionid = b.sectionid-1 or a.sectionid = b.sectionid+1)) as has_neighbour, 
     row_number() OVER (PARTITION by a.name ORDER BY a.name, a.sectionid) as row_no 
FROM mytable a 
) 
SELECT sectionid, name 
FROM alternate 
WHERE row_no % 2 = 1 OR NOT(has_neighbour) 
ORDER BY name, sectionid; 

dà:

sectionid | name 
-----------+------ 
     1 | Dan 
     4 | Dan 
     2 | Tom 
     7 | Tom 
     9 | Tom 

Logica: se un record ha vicini con lo stesso nome e id +/- 1 allora ogni riga dispari viene presa, se non ha tali vicini allora ottiene la riga indipendentemente se è pari o dispari.

Come indicato nel commento, la condizione è ambigua: all'inizio di ogni nuova sequenza è possibile iniziare con righe pari o dispari e i criteri saranno comunque soddisfatti con risultati diversi (anche con un numero diverso di risultati).

+0

Diverso, ma ha ancora lo stesso problema menzionato da @ninesided. – PaulG

+0

Cattiva idea dal momento che il server SQL non sarà in grado di convertirlo in un antijoin. – erikkallen

+0

@PaulG, puoi spiegare il problema; Ho chiesto maggiori dettagli sul commento ninesided sotto la risposta di Anthony ma nessuno è stato fornito (per quanto posso vedere entrambe le query restituiscono i dati richiesti) @erikkallen, sono d'accordo che non lo farebbe, ma le prestazioni dovrebbero essere testate, i NON ESISTENTI di le prestazioni delle subquery correlate non sono ovviamente superiori alle prestazioni LEFT JOIN, anche con una selettività così elevata. – Unreason