2016-04-11 12 views
3

böyle verilerini içeren bir tablo vardır: hassasiyet içindeSQL Server 2008 - Sorgu kesir biçiminde sonuçlanan almak için

MinFormat(int) MaxFormat(int) Precision(nvarchar) 
    -2    3    1/2 

değerleri 1/2, 1/4, 1/8, 1 edilebilir/16, 1/32, 1/64 sadece. aşağıdaki gibi bir sonuç almak için

-2 
-3/2 
-1 
-1/2 
    0 
    1/2 
    1 
    3/2 
    2 
    5/2 
    3 

herhangi bir sorgu -

Şimdi sıra sorgudan neden istiyor?

Fikir, maksimum sınır değerine (Tamsayı olarak MinFomrat sütun değeri) (tamsayı olarak MaxFormat Col değeri) kesin değere göre sonuç temeline dayalı sonuç üretmektir.

Bu nedenle, yukarıdaki örnekte, bir değer -2 başlar ve bu sadece Hassas 1/1 için çalışacaktır 3

+2

Hassasiyeti nvarchar gibi saklıyorsunuz ...? Neden sadece "0,5" olarak saklamıyorsunuz? – Siyual

+0

Bu soru herhangi bir araştırma çalışması göstermemektedir. –

+0

@TabAlleman bir çözüm bulmak oldukça zor. –

cevap

7

Not gelene kadar hassas değeri (1/2) göre aşağıdaki değerleri üretmelidir , 1/2, 1/4, 1/8, 1/16, 1/32 ve 1/64

DECLARE @t table(MinFormat int, MaxFormat int, Precision varchar(4)) 
INSERT @t values(-2, 3, '1/2') 

DECLARE @numerator INT, @denominator DECIMAL(9,7) 
DECLARE @MinFormat INT, @MaxFormat INT 

-- put a where clause on this to get the needed row 

SELECT @numerator = 1, 
     @denominator = STUFF(Precision, 1, charindex('/', Precision), ''), 
     @MinFormat = MinFormat, 
     @MaxFormat = MaxFormat 
FROM @t 


;WITH N(N)AS 
(SELECT 1 FROM(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))M(N)), 
tally(N)AS(SELECT ROW_NUMBER()OVER(ORDER BY N.N)FROM N,N a,N b,N c,N d,N e,N f) 
SELECT top(cast((@MaxFormat- @MinFormat)/(@numerator/@denominator) as int) + 1) 
CASE WHEN val % 1 = 0 THEN cast(cast(val as int) as varchar(10)) 
    WHEN val*2 % 1 = 0 THEN cast(cast(val*2 as int) as varchar(10)) + '/2' 
    WHEN val*4 % 1 = 0 THEN cast(cast(val*4 as int) as varchar(10)) + '/4' 
    WHEN val*8 % 1 = 0 THEN cast(cast(val*8 as int) as varchar(10)) + '/8' 
    WHEN val*16 % 1 = 0 THEN cast(cast(val*16 as int) as varchar(10)) + '/16' 
    WHEN val*32 % 1 = 0 THEN cast(cast(val*32 as int) as varchar(10)) + '/32' 
    WHEN val*64 % 1 = 0 THEN cast(cast(val*64 as int) as varchar(10)) + '/64' 
END 
FROM tally 
CROSS APPLY 
(SELECT @MinFormat +(N-1) *(@numerator/@denominator) val) x 
+2

Ben beğendim! Yaklaşık 2 saat içinde benimkini gönderir. Acele etmeliydin ... – Shnugo

+1

Cevaplar asla beni şaşırtmayacak gibi görünüyor. +1. – Utsav

+0

Merhaba, geç ama yayınlandı ... – Shnugo

3

Üzgünüm, şimdi geciktim, ama bu benim yaklaşım oldu:

ben Bunu bir TVF'ye dolduktan sonra

veya

SELECT * 
FROM SomeTable 
CROSS APPLY dbo.MyFractalSteller(MinFormat,MaxFormat,[Precision]) AS Steps 

Ama yine de, bu kod gibi gerçek tabloyla bunu katılmak:

DECLARE @tbl TABLE (ID INT, MinFormat INT,MaxFormat INT,Precision NVARCHAR(100)); 

--Inserting two examples 
INSERT INTO @tbl VALUES(1,-2,3,'1/2') 
         ,(2,-4,-1,'1/4'); 

