2010-02-02 15 views
10

Mam SQL Compact Database, która zawiera tabelę nagłówków pakietów IP. Tabela wygląda następująco:Łączenie SQL Rows

Table: PacketHeaders  

ID SrcAddress SrcPort DestAddress DestPort Bytes 
1 10.0.25.1 255  10.0.25.50 500  64 
2 10.0.25.50 500  10.0.25.1 255  80 
3 10.0.25.50 500  10.0.25.1 255  16 
4 75.48.0.25 387  74.26.9.40 198  72 
5 74.26.9.40 198  75.48.0.25 387  64 
6 10.0.25.1 255  10.0.25.50 500  48 

Muszę wykonać zapytanie, aby wyświetlić "rozmowy" odbywające się w sieci lokalnej. Pakiety przechodzące z A -> B są częścią tych samych rozmów co pakiety wychodzące z B -> A. Muszę wykonać zapytanie, aby pokazać trwające rozmowy. Zasadniczo co potrzebne jest coś, co wygląda tak:

Returned Query: 

SrcAddress SrcPort DestAddress DestPort TotalBytes BytesA->B BytesB->A 
10.0.25.1 255  10.0.25.50 500  208   112  96 
75.48.0.25 387  74.26.9.40 198  136   72   64 

Jak widać muszę zapytania (lub seria zapytań) do uznania, że ​​A-> B jest taka sama jak B-> A i zerwać bajt się liczy. W żadnym wypadku nie jestem guru SQL, ale wszelka pomoc w tym zakresie byłaby bardzo doceniana.

Odpowiedz

3

Spróbuj tego:

SELECT 
    T1.SrcAddress, 
    T1.SrcPort, 
    T1.DestAddress, 
    T1.DestPort, 
    T1.Bytes + COALESCE(T2.Bytes, 0) AS TotalBytes, 
    T1.Bytes AS A_to_B, 
    COALESCE(T2.Bytes, 0) AS B_to_A 
FROM (
    SELECT SrcAddress, SrcPort, DestAddress, DestPort, SUM(Bytes) AS Bytes 
    FROM PacketHeaders 
    GROUP BY SrcAddress, SrcPort, DestAddress, DestPort) AS T1 
LEFT JOIN (
    SELECT SrcAddress, SrcPort, DestAddress, DestPort, SUM(Bytes) AS Bytes 
    FROM PacketHeaders 
    GROUP BY SrcAddress, SrcPort, DestAddress, DestPort) AS T2 
ON T1.SrcAddress = T2.DestAddress 
AND T1.SrcPort = T2.DestPort 
AND T1.DestAddress = T2.SrcAddress 
AND T1.DestPort = T2.SrcPort 
WHERE T1.SrcAddress < T1.DestAddress OR 
    (T1.SrcAddress = T1.DestAddress AND T1.SrcPort = T1.DestPort) OR 
    T2.DestAddress IS NULL 

tych danych testu:

CREATE TABLE PacketHeaders (ID INT, SrcAddress NVARCHAR(100), SrcPort INT, DestAddress NVARCHAR(100), DestPort INT, Bytes INT); 
INSERT INTO PacketHeaders (ID, SrcAddress, SrcPort, DestAddress, DestPort, Bytes) VALUES 
(1, '10.0.25.1', 255, '10.0.25.50', 500, 64), 
(2, '10.0.25.50', 500, '10.0.25.1', 255, 80), 
(3, '10.0.25.50', 500, '10.0.25.1', 255, 16), 
(4, '75.48.0.25', 387, '74.26.9.40', 198, 72), 
(5, '74.26.9.40', 198, '75.48.0.25', 387, 64), 
(6, '10.0.25.1', 255, '10.0.25.50', 500, 48), 
(7, '10.0.25.2', 255, '10.0.25.50', 500, 48), 
(8, '10.0.25.52', 255, '10.0.25.50', 500, 48); 

To daje następujące wyniki:

'10.0.25.1', 255, '10.0.25.50', 500, 208, 112, 96 
'10.0.25.2', 255, '10.0.25.50', 500, 48, 48, 0 
'10.0.25.52', 255, '10.0.25.50', 500, 48, 48, 0 
'74.26.9.40', 198, '75.48.0.25', 387, 136, 64, 72 

Jak to działa jest pierwsza grupa jednokierunkowych rozmów i suma bajtów się liczy. Zapewnia to, że każda rozmowa będzie reprezentowana dokładnie dwa razy - raz dla każdego kierunku. Ten wynik jest następnie łączony, aby uzyskać pożądany wynik, filtrując duplikaty, poprzez wymuszenie, że (adres, port) A musi być mniejszy niż B. Lewe złączenie jest używane do zezwalania na jednokierunkowe konwersacje.

+0

