2014-12-10 1 views
0

커서를 기반으로하는 쿼리를 다시 작성하려고합니다.SQL 계산 및 0으로 나누기 방지

쿼리는 여러 값을 기반으로 특정 통계를 계산합니다. 아래 첫 번째, 두 번째 및 세 번째 스 니펫에서는 Unit1의 행복이 작동합니다. CASE. 이러한 필드는 모두 0입니다 (결코 NULL 일 수 없음) Divide by Zero 오류가 발생합니다. 각 필드에 (Unit2 + 1)/(Unit1 + 1)을 1 개 더할 수 있으며 오류가 중지됩니다. 그러나 그것은 교묘 한 것처럼 보이며 잠재적으로 부정확 한 결과를 줄 것입니다. 즉. Unit1은 행복을 유지하기 위해 같은 양의 Unit2이 필요합니다. Unit1이 하나 있는데 Unit2이 아닌 경우이 수트는 100 % 만족 스러울 것입니다. 그래서 제 첫 번째 문제는 제로에 의한 나눗셈을 방지하지만 결과를 왜곡시키지 않는 것입니다. 각 CASE 내가 각 UnitHappiness 가장 낮은 값을 가지고 테이블에서 그 값을 저장할 필요가있다 나에게 % 행복

Select 

CASE WHEN ((Unit2/Unit1) * 100) > 100 Then 100 Else ((Unit2/Unit1) * 100) END Unit1Happy1, 
CASE WHEN ((Stock3/(Unit1 * 2)) * 100) > 100 Then 100 Else ((Stock3/(Unit1 * 2)) * 100) END Unit1Happy2, 
CASE WHEN (((Drug3 + (Drug1/2))/Unit1) * 100) > 100 Then 100 Else (((Drug3 + (Drug1/2))/Unit1) * 100) END Unit1Happy3, 
CASE WHEN (((Weapon6 + Weapon7 + Weapon8 + Weapon9)/Unit2) * 100) > 100 Then 100 ELSE (((Weapon6 + Weapon7 + Weapon8 + Weapon9)/Unit2) * 100) END Unit2Happ1, 
CASE WHEN (((Stock2 + (Stock1/2))/Unit2) * 100) > 100 Then 100 Else (((Stock2 + (Stock1/2))/Unit2) * 100) END Unit2Happ2 

FROM tblUserFiles 

나의 다음 문제를 제공합니다. 그래서 tblUserFiles에는 5 필드 Unit1Happ, Unit2Happ .... Unit5Happ이 있습니다. Unit1Happy1 내가 Unit1Happ에 그 숫자를 가장 낮은 수치 저장되어있는 경우 Unit2Happy이 가장 낮은 경우 나는 그 등을 저장, 위의 쿼리를 보면

내 기록 식별자 UserId 내가 주어진 UserId 나에 대해이 작업을 실행해야 전체 테이블.

내가 기본적으로 요구하고 있습니다 :

  • 각 단위 계산의 가장 낮은 값을 식별하는 가장 좋은 방법은 무엇입니까?
  • 0으로 나누기를 방지하는 가장 좋은 방법은 무엇입니까? 오류가 있습니까?
  • 더 나은 방법으로이 문제에 접근 할 수 있습니까?

업데이트

나는 아래의 답변에 게시 제안을하고 있어요. 이것은 단지 훈련 일 뿐이므로 시간이 걸릴 수 있습니다. 나는 찾고있는 결과를주는 작동하는 쿼리를 가지고 있는데, 제안 된 응답이 더 효율적인지 확실하지 않습니다.

Update tblUserFiles Set Unit1Happ = happyvals.Unit1Happiness, Unit2Happ = happyvals.Unit2Happiness, Unit3Happ = happyvals.Unit3Happiness, Unit4Happ = happyvals.Unit4Happiness, Unit5Happ = happyvals.Unit5Happiness FROM 

