2012-05-30 4 views
0

내가 조인 내에서 상관 된 하위 쿼리가 필요한 쿼리가 있습니다. 나는 필요성을 말하고, 나는 그것이 내가 필요로한다고 생각한다. 나는 이것을 어떻게 할 수 있는가? 내 쿼리가 아래에 있는데, "다중 부분 식별자"FIELDNAME GOESERE "바인딩 할 수 없습니다"오류가 발생합니다 ... 어떻게 작동하도록이 쿼리를 변경할 수 있습니까? 크로스이 시나리오에서 작품을 적용조인 내의 상관 된 하위 쿼리?

SELECT FireEvent.ExerciseID, 
     FireEvent.FireEventID, 
     tempHitEvent.HitEventID, 
     FireEvent.AssociatedPlayerID, 
     tempHitEvent.AssociatedPlayerID, 
     FireEvent.EventTime, 
     tempHitEvent.EventTime, 
     FireEvent.Longitude, 
     FireEvent.Latitude, 
     tempHitEvent.Longitude, 
     tempHitEvent.Latitude, 
     tempHitEvent.HitResult, 
     FireEvent.AmmunitionCode, 
     FireEvent.AmmunitionSource, 
     FireEvent.FireEventID, 
     0 AS 'IsArtillery' 
FROM FireEvent 
     LEFT JOIN (SELECT HitEvent.*, 
         FireEvent.FireEventID, 
         Rank() 
          OVER ( 
          ORDER BY HitEvent.EventTime) AS RankValue 
        FROM HitEvent 
         WHERE FireEvent.EventTime BETWEEN 
            Dateadd(millisecond, -5000, 
            HitEvent.EventTime) AND 
               Dateadd(millisecond, 
               5000, HitEvent.EventTime) AND HitEvent.FiringPlayerID = FireEvent.PlayerID 
        AND HitEvent.AmmunitionCode = 
         FireEvent.AmmunitionCode 
        AND HitEvent.ExerciseID = 
         'D289D508-1479-4C17-988C-5F6A847AE51E' 
         AND FireEvent.ExerciseID = 
         'D289D508-1479-4C17-988C-5F6A847AE51E' 
        AND HitEvent.HitResult NOT IN (0, 1)) AS 
       tempHitEvent 
       ON ( 
       RankValue = 1 
      AND tempHitEvent.FireEventID = 
        FireEvent.FireEventID 
        ) 
WHERE FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' 
ORDER BY HitEventID 
+0

잠깐, 문제가 단지 by 절에있어, HitEventID의 접두사가 있어야합니까? –

답변

1

사용 OUTER APPLY 대신 왼쪽 가입. 나는 주위 조항의 일부를 이동했다,하지만 당신은 단지 일치 HitEvent는 CROSS APPLY을 사용하여이 결과를 반환 할 경우, 아래의 원하는 결과

SELECT FireEvent.ExerciseID, 
     FireEvent.FireEventID, 
     tempHitEvent.HitEventID, 
     FireEvent.AssociatedPlayerID, 
     tempHitEvent.AssociatedPlayerID, 
     FireEvent.EventTime, 
     tempHitEvent.EventTime, 
     FireEvent.Longitude, 
     FireEvent.Latitude, 
     tempHitEvent.Longitude, 
     tempHitEvent.Latitude, 
     tempHitEvent.HitResult, 
     FireEvent.AmmunitionCode, 
     FireEvent.AmmunitionSource, 
     FireEvent.FireEventID, 
     0 AS 'IsArtillery' 
