2017-02-07 25 views
2

我有一個表,像這樣的現值:在現場把T-SQL連字符的平均分隔在另一個領域

ID | FIX_1 | FTO | FIX_2      | 
_____________________________________________________ 
1 |  | 15452 |1.3-1.7-1.8-2.4-2.0   | 
2 |  | 15454 |1.4-1.1-1.4-2.7-2.6-1.8-2.4 | 
3 |  | 15454 |1.9-1.3-1.3     | 
.... ...... .... ................. 
.... ...... .... ................. 
100 |  | 15552 |0.4-1.7-1.2-2.1-2.6-1.6  | 

我需要做一個選擇與FIX_1場等於平均連字符的FIX_2字段中的分隔值。 T-SQL可以不使用臨時表嗎? 在此先感謝

+1

你能告訴你的預期輸出 – TheGameiswar

+0

爲什麼沒有臨時表?如果你不能有臨時表,我假設你不能創建函數? – iamdave

+0

對於id = 1的記錄,FIX_1字段輸出必須爲1.8,對於id = 2的記錄,1.9爲id = 3的記錄爲1.5,對於id爲100的記錄,爲1.6的記錄 –

回答

2

選項與UDF

Declare @YourTable table (ID int,FIX_1 money,FTO int,FIX_2 varchar(max)) 
Insert Into @YourTable values 
(1,null,15452,'1.3-1.7-1.8-2.4-2.0'), 
(2,null,15454,'1.4-1.1-1.4-2.7-2.6-1.8-2.4'), 
(3,null,15454,'1.9-1.3-1.3') 

Update @YourTable Set FIX_1=B.Value 
From @YourTable A 
Cross Apply (
       Select Value = Avg(cast(RetVal as money)) 
       From (Select * from [dbo].[udf-Str-Parse](A.FIX_2,'-')) B1 
      ) B 

Select * From @YourTable 

選項沒有UDF

Update @YourTable Set FIX_1=B.Value 
From @YourTable A 
Cross Apply (
       Select Value = Avg(cast(RetVal as money)) 
       From (
         Select RetSeq = Row_Number() over (Order By (Select null)) 
           ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
         From (Select x = Cast('<x>' + replace((Select replace(A.FIX_2,'-','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
         Cross Apply x.nodes('x') AS B(i) 
        ) B1 
      ) B 

雙方將返回

ID FIX_1 FTO  FIX_2 
1 1.84 15452 1.3-1.7-1.8-2.4-2.0 
2 1.9142 15454 1.4-1.1-1.4-2.7-2.6-1.8-2.4 
3 1.50 15454 1.9-1.3-1.3 

的UDF如果需要

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(10)) 
Returns Table 
As 
Return ( 
    Select RetSeq = Row_Number() over (Order By (Select null)) 
      ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)'))) 
    From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i) 
); 
--Thanks Shnugo for making this XML safe 
--Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ') 
--Select * from [dbo].[udf-Str-Parse]('this,is,<test>,for,< & >',',') 
+0

你是從@Shnugo引用帖子還是回答,如果有的話,我想這需要正確的歸屬?!如果不是沒有問題。 – Tanner

+0

@Tanner其實這是我的一個解析實用程序,但Shnugo在另一篇文章中提到了一個XML安全解析(我接受了這個解析)。對他來說這是一頂帽子。 –

+0

沒問題,它看起來像一個嘗試歸因,但它不明確 – Tanner

0

與用戶定義的函數...

create FUNCTION dbo.AvgOfDashSepVals (@vals varchar(500)) 
returns float as 
BEGIN 
declare @avg decimal 
declare @cnt int = 0 
declare @sum float = 0.0 
While charIndex('-', @vals) > 0 Begin 
     if isnumeric(left(@vals, charIndex('-', @vals)-1)) = 0 
     return null   
    set @cnt+= 1 
    set @sum += cast(left(@vals, charIndex('-', @vals)-1) as float) 
    set @vals = substring(@vals, charIndex('-', @vals)+1, len(@vals)) 
End 
RETURN case @cnt when 0 then null else @sum/@cnt end 

然後改變你的表中添加一個計算列。

alter table myTable 
    add Fix_1 as ([dbo].[AvgOfDashSepVals]([Fix_2])) 
+0

幹得好!我已經創建了一個類似於你的udf的函數,但是當我嘗試選擇dbo.AvgOfDashSepVals([FIX_2])時,我得到了'被零分隔錯誤分隔'的消息。你知道爲什麼嗎?感謝 –

+0

可能是因爲它運行在一個空字符串上('@ cnt' = 0)我添加了代碼來處理這個問題。 –

+0

太棒了!它幾乎是完美的,但是當在FIX_2字段中只有一個值時,函數返回NULL。此外,可以從標量結果的小數點後面的第三位截斷嗎? –

0
Declare @YourTable table (ID int,FIX_1 money,FTO int,FIX_2 varchar(max)) 
    Insert Into @YourTable values 
    (1,null,15452,'1.3-1.7-1.8-2.4-2.0'), 
    (2,null,15454,'1.4-1.1-1.4-2.7-2.6-1.8-2.4'), 
    (3,null,15454,'1.9-1.3-1.3'), 
    (4,null,15454,'1.5') 

;WITH cte AS 
(
    SELECT ID, SUBSTRING(FIX_2, 1, CHARINDEX('-',FIX_2) - 1) AS VALUE, SUBSTRING(FIX_2, CHARINDEX('-',FIX_2) + 1, LEN(FIX_2)) AS NEW_FIX_2 
    FROM @YourTable 
    WHERE CHARINDEX('-',FIX_2) > 0 
    UNION ALL 
    SELECT cte.ID, SUBSTRING(NEW_FIX_2, 1, CHARINDEX('-',NEW_FIX_2) - 1) AS VALUE, SUBSTRING(NEW_FIX_2, CHARINDEX('-',NEW_FIX_2) + 1, LEN(NEW_FIX_2)) AS NEW_FIX_2 
    FROM @YourTable y 
     JOIN cte ON cte.ID = y.ID 
    WHERE CHARINDEX('-', NEW_FIX_2) > 0 
    UNION ALL 
    SELECT ID, NEW_FIX_2, NULL 
    FROM cte 
    WHERE CHARINDEX('-', NEW_FIX_2) = 0 
) 
SELECT t.ID, ISNULL(v.VALUE, t.FIX_2) AS FIX_1, t.FTO, t.FIX_2 
FROM @YourTable t 
    LEFT JOIN (
     SELECT cte.ID, AVG(CAST(cte.VALUE AS MONEY)) AS VALUE 
     FROM cte 
     GROUP BY cte.ID 
) v ON v.ID = t.ID