2012-04-10 11 views
5

Aby ustawić skonsolidowane zarządzanie kontem, chcę się dowiedzieć, że konta mają "dokładnie taki sam" zestaw właścicieli.Jak mogę znaleźć grupy rekordów, które pasują do innych grup rekordów (podział relacyjny?)

Myślę, że może to działać, aby przestawić właścicieli z dynamicznym sql, a następnie użyć funkcji rankingu , ale nie chcę realizować tego podejścia; Nie mam górnego limitu liczby nazw, które można powiązać z kontem podanym w , dlatego chcę uniknąć dynamicznego SQL.

moje dane (również to co http://www.sqlfiddle.com/#!3/1d36e)

CREATE TABLE allacctRels 
(account INT NOT NULL, 
module CHAR(3) NOT NULL, 
custCode CHAR(20) NOT NULL) 


INSERT INTO allacctrels 
(account, module, custCode) 
VALUES 
(1, 'DDA', 'Wilkie, Walker'), 
(1, 'DDA', 'Houzemeal, Juvy'), 
(2, 'CDS', 'Chase, Billy'), 
(2, 'CDS', 'Norman, Storm'), 
(3, 'CDS', 'Chase, Billy'), 
(3, 'CDS', 'Norman, Storm'), 
(7, 'CDS', 'Perkins, Tony'), 
(15, 'SVG', 'Wilkie, Walker'), --typo in name before mwigdahl's response 
(16, 'SVG', 'Wilkie, Walker'), -- corrected typo here too 
(606, 'DDA', 'Norman, Storm'), 
(606, 'DDA', 'Chase, Billy'),-- corrected 2nd typo found 
(4, 'LNS', 'Wilkie, Walker'), 
(4, 'LNS', 'Houzemeal, Juvy'), 
(44, 'DDA', 'Perkins, Tony'), 
(222, 'DDA', 'Wilkie, Walker'), 
(222, 'DDA', 'Houzemeal, Juvy'), 
(17, 'SVG', 'Wilkie, Walker'), -- added these three rows in edit, SVG 17 doesn't match any dda 
(17, 'SVG', 'Welch, Raquel'), 
(17, 'SVG', 'Houzemeal, Juvy') 

Chcę dowiedzieć się, na każdym module-konta, co najniższa DDA konto jest to, że ma te same właścicieli z nim związane.

W przykładowych danych chciałbym te wyniki, trzecia kolumna to najniższe konto DDA, które ma tych samych właścicieli. Wyniki powinien mieć taką samą liczbę rzędów jak moduł/konta thereâ ponownego kombinacje - jednym rzędzie za każdym wierszu „SELECT moduł różne, odpowiadają OD allAcctRels”)

1, DDA, 1 
2, CDS, 606 
3, CDS, 606 
15, SVG, NULL 
16, SVG, NULL 
606, DDA, 606 
4, LNS, 1 
7, CDS, 44 
44, DDA, 44 
222, DDA, 1 
17, SVG, NULL -- added to original post. 

SVG 15 i 16 mają nie pasujące do żadnego DDA konto, więc nie ma znaczenia, że ​​ pasują do siebie nawzajem, uzyskują NULL dla konta do konsolidacji. EDYCJA: SVG 17 nie pasuje do niczego, mimo że istnieje akcent DDA, który ma wszystkie swoje posiadacze w SVG 17, kombinacja posiadaczy w SVG 17 nie występuje dla żadnego akta DDA. Każde konto DDA pasuje do siebie, chyba że istnieje konto dda o tym samym właścicielu i niższym DDA (tak jak w przypadku DDA 222).

Widzę, że jednym z ogólnych podejść jest przestawianie każdego konta, grupy w tabeli przestawnej i użycie parametru numer_wiersza. Biorąc pod uwagę nieograniczoną liczbę posiadaczy powiązanych z każdym kontem, myślę, że obracanie wymagałoby dynamicznego SQL, którego wolałbym uniknąć.

Wydaje mi się, że jest to problem "relacji z relacjami", z podziałem relacyjnym prawdopodobnie "nakarmionym" przez APLIKACJĘ KRZYŻOWĄ. Wypróbowałem napisanie funkcji, która zajęłaby tabelę posiadaczy rachunków powiązaną z konkretnym kontem i znalazłem najniższe konto dda, wzdłuż linii pokazanej poniżej, celem było sprawdzenie, czy cała liczba osób w danym Konto jest takie samo, jak liczba osób, które dołączyły konto do danego konta dda, ale nie wiem, jak "zasilić" tabele z numerami kont w tej funkcji.

-- this is what I tried but I'm not sure it the logic would work 
-- and I can't figure out how to pass the account holders for each 
-- account in. This is a bit changed from the function I wrote, some 
    -- extraneous fields removed and cryptic column names changed. So it 
    -- probably won't run as is. 

    -- to support a parameter type to a tape 
-- CREATE type VisionCustomer as Table 
-- (customer varchar(30)) 

CREATE FUNCTION consolidatable 
(@custList dbo.VisionCustomer READONLY) 
RETURNS char(10) 
AS 
BEGIN 
DECLARE @retval Varchar(10) 
DECLARE @howmany int 
select @howmany=Count(*) FROM @custlist; 

