2014-11-23 24 views
7

Mam tabeli jak tenPobierz poprzedni i następny wiersz z wierszy wybranych z (gdzie) warunkach

Na przykład mam to stwierdzenie:

my name is joseph and my father name is brian 

To stwierdzenie jest podzielony słowem jak ten stół

------------------------------ 
|  ID  | word  | 
------------------------------ 
|  1  |  my  | 
|  2  |  name | 
|  3  |  is  | 
|  4  |  joseph | 
|  5  |  and  | 
|  6  |  my  | 
|  7  |  father | 
|  8  | name  | 
|  9  |  is  | 
|  10  | brian | 
------------------------------ 

Chcę dostać poprzedni i następny wartości samego słowa

na przykład Chcę uzyskać poprzednie i następne słowo "nazwa":

-------------------------- 
| my | name | is | 
-------------------------- 
| father | name | is | 
-------------------------- 

Jak mogę to zrobić?

+1

Czy w twoim identyfikatorze są jakieś luki? – plalx

+2

Jakiej bazy danych używasz? Jakiej wersji tej bazy danych używasz? SQL jest językiem, ale prawie każda baza danych ma nieco inny dialekt SQL, który obsługuje. Tego typu rzeczy są znacznie łatwiejsze, gdy używasz bazy danych obsługującej funkcje analityczne, takie jak 'lead' i' lag'. –

+0

Używam SQL 2012, obsługuję LGD i LEAD, ale chcę szybko uzyskać wynik za 5 milionów słów, ważne jest, aby wynik był bardzo szybki w moim programie. –

Odpowiedz

13

ty nie określił swoich DBMS, więc po to ANSI SQL:

select prev_word, word, next_word 
from (
    select id, 
      lag(word) over (order by id) as prev_word, 
      word, 
      lead(word) over (order by id) as next_word 
    from words 
) as t 
where word = 'name'; 

SQLFiddle: http://sqlfiddle.com/#!12/7639e/1

+0

z tym kodem, w wewnętrznym oświadczeniu select cały wiersze tabeli są łączone i na zewnątrz: wybierz wiersze z tym samym wyrazem, jeśli chcę wziąć tylko jedno słowo, wszystkie słowa tabel są połączone, a następnie wybierz jedną z nich ... –

+0

jest ok, ale mam ponad 100 milionów rekordów, i czas na wynik jest bardzo ważny, czy mogę poprawić wydajność tego kodu? –

+0

Chcę szybko uzyskać wynik, możesz mi pomóc? –

1

Spróbuj

SELECT * 
FROM tablename a 
WHERE ID IN(SELECT ID - 1 
      FROM tablename 
      WHERE word = 'name') -- will fetch previous rows of word `name` 
     OR ID IN(SELECT ID + 1 
       FROM tablename 
       WHERE word = 'name') -- will fetch next rows of word `name` 
     OR word = 'name' -- to fetch the rows where word = `name` 
+0

Jest ok, ale mam ponad 100 milionów rekordów i czas na wynik jest bardzo ważne, czy mogę poprawić wydajność kodu? –

3

Bez podzapytaniami:

SELECT a.word 
FROM my_table AS a 
JOIN my_table AS b 
ON b.word = 'name' AND abs(a.id - b.id) <= 1 
ORDER BY a.id 
+0

to nie zadziała, jeśli są luki w sekwencji id –

+0

@ t-clausen.dk op powiedział tabela została utworzona z podziału zdanie, więc nie powinno być żadnej luki – Will

1

Oto inne podejście, jeśli chcesz, aby wybór był szybki. To wymaga trochę pracy przygotowawczej.

  • Tworzenie nowej kolumny (na przykład „zwrot”) w bazie danych, która będzie zawierać słowa chcesz. (tj. poprzedni, bieżący i następny).

  • Napisz wyzwalacz, który na wkładce Dołącza nowe słowo do wyrażenia poprzedniego rzędzie i poprzedza słowo poprzedniego rzędu do słowa nowego wiersza i wypełnia frazę.

  • Jeśli poszczególne słowa mogą się zmienić, potrzebny jest czynnik uruchamiający przy aktualizacji, aby zachować synchronizację frazy.

Następnie wybierz frazę. Otrzymujesz znacznie lepszą prędkość, ale kosztem dodatkowego miejsca do przechowywania i wolniejszego wkładania i trudniejszej konserwacji. Oczywiście musisz zaktualizować kolumnę frazy dla istniejących rekordów, ale masz SQL, aby to zrobić w innych odpowiedziach.

1

Użyj Join, aby uzyskać oczekiwany wynik dla SQL Server 2005 plus.

create table words (id integer, word varchar(20)); 

    insert into words 
    values 
    (1 ,'my'), 
    (2 ,'name'), 
    (3 ,'is'), 
    (4 ,'joseph'), 
    (5 ,'and'), 
    (6 ,'my'), 
    (7 ,'father'), 
    (8 ,'name'), 
    (9 ,'is'), 
    (10,'brian'); 

SELECT A.Id , C.word AS PrevName , 
       A.word AS CurName , 
       B.word AS NxtName 
FROM words AS A 
LEFT JOIN words AS B ON A.Id = B.Id - 1 
LEFT JOIN words AS C ON A.Id = C.Id + 1 
WHERE A.Word = 'name' 

Wynik:

enter image description here

Fiddler Demo

-1

utworzyć indeks na mojej kolumnie słowa i ustawić ten kod, aby uzyskać wynik szybko:

WITH CTE AS 
(SELECT * FROM WordsTable WHERE word=N'Name') 
SELECT   
    t2.word AS previousWord, 
    t1.word, 
    t3.word AS nextWord 
FROM 
    WordsTable AS t2, 
    CTE AS t1, 
    WordsTable AS t3 
WHERE 
    (t2.ID + 1)= t1.ID AND 
    (t3.ID - 1) = t1.ID 
+0

Nie używaj identyfikatorów jako znaczących pól –

1

dlaczego łeb ody dać prostą odpowiedź?

SELECT LAG(word) OVER (ORDER BY ID) AS PreviousWord , 
     word , 
     LEAD(word) OVER (ORDER BY ID) AS NextWord 
FROM words; 
+0

Nie możesz ograniczyć wyników do następnych/poprzednich konkretne słowo. Przyjęta odpowiedź ma klauzulę "WHERE". – Gili