OVER를 사용하여 창 기능에서 DISTINCT 사용


18

Oracle에서 SQL Server 2014로 쿼리를 마이그레이션하려고합니다.

다음은 Oracle에서 잘 작동하는 쿼리입니다.

select
count(distinct A) over (partition by B) / count(*) over() as A_B
from MyTable 

다음은 SQL Server 2014 에서이 쿼리를 실행하려고 시도한 후에 발생한 오류입니다.

Use of DISTINCT is not allowed with the OVER clause

문제가 무엇인지 아는 사람이 있습니까? SQL Server에서 이런 종류의 쿼리가 가능합니까? 조언 부탁드립니다.


실제로 모든 행에 대해 결과에 실제로 하나의 행이 필요 MyTable합니까? 아니면 별개의 행으로 충분합니까? 그리고 행 이 없으면 0으로 나누기 오류를 고려할 필요가 없습니다MyTable .
Erwin Brandstetter

답변:


12

문제가 무엇인지 아는 사람이 있습니까? SQL Server에서 이런 종류의 쿼리가 가능합니까?

아니요 현재 구현되어 있지 않습니다. 다음 연결 항목 요청을 참조하십시오.

OVER 절 개선 요청-집계 함수에 대한 DISTINCT 절

또 다른 가능한 변형은

SELECT M.A,
       M.B,
       T.A_B
FROM   MyTable M
       JOIN (SELECT CAST(COUNT(DISTINCT A) AS NUMERIC(18,8)) / SUM(COUNT(*)) OVER() AS A_B,
                    B
             FROM   MyTable
             GROUP  BY B) T
         ON EXISTS (SELECT M.B INTERSECT SELECT T.B) 

캐스트 NUMERIC는 정수 나누기를 피하기 위해 존재합니다. join 절의 이유 는 여기설명되어 있습니다 .

ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)원하는 경우 (또는 열이 널 입력 가능하지 않은 ON M.B = T.B경우) 대체 될 수 있습니다 B.


14

이것은 B에 의해 분할 된 A에 대한 고유 카운트 (*)를 제공합니다.

dense_rank() over (partition by B order by A) 
+ dense_rank() over (partition by B order by A desc) 
- 1

3
재미있는 해결책. Anull이 아닌 경우 에만 작동한다는 면책 조항이 있어야한다고 생각합니다 (널도 계산합니다).
ypercubeᵀᴹ

그것은해야합니다 abs(dense_rank - dense_rank) + 1나는 생각한다.
norcalli

7

최대 값을 취하여 dense_rank()B로 분할 된 A의 고유 카운트를 얻을 수 있습니다 .

A에 널값이있을 수있는 경우를 처리하기 위해 first_value파티션에 널이 있는지 여부를 알아 낸 다음 주석에서 Martin Smith가 제안한 경우 1을 뺍니다.

select (max(T.DenseRankA) over(partition by T.B) - 
          cast(iif(T.FirstA is null, 1, 0) as numeric(18, 8))) / T.TotalCount as A_B
from (
     select dense_rank() over(partition by T.B order by T.A) DenseRankA,
            first_value(T.A) over(partition by T.B order by T.A) as FirstA,
            count(*) over() as TotalCount,
            T.A,
            T.B
     from MyTable as T
     ) as T

5

하위 쿼리를 수행하고 A, B로 그룹화하고 개수를 포함하십시오. 그런 다음 외부 쿼리에서 count (distinct)는 일반 카운트가되고 count (*)는 sum (cnt)가됩니다.

select
count(A) over (partition by B) * 1.0 / 
    sum(cnt) over() as A_B
from
(select A, B, count(*) as cnt
 from MyTable
 group by A, B) as partial;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.