--Test with example 1, just set it to 2 if you want to try the other example 
DECLARE @ID INT=1; 

--If you want to get your steps numbered, just de-comment the tree occurencies of "Step" 
WITH RecursiveCTE as 
(
    SELECT CAST(tbl.MinFormat AS FLOAT) AS RunningValue 
      ,CAST(tbl.MaxFormat AS FLOAT) AS MaxF 
      ,1/CAST(SUBSTRING(LTRIM(RTRIM(tbl.Precision)),3,10) AS FLOAT) AS Prec 
      --,1 AS Step 
    FROM @tbl AS tbl 
    WHERE [email protected] 

    UNION ALL 

    SELECT RunningValue + Prec 
      ,MaxF 
      ,Prec 
      --,Step + 1 
    FROM RecursiveCTE 
    WHERE RunningValue + Prec <= MaxF 
) 
SELECT RunningValue --,Step 
     ,CASE WHEN CAST(RunningValue AS INT)<>RunningValue 
      THEN CAST(RunningValue/Prec AS VARCHAR(10)) + '/' + CAST(CAST(1/Prec AS INT) AS VARCHAR(MAX)) 
      ELSE CAST(RunningValue AS VARCHAR(10)) 
     END AS RunningValueFractal 
FROM RecursiveCTE; 

sonuç

Value ValueFractal 
-2  -2 
-1,5 -3/2 
-1  -1 
-0,5 -1/2 
0  0 
0,5  1/2 
1  1 
1,5  3/2 
2  2 
2,5  5/2 
3  3 
3

Mine biraz farklı diğerleri olduğunu. Eklemeyi kesir üzerinde gerçekleştiririm ve sonunda kesirleri basitleştirdim.

-- This solution uses CTE 
-- it breaks the @min, @max number into fraction 
-- perform the addition in terms of fraction 
-- at result, it attemp to convert the fraction to simpliest form 

declare @min  int, 
    @max  int, 
    @step  varchar(10), 
    @step_n  int, -- precision step numerator portion 
    @step_d  int -- precision step denominator portion 

select @min = -2, 
    @max = 3, 
    @step = '1/16' 

select @step_n = left(@step, charindex('/', @step) - 1), 
    @step_d = stuff(@step, 1, charindex('/', @step), '') 

; with rcte as 
(
    -- Anchor member 
    select n = @min, -- numerator 
     d = 1,  -- denominator 
     v = convert(decimal(10,5), @min) 

    union all 

    -- Recursive member 
    select n = case when ((r.n * @step_d) + (r.d * @step_n)) % @step_d = 0 
      and (r.d * @step_d) % @step_d = 0 
      then ((r.n * @step_d) + (r.d * @step_n))/@step_d 
      else (r.n * @step_d) + (r.d * @step_n) 
      end, 
     d = case when ((r.n * @step_d) + (r.d * @step_n)) % @step_d = 0 
      and (r.d * @step_d) % @step_d = 0 
      then (r.d * @step_d)/@step_d 
      else (r.d * @step_d) 
      end, 
     v = convert(decimal(10,5), ((r.n * @step_d) + (r.d * @step_n))/(r.d * @step_d * 1.0)) 
    from rcte r 
    where r.v < @max 
) 
select *, 
    fraction = case when n = 0 
       then '0' 
       when coalesce(d2, d) = 1 
       then convert(varchar(10), coalesce(n2, n)) 
       else convert(varchar(10), coalesce(n2, n)) + '/' + convert(varchar(10), coalesce(d2, d)) 
       end 
from rcte r 
    cross apply -- use to simplify the fraction result 
    (
     select n2 = case when n % 32 = 0 and d % 32 = 0 then n/32 
        when n % 16 = 0 and d % 16 = 0 then n/16 
        when n % 8 = 0 and d % 8 = 0 then n/8 
        when n % 4 = 0 and d % 4 = 0 then n/4 
        when n % 2 = 0 and d % 2 = 0 then n/2 
        end, 
      d2 = case when n % 32 = 0 and d % 32 = 0 then d/32 
        when n % 16 = 0 and d % 16 = 0 then d/16 
        when n % 8 = 0 and d % 8 = 0 then d/8 
        when n % 4 = 0 and d % 4 = 0 then d/4 
        when n % 2 = 0 and d % 2 = 0 then d/2 
        end 
    ) s 
order by v 
option (MAXRECURSION 0)