2010-04-02 2 views
1

이 경우를 상상해보십시오. 그러나 더 많은 구성 요소 버킷과 더 많은 중간체 및 출력이 있습니다. 중간체의 대부분은 상세 수준에서 계산되지만 몇 가지가 집계 수준에서 계산됩니다 같은 공식이 얼마나SQL에서 집계 수준 수식 재사용 - 좋은 전술?

DECLARE @Profitability AS TABLE 
    (
    Cust INT NOT NULL 
    ,Category VARCHAR(10) NOT NULL 
    ,Income DECIMAL(10, 2) NOT NULL 
    ,Expense DECIMAL(10, 2) NOT NULL 
    ,Liability DECIMAL(10, 2) NOT NULL 
    ,AllocatedCapital DECIMAL(10, 2) NOT NULL 
    ) ; 

INSERT INTO @Profitability 
VALUES (1, 'Software', 100, 50, 0, 0) ; 
INSERT INTO @Profitability 
VALUES (2, 'Software', 100, 20, 0, 0) ; 
INSERT INTO @Profitability 
VALUES (3, 'Software', 100, 60, 0, 0) ; 
INSERT INTO @Profitability 
VALUES (4, 'Software', 500, 400, 0, 0) ; 
INSERT INTO @Profitability 
VALUES (
     5 
     ,'Hardware' 
     ,1000 
     ,550 
     ,0 
     ,0 
     ) ; 
INSERT INTO @Profitability 
VALUES (
     6 
     ,'Hardware' 
     ,1000 
     ,250 
     ,500 
     ,200 
     ) ; 
INSERT INTO @Profitability 
VALUES (
     7 
     ,'Hardware' 
     ,1000 
     ,700 
     ,500 
     ,600 
     ) ; 
INSERT INTO @Profitability 
VALUES (
     8 
     ,'Hardware' 
     ,5000 
     ,4500 
     ,2500 
     ,800 
     ) ; 

WITH ProfitView 
      AS (SELECT Cust 
         ,Category 
         ,Income 
         ,Expense 
         ,Profit = Income - Expense 
         ,NetProfit = Income - Expense 
         - CASE WHEN Liability - AllocatedCapital > 0 
           THEN Liability - AllocatedCapital 
           ELSE 0 
          END 
       FROM  @Profitability 
      ) 
    SELECT Cust 
      ,Category 
      ,Income 
      ,Expense 
      ,Profit 
      ,NetProfit 
      ,Margin = Profit/Income 
      ,NetMargin = NetProfit/Income 
    FROM ProfitView ; -- NOTE I've left off the AFTER grouping formulas on this one. 

WITH ProfitView 
      AS (SELECT Cust 
         ,Category 
         ,Income 
         ,Expense 
         ,Profit = Income - Expense 
         ,NetProfit = Income - Expense 
         - CASE WHEN Liability - AllocatedCapital > 0 
           THEN Liability - AllocatedCapital 
           ELSE 0 
          END 
       FROM  @Profitability 
      ), 
     GROUP1 
      AS (SELECT Category 
         ,SUM(Profit) AS Profit 
         ,SUM(NetProfit) AS NetProfit 
         ,SUM(Income) AS Income 
         ,SUM(Profit)/SUM(Income) AS Margin 
         ,SUM(NetProfit)/SUM(Income) AS NetMargin 
       FROM  ProfitView 
       GROUP BY Category 
      ), 
     GROUP2 
      AS (SELECT GROUP1.* 
         ,NetProfit - Profit AS Exposure 
       FROM  GROUP1 
      ) 
    SELECT * 
      ,Exposure/Income AS ExposureRatio 
    FROM GROUP2 ; 

WITH ProfitView 
      AS (SELECT Cust 
         ,Category 
         ,Income 
         ,Expense 
         ,Profit = Income - Expense 
         ,NetProfit = Income - Expense 
         - CASE WHEN Liability - AllocatedCapital > 0 
           THEN Liability - AllocatedCapital 
           ELSE 0 
          END 
       FROM  @Profitability 
      ), 
     GROUP1 
      AS (SELECT SUM(Profit) AS Profit 
         ,SUM(NetProfit) AS NetProfit 
         ,SUM(Income) AS Income 
         ,SUM(Profit)/SUM(Income) AS Margin 
         ,SUM(NetProfit)/SUM(Income) AS NetMargin 
       FROM  ProfitView 
      ), 
     GROUP2 
      AS (SELECT GROUP1.* 
         ,NetProfit - Profit AS Exposure 
       FROM  GROUP1 
      ) 
    SELECT * 
      ,Exposure/Income AS ExposureRatio 
    FROM GROUP2 ; 

