2012-07-04 13 views
6

Używam programu SQL Server 2008 R2.Jak przetestować serię równych X sparowanych wierszy w rzędzie odnoszących się do konkretnej kolumny?

Rozważmy @t stołowego (TOP 20 porządku PK DESC):

PK SK VC APP  M C 
== == == ==== == ================== 
21 7 79 NULL 0 NULL 
20 9 74 1  3 20=14, 18=13, 15=2 
19 6 79 1  2 19=11, 17=7 
18 9 77 1  0 NULL 
17 6 74 1  0 NULL 
16 7 79 1  0 NULL 
15 9 74 1  0 NULL 
14 9 74 1  0 NULL 
13 9 77 1  0 NULL 
12 7 77 1  0 NULL 
11 6 79 1  0 NULL 
10 7 79 1  0 NULL 
9 7 74 1  0 NULL 
8 7 79 1  0 NULL 
7 6 74 1  0 NULL 
6 6 74 1  0 NULL 
5 7 79 1  0 NULL 
4 7 77 1  0 NULL 
3 6 79 1  0 NULL 
2 9 74 1  0 NULL 

Utworzono z tym:

DECLARE @t TABLE(PK INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, SK INT NOT NULL, VC INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 

INSERT @t (SK,VC,APP,M,C) VALUES 
(7,77,1,0,NULL), 
(9,74,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(6,74,1,0,NULL), 
(7,79,1,0,NULL), 
(7,74,1,0,NULL), 
(7,79,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(9,77,1,0,NULL), 
(9,74,1,0,NULL), 
(9,74,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(9,77,1,0,NULL), 
(6,79,1,2,'19=11, 17=7'), 
(9,74,1,3,'20=14, 18=13, 15=2'), 
(7,79,NULL,0,NULL) 

Moim zadaniem jest powrót true na mecz, jeśli ostatni wiersz (where APP IS NOT NULL) uzupełnij serię pasujących par X lub ostatnich rzędów tej samej grupy (ten sam obecny SK).

Na przykład, gdy testowanie obejmuje tylko 2 pary, biorąc pod uwagę, że obecny wymagany test dotyczy SK = 6, jak tylko dojdziemy do PK = 19, istnieje dopasowanie.

Spotkanie VC (19) = VC (11) = 79 i VC (17) = VC (7) = 74

Zobacz, że przez wykonanie następujących czynności:

DECLARE @PairsToTest int = 2 
DECLARE @SK int = 6 
SELECT 
    TOP (2*@PairsToTest) 
    * 
    FROM @t 
    WHERE 
      APP IS NOT NULL 
     AND SK = @SK 
    ORDER BY SK, PK DESC 

wyników:

PK SK VC APP M C 
19 6 79 1 2 19=11, 17=7 
17 6 74 1 0 NULL 
11 6 79 1 0 NULL 
7 6 74 1 0 NULL 

Innym przykładem

testując 3 parami zostanie znaleziony w PK = 20, gdy patrzy się SK = 9 (Chociaż jest to interesujące pytanie samo w sobie, dla mojego zadania nie ma potrzeby testowania wszystkich SK. Wynik dla danej SK jest dla mnie wystarczający.

Aby zobaczyć wykonać mecz to:

DECLARE @PairsToTest int = 3 
DECLARE @SK int = 9 
SELECT 
    TOP (2*@PairsToTest) 
    * 
    FROM @t 
    WHERE 
      APP IS NOT NULL 
     AND SK = @SK 
    ORDER BY SK, PK DESC 

co skutkuje:

PK SK VC APP M C 
20 9 74 1 3 20=14, 18=13, 15=2 
18 9 77 1 0 NULL 
15 9 74 1 0 NULL 
14 9 74 1 0 NULL 
13 9 77 1 0 NULL 
2 9 74 1 0 NULL 

jak widać: VC (20) = VC (14) = 74, VC (18) = VC (13) = 74 i VC (15) = VC (2)

Pomyślałem o wybraniu wymaganych zestawów rzędów we właściwej kolejności i policzeniu równych rzędów w VC. Jeśli licznik jest taki sam jak @PairsToTest, jest to znak podniesienia flagi.

Próbowałem:

DECLARE @PairsToTest int = 3 
DECLARE @SK int = 9 
;with t0 as 
(
SELECT 
    TOP (2*@PairsToTest) 
    * 
    FROM @t 
    WHERE 
      APP IS NOT NULL 
     AND SK = @SK 
    ORDER BY SK, PK DESC 
), 
t1 AS 
(
SELECT TOP (@PairsToTest) * FROM t0 
), 
t2 AS 
(
SELECT TOP (@PairsToTest) * FROM t0 ORDER BY PK ASC 
) 
,t3 AS 
(
SELECT TOP 99999999 * FROM t2 ORDER BY PK DESC 
) 

IF (SELECT COUNT(*) FROM t1 LEFT OUTER JOIN t3 ON t1.VC = t3.VC) = @PairsToTest 
    SELECT 1 
ELSE 
    SELECT 0 

ale w tym są zbyt may wady:

  1. VC nie zawierają unikalne dane (jedynie przypadkowo)
  2. IF jest niedozwolone
  3. Powinienem pozbyć się TOP 99999999 w t3 (chociaż mogę z tym żyć)

Jakie są wymagane zmiany, które powinienem podjąć, aby rozwiązać ten problem?

+2

Po prostu dał mi ból głowy ... – Jim

Odpowiedz

1
DECLARE @t TABLE(PK INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, SK INT NOT NULL, VC INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 

INSERT @t (SK,VC,APP,M,C) VALUES 
(7,77,1,0,NULL), 
(9,74,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(6,74,1,0,NULL), 
(7,79,1,0,NULL), 
(7,74,1,0,NULL), 
(7,79,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(9,77,1,0,NULL), 
(9,74,1,0,NULL), 
(9,74,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(9,77,1,0,NULL), 
(6,79,1,2,'19=11, 17=7'), 
(9,74,1,3,'20=14, 18=13, 15=2'), 
(7,79,NULL,0,NULL) 


DECLARE @PairsToTest int = 3 
DECLARE @SK int = 9 

IF ((SELECT COUNT(*) FROM @t WHERE APP IS NOT NULL AND SK = @SK)[email protected]) >=0 
    BEGIN 
     DECLARE @swapData TABLE(PK1 INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, PK INT NOT NULL, SK INT NOT NULL, VC INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 
     DECLARE @olderData TABLE(PK2 INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, PK INT NOT NULL, SK INT NOT NULL, VC2 INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 
     DECLARE @newerData TABLE(PK3 INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, PK INT NOT NULL, SK INT NOT NULL, VC3 INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 


     INSERT @swapData SELECT TOP ((SELECT COUNT(*) FROM @t WHERE APP IS NOT NULL AND SK = @SK)[email protected]) * FROM @t WHERE APP IS NOT NULL AND SK = @SK ORDER BY PK 
     INSERT @olderData SELECT TOP (@PairsToTest) PK,SK,VC,APP,M,C FROM @swapData ORDER BY PK1 DESC 
     INSERT @newerData SELECT TOP (@PairsToTest) * FROM @t WHERE APP IS NOT NULL AND SK = @SK ORDER BY SK, PK DESC 



     DECLARE @Matches int = (SELECT COUNT(*)FROM @newerData INNER JOIN @olderData ON PK2 = PK3 WHERE VC2=VC3) 

     IF @Matches = @PairsToTest 
      SELECT 1 AS Match 
     ELSE 
      SELECT 0 AS Match 
    END 
ELSE 
    SELECT 0 AS Match 

/* 
SELECT TOP (2*@PairsToTest) * FROM @t WHERE APP IS NOT NULL AND SK = @SK ORDER BY SK, PK DESC 
SELECT * FROM @olderData 
SELECT * FROM @newerData 
*/ 
1

Spróbuj tego kodu, to zlicza liczbę par wierszy w każdej z przegród SK i wyklucza wiersze bez pary z wyniku:

DECLARE @t TABLE(PK INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, SK INT NOT NULL, VC INT NULL, APP INT NULL, M INT NOT NULL, C NVARCHAR(111) NULL); 

INSERT @t (SK,VC,APP,M,C) VALUES 
(7,77,1,0,NULL), 
(9,74,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(6,74,1,0,NULL), 
(7,79,1,0,NULL), 
(7,79,1,0,NULL), 
(6,79,1,0,NULL), 
(7,77,1,0,NULL), 
(9,77,1,0,NULL), 
(9,74,1,0,NULL), 
(9,74,1,0,NULL), 
(7,79,1,0,NULL), 
(6,74,1,0,NULL), 
(9,77,1,0,NULL), 
(6,79,1,2,'19=11, 17=7'), 
(9,74,1,3,'20=14, 18=13, 15=2'), 
(7,79,NULL,0,NULL) 

;WITH c AS 
(
    SELECT *, 
      DENSE_RANK() OVER (PARTITION BY SK ORDER BY VC DESC) DenseRankPartitionBySK, 
      ROW_NUMBER() OVER (PARTITION BY SK ORDER BY PK DESC) ordinalNumberInSKPartition 
    FROM @t 
    WHERE APP IS NOT NULL 
), 
e AS 
(
    SELECT *, 
      COUNT(*) OVER (PARTITION BY SK, DenseRankPartitionBySK) _Sum, 
      ROW_NUMBER() OVER (PARTITION BY SK, DenseRankPartitionBySK ORDER BY PK) Odd 
    FROM c 
), 
d AS (
    SELECT *, 
      COUNT(*) OVER (PARTITION BY SK) numberOfRows 
    FROM e 
    WHERE _Sum % 2 = 0 OR Odd <> 1 
) 

SELECT 
     d.PK, d.SK, d.VC, d.APP, d.M, d.C, 
     CASE WHEN ordinalNumberInSKPartition = 1 THEN 1 ELSE 0 END IsTopRow, 
     numberOfRows/2 [NumberOfPairsInSKPartition(M)] 
FROM d 
ORDER BY SK, PK DESC 
Powiązane problemy