2015-05-27 20 views
6

Próbuję zamówić konkretne zapytanie, biorąc pod uwagę następne i poprzednie rekordy, ale nie mogę tego zrobić. Chciałbym zamówić przez liczbę i literę, ale jeśli, na przykład, ostatnia litera z numerem 1 jest równa jednej z liter numeru 2, chcę zmienić kolejność, tak aby list pasował do następujących rekord.Sortowanie w oparciu o kolejne i wcześniejsze rekordy w SQL

Create script and SQL fiddle demo

create table Parent (
id [bigint] IDENTITY(1,1), 
number bigint NOT NULL, 
PRIMARY KEY (id) 
) 
GO 

create table Child (
id [bigint] IDENTITY(1,1), 
parentId BIGINT, 
letter VARCHAR(1) NOT NULL, 
PRIMARY KEY (id), 
UNIQUE (parentId, Letter), 
FOREIGN KEY (parentId) REFERENCES Parent(id) 
) 
GO 

INSERT Parent (number) VALUES (1) 
INSERT Parent (number) VALUES (2) 
INSERT Parent (number) VALUES (3) 

INSERT Child (parentId, letter) VALUES (1, 'A') 
INSERT Child (parentId, letter) VALUES (1, 'C') 
INSERT Child (parentId, letter) VALUES (2, 'B') 
INSERT Child (parentId, letter) VALUES (2, 'C') 
INSERT Child (parentId, letter) VALUES (3, 'B') 
INSERT Child (parentId, letter) VALUES (3, 'D') 

Aktualny zapytania

Obecnie jestem sortowaniu z tego zapytania:

SELECT P.number, C.letter 
FROM Child C 
JOIN Parent P ON C.parentId = P.id 
ORDER BY P.number, C.letter 

Aktualny wynik ustawić

number    letter 
-------------------- ------ 
1     A 
1     C 
2     B 
2     C 
3     B 
3     D 

Oczekiwany wynik ustawić

Aby wyjaśnić, co tak naprawdę chcesz zrobić, jest tu oczekiwany zestaw wyników (z C do B numer 2 przełączane).

number    letter 
-------------------- ------ 
1     A 
1     C 
2     C --switched 
2     B --switched 
3     B 
3     D 

Inne wymagania i pytanie

  • Ma pracować w SQL Server 2005.
  • Istnieje scenariusz, w którym używane są 3 litery na cyfrę, cieszę się, jeśli po prostu używa najlepszego dopasowania.
  • Właściwie interesuję się również rozwiązaniami do późniejszych wersji SQL Server (do nauki), ale te nie odpowiadają na moje pytanie.

Czy ktoś może wskazać mi właściwy kierunek postępowania?

+0

Proszę zobaczyć to pytanie dla nowego scenariusza, który przyszedł mi do głowy, przez komentarze na zaakceptowanej odpowiedzi: http://stackoverflow.com/questions/30480504/complex-sorting-based-on- next-and-previous-records-in-sql –

Odpowiedz

6

Możesz zrobić coś takiego.

  1. zidentyfikować pierwszą i ostatnią literę każdego rodzica za pomocą ROW_NUMBER() i PARTITION BY
  2. Mecz ostatni rekord z poprzedniego id z pierwszego rekordu następnego id.
  3. Sprawdź, czy drugi id rodzic ma żadnych list, który odpowiada z literą wybranego powyżej
  4. Użyj LEFT JOIN i używać CASE lub ISNULL ustawić wyższy priorytet dla takiego id rekordu w której list był dopasowane

Zapytanie

;WITH CTE AS 
(
SELECT id,ParentID,letter, 
ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID) first_element, 
ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID DESC) Last_element 
FROM Child 
), CTE2 AS 
(
SELECT c1.id,c1.parentid,c1.letter,c2.parentid as c2parentid 
FROM CTE c1 
INNER JOIN CTE c2 
ON c1.last_element = 1 
AND c2.first_element = 1 
AND c1.id +1 = c2.id 
), CTE3 AS 
(
SELECT C.parentid,C.id 
FROM CTE2 
INNER JOIN child C ON CTE2.c2parentid = C.parentid 
AND C.letter = CTE2.letter 
) 
SELECT P.number, C.letter 
FROM Child C 
JOIN Parent P ON C.parentId = P.id 
LEFT JOIN CTE3 ON CTE3.id = C.id 
ORDER BY P.number, ISNULL(CTE3.id,0) DESC, C.letter 

Wyjście

number letter 
1 A 
1 C 
2 C 
2 B 
3 B 
3 D 

SQL Fiddle

EDIT

Jeśli Twój ids nie są sekwencyjne, można zmienić CTE1 i CTE2 tak aby wykorzystać ROW_NUMBER()OVER(ORDER BY ID) seq_id.

;WITH CTE AS 
(
SELECT id,ParentID,letter, 
ROW_NUMBER()OVER(ORDER BY ID) seq_id, 
ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID) first_element, 
ROW_NUMBER()OVER(PARTITION BY parentId ORDER BY ID DESC) Last_element 
FROM Child 
), CTE2 AS 
(
SELECT c1.id,c1.parentid,c1.letter,c2.parentid as c2parentid 
FROM CTE c1 
INNER JOIN CTE c2 
ON c1.last_element = 1 
AND c2.first_element = 1 
AND c1.seq_id + 1 = c2.seq_id 
) 

Reszta kodu pozostaje taka sama.

SQL Fiddle

+0

Bardzo miło, próbowałem zrobić coś takiego, ale byłeś waaaaaaaaay szybciej: p, nie byłem nawet w połowie drogi –

+0

'AND c1.id +1 = c2.id "to dotyczy mnie trochę, a co, jeśli identyfikacja się nie powiedzie? –

+0

możesz zrobić 'row_number() over (order by id)', a następnie użyć tego – ughai