(SELECT ch.UserId, 
Case When ch.Unit1Happy1 < ch.Unit1Happy2 And ch.Unit1Happy1 < ch.Unit1Happy3 Then ch.Unit1Happy1 
      When ch.Unit1Happy2 < ch.Unit1Happy1 And ch.Unit1Happy2 < ch.Unit1Happy3 Then ch.Unit1Happy2 
      Else ch.Unit1Happy3 
End As Unit1Happiness, 
CASE WHEN ch.Unit2Happy1 > ch.Unit2Happy2 THEN ch.Unit2Happy1 
      ELSE ch.Unit2Happy2 
END AS Unit2Happiness, 
ch.Unit3Happy1 AS Unit3Happiness, 
ch.Unit4Happy1 AS Unit4Happiness, 
ch.Unit5Happy1 AS Unit5Happiness 
FROM 
(

Select 
UserId, 
CASE WHEN Unit2 = 0 OR Unit1 = 0 THEN 0 
     WHEN ((Unit2/Unit1) * 100) > 100 Then 100 
     ELSE ((Unit2/Unit1) * 100) 
END Unit1Happy1, 
CASE WHEN Stock3 = 0 OR Unit1 = 0 THEN 0 
     WHEN ((Stock3/(Unit1 * 2)) * 100) > 100 THEN 100 
     ELSE ((Stock3/(Unit1 * 2)) * 100) 
END Unit1Happy2, 
CASE WHEN Unit1 = 0 THEN 0 
     WHEN Drug3 = 0 AND Drug1 = 0 THEN 0 
     WHEN Drug1 = 0 THEN 
         CASE WHEN (Drug3/Unit1) * 100 > 100 THEN 100 
          ELSE (Drug3/Unit1) * 100 
         END 
     WHEN Drug3 = 0 THEN 
         CASE WHEN (Drug1/2)/Unit1 > 100 THEN 100 
          ELSE (Drug1/2)/Unit1 
         END 
     ELSE 
      CASE WHEN (((Drug3 + (Drug1/2))/Unit1) * 100) > 100 THEN 100 
       ELSE (((Drug3 + (Drug1/2))/Unit1) * 100) 
      END 

END Unit1Happy3, 
CASE WHEN Unit2 = 0 THEN 0 
     WHEN (Weapon6 + Weapon7 + Weapon8 + Weapon9) = 0 THEN 0 
     WHEN (((Weapon6 + Weapon7 + Weapon8 + Weapon9)/Unit2) * 100) > 100 THEN 100 
     ELSE (((Weapon6 + Weapon7 + Weapon8 + Weapon9)/Unit2) * 100) 
END Unit2Happy1, 
CASE WHEN Unit2 = 0 THEN 0 
     WHEN Stock1 = 0 AND Stock2 = 0 THEN 0 
     WHEN Stock1 = 0 THEN 
      CASE WHEN ((Stock2/Unit2) * 100) > 100 THEN 100 
       ELSE ((Stock2/Unit2) * 100) 
      END 
     WHEN Stock2 = 0 THEN 
      CASE WHEN (((Stock1/2)/Unit2) * 100) > 100 THEN 100 
       ELSE (((Stock1/2)/Unit2) * 100) 
      END 
     WHEN (((Stock2 + (Stock1/2))/Unit2) * 100) > 100 THEN 100 
     ELSE (((Stock2 + (Stock1/2))/Unit2) * 100) 
END Unit2Happy2,  
CASE WHEN Unit2 = 0 OR Unit3 = 0 THEN 0 
     WHEN ((Unit2/Unit3) * 100) > 100 THEN 100 
     ELSE ((Unit2/Unit3) * 100) 
END Unit3Happy1, 
CASE WHEN Unit2 = 0 OR Unit4 = 0 THEN 0 
     WHEN ((Unit2/Unit4) * 100) > 100 THEN 100 
     ELSE ((Unit2/Unit4) * 100) 
END Unit4Happy1, 
CASE WHEN Unit2 = 0 OR Unit5 = 0 THEN 0 
     WHEN ((Unit2/Unit5) * 100) > 100 THEN 100 
     ELSE ((Unit2/Unit5) * 100) 
END Unit5Happy1 
FROM tblUserFiles) ch) happyvals 
Join tblUserFiles ON tblUserFiles.UserID = happyvals.UserID 
+0

'MIN' 집계 함수가 가장 낮습니다. 또는 'TOP 1'을 선택하고 order by 절을 사용하십시오.0으로 나누기는 IF 또는 CASE 문으로 회피 할 수 있습니다. –

+0

@ VladimirOselsky 방금 2 분 동안 나갔고,이 경우 0으로 나누는 것을 막을 수 있음을 깨달았습니다. 트릭을해야하는 'MIN'. 나는 게시하기 전에 빠져 나가야했다. 감사! – Fred

답변

0

각 나누어서 주위에 nullif(Unit1, 0) 넣으시겠습니까?