SELECT @retval = min (acct) FROM allAcctRels 
    JOIN @custlist 
     On VendorCustNo = Customer 
      WHERE acctType = 'DDA' 
      GROUP BY acct 
      HAVING (count(*) = @howmany) 
      and 
      COUNT(*) = (select Count(*) FROM allAcctRels X 
    WHERE X.acctType = 'DDA' 
    AND X.account = AllAcctRels.account) ; 
RETURN @retval 
END; 
+0

uwaga, że ​​„Chase, Billie” w wierszu 606 DDA nie jibe z wynikowego mówisz, że chcesz z powrotem ; Myślę, że chcesz, żeby to było "Chase, Billy", prawda? – mwigdahl

+0

Tak, to prawda, przepraszam za to, i dziękuję, będę ponownie edytować teraz –

Odpowiedz

1

To naprawdę okazuje się całkiem proste, jeśli dobrze rozumiem. Wypróbuj to:

SELECT a.account, a.module, MIN(b.account) 
FROM allacctRels a 
    LEFT JOIN allacctRels b ON a.custCode = b.custCode AND b.module = 'DDA' 
GROUP BY a.account, a.module 

EDYCJA: Powyższe nie działa po wyjaśnieniach, ale powinno. Jest to rzeczywiście rodzaj podziału relacyjnego. Prawdopodobnie nie jest to najbardziej wydajny plan zapytań na świecie, ale działa.

SELECT a.account, a.module, MIN(b.account) 
FROM allacctRels a 
    LEFT JOIN allacctRels b ON b.module = 'DDA' 
    AND 
    -- first test is to confirm that the number of matching names for this combination equals the number of names for the DDA set... 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
      INNER JOIN allacctRels a2 ON b2.custCode = a2.custCode 
     WHERE a.account = a2.account AND b.account = b2.account 
    ) = 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
     WHERE b.account = b2.account 
    ) 
    AND 
    -- second test is to confirm that the number of names for the DDA set equals the number of names for the base set... 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
     WHERE b.account = b2.account 
    ) = 
    (
     SELECT COUNT(*) 
     FROM allacctRels a2 
     WHERE a.account = a2.account 
    ) 
GROUP BY a.account, a.module 
+0

+1; to pierwsza rzecz, która pojawiła się w mojej głowie, kiedy na nią patrzyłem. – lyrisey

+0

Ale tutaj zachowujesz wszystkie wiersze, które mają dowolne dopasowanie po stronie "b" (DDA), prawda? Np., Jeśli dodaję "Welch Raquel" do każdego konta innego niż DDA, wyniki dla nie-dda nie zmienią się, ale nie powinno być żadnych dopasowań, ponieważ żaden nie-DDA nie ma Raquel Welch. Miałem dwie literówki w "Walker Wilkie" w moich przykładowych danych, które sprawiły, że to zapytanie dało takie same wyniki jak mój przykład, i nie miałem żadnych przykładów w moich danych kont z "ekstra" osobą, która nie powinna pasować. Zaktualizowałem sql fiddle, a także zaktualizuję powyższe przykłady. –

+0

Dzięki za wyjaśnienie. Patrzę na to jeszcze raz. – mwigdahl

1

Wierzę, że to jest to, czego szukasz (http://www.sqlfiddle.com/#!3/f96c5/1):

;WITH AccountsWithOwners AS 
(
    SELECT DISTINCT 
    DA.module 
    , DA.account 
    , STUFF((SELECT 
       ',' + AAR.custCode 
       FROM allacctRels AAR 
       WHERE AAR.module = DA.module 
       AND AAR.account = DA.account 
       ORDER BY AAR.custCode 
       FOR XML PATH('')) 
       , 1, 1, '') AS Result 
    FROM allacctRels DA 
) 
, WithLowestDda AS 
(
    SELECT 
     AWO.module 
     , AWO.account 
     , MatchingAccounts.account AS DdaAccount 
     , ROW_NUMBER() OVER(PARTITION BY AWO.module, AWO.account ORDER BY MatchingAccounts.account) AS Row 
    FROM AccountsWithOwners AWO 
    LEFT JOIN AccountsWithOwners MatchingAccounts 
     ON MatchingAccounts.module = 'DDA' 
     AND MatchingAccounts.Result = AWO.Result 
) 
SELECT 
    account 
    , module 
    , DdaAccount 
FROM WithLowestDda 
WHERE Row = 1 
+0

Wygląda na to, że zwyciężczyni, dostał się w momencie, w którym muszę zacząć tworzyć kopie zapasowe i wrócić do domu. Zobaczę to jeszcze dziś wieczorem, ale widzę, że uzyskał poprawne wyniki na moich danych testowych. Nie znam FOR XML, więc zanim go zaakceptuję, będę chciał dowiedzieć się, jak to działa. –

+0

@LevinMagruder Zasadniczo tworzy kod XML bez rzeczywistego znacznika i służy do utworzenia listy oddzielanej przecinkami. Daj mi znać, jeśli masz jakieś pytania. –

Powiązane problemy