주의는 다른 집계 레벨에서 사용할 수 있습니다. 코드 중복이 발생합니다.

나는 UDF를 (스칼라 또는 최종 결과 보낸 사람 많은 집계 수준에서 계산되어야한다 중간체를 공유 할 수 있습니다 APPLY OUTER 키워드와 가치 테이블),하지만 내 경험 스칼라 및 멀티를 사용하는 생각 명령문 테이블 반환 UDF는 매우 잘 수행되지 않습니다.

또한 동적 SQL을 사용하고 수식을 이름으로 적용하는 것에 대해 생각했습니다.

동기화 및/또는 체계적으로 다른 수준에서 적용해야하는 이러한 종류의 수식을 유지하는 데 필요한 다른 기술, 기법 또는 전술은 무엇입니까?

+0

정확하게 이해했다면 CREATE VIEW myview AS SELECT SUM (수입 - 비용) FROM mytable GROUP BY x'와 같은 것을 원하십니까? – Quassnoi

+0

@Quassnoi - 기본적으로 집계에 관계없이 모든 적절한 입력 열이있는 집합에 동일한 수식을 일관되게 적용 할 수 있기를 원합니다. –

+0

이렇게하면 각 쿼리를 다시 구문 분석하고 각 최적화를 다시 수행해야하므로 수식이 실제로 그렇게 어려운 경우 동적 SQL을 사용할 수 있습니다. – Quassnoi

답변

1

서로 다른 집계 수준에서 동일한 수식을 사용해야합니다. 코드 중복이 발생합니다.

함수가 더 복잡한 경우 사용자 정의 CLR 집계를 만들면 도움이됩니다.

그러나 이러한 단순한 기능의 경우 기본 제공 SUM이 가장 좋습니다.

PostgreSQL과 달리 SQL Server은 기본 제공 언어로 사용자 지정 집계를 만들 수 없습니다. 사용자의 간단한 예를 들어

1

는, I는 원시 데이터 (SUM(Income)SUM(Expense)) 각각 따로 계산하고 결과 집합 Profit와 비즈니스 계층 Margin 복귀하여 계산을 리팩토링 것이다.

실제 상황에서는 불가능한 경우 간단한 예제를 좀 더 복잡하게 만들면 나에게 무엇이 표시되는지 알 수 있습니까?

저는 최근에 쿼리 내에서 복잡한 비즈니스 분석 계산이 필요한 프로젝트를 진행했습니다. 데이터 쿼리 외부에서 수행 할 수없는 것으로 판명되었으므로 결국 모든 것을 동적 SQL로 변환하는 데 의존했습니다. 이를 통해 매크로 함수를 구성하여 각 쿼리의 다양한 부분을 구성 할 수있었습니다. 이렇게함으로써 우리는 가독성을 희생했지만 유지 보수성을 확보하게되었습니다. 우리는 매크로 함수를 통해 가능한 모든 코드 경로를 사용하는 단위 테스트를 작성하고 생성 된대로 각 쿼리를 기록하기 때문에 테스트 가능성을 희생하지 않았습니다.

+0

감사합니다. 내가하고 있다고 생각했던 것들이 이미 유효한 접근법으로 사용되고 있다는 것을 알고있는 것이 좋습니다. –

1

당신은보기에서 복잡성의 일부를 분리 할 수 ​​있습니다 :

SELECT cust, SUM(profit), SUM(Income)/SUM(Expense) 
FROM dbo.vw_Profit 
GROUP BY cust 

예제 쿼리 전망 단순화를 보장 할만큼 거의 복잡하다 : 약간 간단한 쿼리 수

create view dbo.vw_Profit 
as 
SELECT 
    Cust 
, Income, 
, Expense 
, Income - Expense as Profit 
FROM dbo.Profitability 

. 그러나 뷰는 실제로 복잡한 쿼리에 큰 도움이 될 수 있습니다.

+0

죄송합니다. SUM (여백)이 의미가 없음을 분명히 했어야합니다. 코드를 실행하면 마진을 단순히 합산 할 수 없다는 것을 알 수 있습니다. 따라서 집계 후에 SUM을 적용하는 것이 필요합니다 (SUM (Profit)는 유효합니다). –

+0

@Cade Roux : 맞아! 대답은 편집되었지만보기가 덜 복잡해 졌음에도 불구하고 수정되었습니다. – Andomar

+0

현재 수십 개의 중간 열 결과를 생성하는 세부 수준에서 12 개의 CTE로 구성된보기가 있지만 집계해야하는 모든 다른 쿼리에는 3 CTE는 집계 수식의 계층 적 조건부 논리로 인해 발생합니다. –