+0

실제로 제로 약수를 'null'로 바꾸면 제로로 나누기 오류가 발생하지 않으므로 해답을 제공합니다. –

0

이와 비슷한 것.

아이디어는 UDF (스칼라 사용자 정의 함수) ...로 나누고 "Max (v)"트릭을 사용하는 것입니다.

아래의 코드는 완벽하지 않을 수 있습니다. 아이디어를 제공했습니다.

커서는 무서운 연기자로 99.9 %입니다. 이것을 없애고 커서를 풀어보십시오.

/* or Create */ 
ALTER FUNCTION dbo.udfSafeDivision (@num float , @denom float) 

RETURNS float 

AS 

BEGIN 
    declare @returnValue float 
    select @returnValue = 0 

     if(isnull(@denom,0) != 0) 
     BEGIN 
      select @returnValue = convert(float, convert(float, @num)/convert(float, @denom)) 
     END 
    return @returnValue 


END 


GO 


IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL 
begin 
     drop table #TableOne 
end 


CREATE TABLE #TableOne 
( 
SurrogateKey int IDENTITY(1001, 1), 
Unit1 int , 
Unit2 int , 
Stock1 int , 
Stock2 int , 
Stock3 int , 

Drug1 int , 
Drug3 int , 
Weapon6 int , Weapon7 int , Weapon8 int , Weapon9 int 

) 

Insert into #TableOne (Unit1, Unit2, Stock1, Stock2 , Stock3 , Drug1, Drug3 , Weapon6 , Weapon7 , Weapon8 , Weapon9) 
select 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 7 , 0 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 0 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 0 
UNION ALL select 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 


UNION ALL select 5 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 5 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , 0 , 0 , 0 
UNION ALL select 10 , 0 , 0 , 0 , 0 , 5 , 10 , 0 , 0 , 0 , 0 
UNION ALL select 0 , 1 , 0 , 0 , 0 , 5 , 10 , 10 , 20 , 30 , 40 
UNION ALL select 0 , 50 , 20 , 10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 


SELECT 
    (SELECT Max(v) 
    FROM (VALUES (Unit1Happy1), (Unit1Happy2), (Unit1Happy3), (Unit2Happ1), (Unit2Happ2)) AS value(v)) as [MaxValue] 
    , '--------' as Sep1 
    , derived1.* 

FROM 
(
Select 

CASE WHEN ((dbo.udfSafeDivision(Unit2 , Unit1)) * 100) > 100 Then 100 Else (dbo.udfSafeDivision(Unit2 , Unit1) * 100) END Unit1Happy1, 
CASE WHEN (dbo.udfSafeDivision(Stock3 , (Unit1 * 2)) * 100) > 100 Then 100 Else (dbo.udfSafeDivision(Stock3 , (Unit1 * 2)) * 100) END Unit1Happy2, 
CASE WHEN (dbo.udfSafeDivision((Drug3 + (Drug1/2)) , Unit1) * 100) > 100 Then 100 Else (dbo.udfSafeDivision((Drug3 + (Drug1/2)) , Unit1) * 100) END Unit1Happy3, 
CASE WHEN (dbo.udfSafeDivision((Weapon6 + Weapon7 + Weapon8 + Weapon9) , Unit2) * 100) > 100 Then 100 ELSE (dbo.udfSafeDivision((Weapon6 + Weapon7 + Weapon8 + Weapon9) , Unit2) * 100) END Unit2Happ1, 
CASE WHEN (dbo.udfSafeDivision((Stock2 + (Stock1/2)) , Unit2) * 100) > 100 Then 100 Else (dbo.udfSafeDivision((Stock2 + (Stock1/2)) , Unit2) * 100) END Unit2Happ2 
/* the below is to debug */ 
, '--' as Sep1 
, Unit1, Unit2, Stock1, Stock2 , Stock3 , Drug1, Drug3 , Weapon6 , Weapon7 , Weapon8 , Weapon9 
, dbo.udfSafeDivision(Unit2 , Unit1) as Div1 
, dbo.udfSafeDivision(Stock3 , (Unit1 * 2)) as Div3 

FROM #TableOne 
) as derived1 



IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL 
begin 
     drop table #TableOne 
end 
+0

약간의 수정이있었습니다. 자신의 가치를 테스트해야합니다. 하지만 몇 줄이 0이 아닌 값을 반환합니다. – granadaCoder