Zakłada się, że każda ścieżka ma odpowiadający jej przeciwny wpis. Więc wszystko musi być ZŁĄCZEM ZEWNĘTRZNYM, co oznacza, że ​​musisz WYKORZYSTAĆ GRUPĘ ISNULL (T1.SrcAddress, T2.DestAddress), itp. – MatBailie

+0

Edycja usunęła zewnętrzną grupę GROUP BY itp.To nadal działa tylko wtedy, gdy każdy pakiet odpowiada pakietowi idącemu w przeciwnym kierunku. (Ale jeśli ten warunek jest prawdziwy, działa, myślę ...) – MatBailie

+0

Działa to tylko w przypadku rozmów dwukierunkowych. Nie wszystkie rozmowy będą dwukierunkowe. Jak mogę zmodyfikować sprzężenie, aby to złagodzić? – lumberjack4

3

Widzę dwa podstawowe sposoby robienia tego ...
1. Pogrupuj wszystko, ignorując a-> b i b-> a, a następnie samodzielnie dołącz wyniki.
2. Zmień rozmieszczenie danych za pomocą "najniższego" adresu IP w polu "src", ale również utwórz pole "kierunku".

Wariant 2 jest chyba sposób pójdę ...

SELECT 
    SrcAddress, 
    SrcPort, 
    DestAddress, 
    DestPort, 
    SUM(AtoB) + SUM(BtoA), 
    SUM(AtoB), 
    SUM(BtoA) 
FROM 
(
    SELECT 
     CASE WHEN SrcAddress < DestAddress THEN SrcAddress ELSE DestAddress END AS SrcAddress, 
     CASE WHEN SrcAddress < DestAddress THEN SrcPort  ELSE DestPort END AS SrcPort, 
     CASE WHEN SrcAddress < DestAddress THEN DestAddress ELSE SrcAddress END AS DestAddress, 
     CASE WHEN SrcAddress < DestAddress THEN DestPort ELSE ScrPort  END AS DestPort, 
     CASE WHEN SrcAddress < DestAddress THEN Bytes  ELSE 0   END AS AtoB, 
     CASE WHEN SrcAddress < DestAddress THEN 0   ELSE Bytes  END AS BtoA 
    FROM 
     PacketHeaders 
) 
    AS [data] 
GROUP BY 
    SrcAddress, 
    SrcPort, 
    DestAddress, 
    DestPort 

EDIT

Kilka innych odpowiedzi mają wersję tego, co nazwałem wariant 1. będę mieć iść na to zbyt zamiast spamowania komentarzy na odpowiedzi ludzi :(

SELECT 
    ISNULL([AtoB].SrcAddress, [BtoA].DestAddress) 
    ISNULL([AtoB].SrcPort,  [BtoA].DestPort) 
    ISNULL([AtoB].DestAddress, [BtoA].SrcAddress) 
    ISNULL([AtoB].DestPort, [BtoA].SrcPort) 
    ISNULL([AtoB].Bytes,0) + ISNULL([BtoA].Bytes,0), 
    ISNULL([AtoB].Bytes,0), 
    ISNULL([BtoA].Bytes,0) 
FROM 
    (
     SELECT SrcAddress, SrcPort, DestAddress, DestPort, SUM(Bytes) AS Bytes 
     FROM  PacketHeaders 
     WHERE SrcAddress <= DestAddress 
     GROUP BY SrcAddress, SrcPort, DestAddress, DestPort 
    ) 
    AS [AtoB] 
FULL OUTER JOIN 
    (
     SELECT SrcAddress, SrcPort, DestAddress, DestPort, SUM(Bytes) AS Bytes 
     FROM  PacketHeaders 
     WHERE SrcAddress > DestAddress 
     GROUP BY SrcAddress, SrcPort, DestAddress, DestPort 
    ) 
    AS [BtoA] 
     ON [AtoB].SrcAddress = [BtoA].DestPort 
     AND [AtoB].SrcPort  = [BtoA].DestAddress 
     AND [AtoB].DestAddress = [BtoA].SrcPort 
     AND [AtoB].DestPort = [BtoA].SrcAddress 

Ale ja powiedziałem, że nie byłoby zrobić to w ten sposób ...

+0

Jeśli chcę zobaczyć kolumnę o sumie bajtów, muszę ją zamknąć w ramach innej instrukcji SELECT. Czy istnieje czystszy sposób? – lumberjack4

+0

Dodałem wiersz "SUMA (AtoB) + SUMA (BtoA)" dla ciebie ... – MatBailie

+0

Czy jesteś pewien, że CTE programu SQL Server obsługuje IsNull? Znalazłem ten wpis: http://sqlserverce.org/blogs/faq/archive/2007/02/16/isnull-vs-coalesce.aspx –