FROM FireEvent 
     OUTER APPLY 
     ( SELECT HitEvent.*, RANK() OVER (ORDER BY HitEvent.EventTime) AS RankValue 
      FROM HitEvent 
      WHERE HitEvent.FireEventID = FireEvent.FireEventID 
      AND  FireEvent.EventTime BETWEEN DATEADD(MILLISECOND, -5000, HitEvent.EventTime) AND DATEADD(MILLISECOND, 5000, HitEvent.EventTime) 
      AND  HitEvent.FiringPlayerID = FireEvent.PlayerID 
      AND  HitEvent.AmmunitionCode = FireEvent.AmmunitionCode 
      AND  HitEvent.ExerciseID = FireEvent.ExerciseID 
      AND  HitEvent.HitResult NOT IN (0, 1) 
     ) AS tempHitEvent 
WHERE COALESCE(RankValue, 1) = 1 
AND  FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' 
ORDER BY FireEvent.HitEventID 

을 생산한다. CROSS APPLYOUTER APPLY으로 무엇입니까 INNER JOINLEFT JOIN입니다.


ADDENDUM

이 모두 사용하여 수행 한 후, 모든 데이터 아니라 HitEvent를 RANK 기능을 수행 HitEvent 가입 서브 쿼리를 사용하지 않고 이동하여, OUTER APPLY 필요없이 결합 될 수있다 표. 이 모든 내용은 하위 쿼리로 이동해야 WHERE 절에 RANK 함수의 결과가 포함될 수 있습니다.

SELECT * 
FROM ( SELECT FireEvent.ExerciseID, 
        FireEvent.FireEventID, 
        HitEvent.HitEventID, 
        FireEvent.AssociatedPlayerID, 
        --HitEvent.AssociatedPlayerID, 
        FireEvent.EventTime, 
        HitEvent.EventTime [HitEventTime], 
        FireEvent.Longitude [FireEventLongitute], 
        FireEvent.Latitude [FireEventLatitute], 
        HitEvent.Longitude [HitEventLongitute], 
        HitEvent.Latitude [HitEventLatitute], 
        HitEvent.HitResult , 
        FireEvent.AmmunitionCode, 
        FireEvent.AmmunitionSource, 
        0 [IsArtillery], 
        RANK() OVER(PARTITION BY HitEvent.FireEventID, HitEvent.FiringPlayerID, HitEvent.AmmunitionCode,HitEvent.ExerciseID ORDER BY HitEvent.EventTime) [RankValue] 
      FROM FireEvent 
        LEFT JOIN HitEvent 
         ON HitEvent.FireEventID = FireEvent.FireEventID 
         AND FireEvent.EventTime BETWEEN DATEADD(MILLISECOND, -5000, HitEvent.EventTime) AND DATEADD(MILLISECOND, 5000, HitEvent.EventTime) 
         AND HitEvent.FiringPlayerID = FireEvent.PlayerID 
         AND HitEvent.AmmunitionCode = FireEvent.AmmunitionCode 
         AND HitEvent.ExerciseID = FireEvent.ExerciseID 
         AND HitEvent.HitResult NOT IN (0, 1) 
     ) data 
WHERE RanKValue = 1 

이것은 OUTER APPLY을 사용하는 것에 비해 약간 향상된 성능을 제공 할 수 있습니다. 이는 스키마와 처리중인 데이터의 양에 따라 다릅니다. 테스트를 대신 할 수있는 것은 없습니다 :

0

...

SELECT FireEvent.ExerciseID, 
     FireEvent.FireEventID, 
     tempHitEvent.HitEventID, 
     FireEvent.AssociatedPlayerID, 
     tempHitEvent.AssociatedPlayerID, 
     FireEvent.EventTime, 
     tempHitEvent.EventTime, 
     FireEvent.Longitude, 
     FireEvent.Latitude, 
     tempHitEvent.Longitude, 
     tempHitEvent.Latitude, 
     tempHitEvent.HitResult, 
     FireEvent.AmmunitionCode, 
     FireEvent.AmmunitionSource, 
     FireEvent.FireEventID, 
     0 AS 'IsArtillery' 
     ,RankValue 
FROM FireEvent 
     CROSS APPLY (SELECT HitEvent.*, 
         FireEvent.FireEventID, 
         Rank() 
          OVER ( 
          ORDER BY HitEvent.EventTime) AS RankValue 
        FROM HitEvent 
         WHERE FireEvent.EventTime BETWEEN 
            Dateadd(millisecond, -5000, 
            HitEvent.EventTime) AND 
               Dateadd(millisecond, 
               5000, HitEvent.EventTime) AND HitEvent.FiringPlayerID = FireEvent.PlayerID 
        AND HitEvent.AmmunitionCode = 
         FireEvent.AmmunitionCode 
        AND HitEvent.ExerciseID = 
         'D289D508-1479-4C17-988C-5F6A847AE51E' 
         AND FireEvent.ExerciseID = 
         'D289D508-1479-4C17-988C-5F6A847AE51E' 
        AND HitEvent.HitResult NOT IN (0, 1)) 
       tempHitEvent 
       WHERE 
       RankValue = 1 
      AND tempHitEvent.FireEventID = 
        FireEvent.FireEventID 

AND FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' 
ORDER BY HitEventID 
0

당신은 상관 하위 쿼리가 필요하지 않습니다. 동시에 여러 필드에 있지만 비교적 간단한 조인을 사용하는 것 같습니다.

다음 FROM 절은 두 테이블을 참조하는 조건을 하위 쿼리에서 추출하여 외부 조건을 JOIN 절로 옮깁니다. 이것은 당신이 순위에서 파티션 당신이 무엇을 기대하고있다 여부에 따라 원하는에 근접 :

FROM FireEvent fe left outer join 
    (SELECT HitEvent.*, 
      Rank() OVER (partition by FiringPlayerID, ExerciseID, FireEventID, FireEventID 
          ORDER BY HitEvent.EventTime) AS RankValue 
     FROM HitEvent 
     WHERE HitEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND 
      HitEvent.HitResult NOT IN (0, 1) 
    ) he 
    ON he.FiringPlayerID = fe.PlayerId and 
     he.AmmunitionCode = fe.AmmunitionCode and 
     fe.EventTime BETWEEN Dateadd(millisecond, -5000, he.EventTime) AND 
          Dateadd(millisecond, 5000, he.EventTime) AND 
     fe.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND 
     RankValue = 1 , d 
     he.FireEventID = fe.FireEventID 
+0

하위 쿼리의 조건을 적용하면 'RANK'함수의 결과가 선택되어 작동하지 않습니다. 즉 외부 적용을 사용하면 firequery.EventTime이 5 초인 첫 번째 이벤트가 하위 쿼리에서 반환되지만 첫 번째 HitEvent가 FireEvent 시간의 5 초 내에있는 경우 쿼리가 결과를 반환합니다 (미묘하지만 중요한 차이점이 있음)). – GarethD

+0

rank()에서 더 나은 파티션 절을 갖도록 쿼리를 수정했습니다. 이것은 정확히 동일하지 않습니다. 그러나, 나는 하위 쿼리를 가져 와서 창 함수를 사용하여 또 다른 열을 추가하여 화재 이벤트 ID를 계산하고 외부 조인을 완전히 없애서 쿼리를 풀 수 있다고 생각합니다. –

+1

partion 절을 수정하는 것이 어느 정도 도움이되었지만 하위 쿼리의 결과가 주 쿼리와 직접 관련되어 있으므로 상관 관계가있는 하위 쿼리가 필요하다는 근본적인 문제가 여전히 남아 있습니다. 문제를 더 잘 보여주기 위해 [SQL Fiddle] (http://sqlfiddle.com/#!3/3bc04/1)을 수행했습니다. 두 번째 결과 창에서 첫 번째 HitEvent가 FireEvent의 5 초 내에 있지 않기 때문에 HitResult가 NULL입니다. 최상위 쿼리에서 5 초 이내에 첫 번째 HitEvent가 표시됩니다 (HitResult = 5가있는 행 앞에 있기 때문에 HitResult = 4로 표시됨). – GarethD