SQL Server使用基于集合的解决方案将某些次要行连接到父行

时间:2015-07-21 18:44:10

标签: sql sql-server xml tsql

我试图在导入到表后解析t-SQL中的BAIv2银行文件。该文件由行组成,每行有两个前导数字。如果行的前导数恰好是“88”,则它是“延续行”并且意味着是前一行的扩展(以防止行在文件中变得太宽)。下面的示例文件:

  

01,123456,123456,123456,1419,1,80,2 /
  02,123456,123456,1,123456,美元,2 /
  03,123456,美元,010,0 ,,, 015,0 ,,, 020,0 ,,, 025,0 ,,, 030,0 ,,, 040,0 ,,, 045,0 ,, / <无线电通信/>   88,050,0 ,,, 055,0 ,,, 057,0 ,,, 060,0 ,,, 072,0 ,,, 074,0 ,,, 100,123456,1,270,123456,1,/
  88,400,123456,35,470,123456,35,/
  16,275,123456,S,123456,0,0 ,, /
  88,ZBA XFER来自银行账户123456
  16,475,123456,Z,123456,123456 /
  88,CHECK-IRD
  16,475,123456,Z,123456,123456 /
  88,登记IRD

如何使用基于集合的SQL查询将前导行“88”的行追加到上一行?看起来像基于XML的查询可能会起作用。我能够通过复杂的循环和变量实现这一点,但效率非常低,所以我想要一个基于集合的解决方案。任何帮助将不胜感激。

我需要它看起来像这样,前面的行附加了“88”记录:

  

01,123456,123456,123456,1419,1,80,2 /
  02,123456,123456,1,123456,美元,2 /
  03,123456,美元,010,0 ,,, 015,0 ,,, 020,0 ,,, 025,0 ,,, 030,0 ,,, 040,0 ,,, 045,0 ,,, 050, 0 ,,, 055,0 ,,, 057,0 ,,, ...
  16,275,123456,S,123456,0,0 ,,, ZBA XFER来自银行账户123456
  16,475,123456,Z,123456,123456,CHECK-IRD
  16,475,123456,Z,123456,123456,登记IRD

2 个答案:

答案 0 :(得分:1)

仅当您的表格中有一个连续的int ID列

时,此功能才有效

编辑重写为递归CTE。可能有一种更简单的方法,但它运行:

;with x (ID,txt,lvl)as 
(select ID,cast(txt as varchar(max)),1 as lvl
from @table
where ID = 1
union all
select a.ID
,cast((case when left(a.txt,2) = '88' then cast(b.txt AS varchar(max)) else '' end)+ a.txt as varchar(max))
,case when left(a.txt,2) = '88' then b.lvl else b.lvl + 1 end
from @table a
inner join x b on a.ID = b.ID + 1)

,y as (
select *,RANK() OVER(PARTITION BY lvl ORDER BY LEN(txt) desc) as rnk from x
)

select ID,REPLACE(REPLACE(txt,'/',''),'88,','') as txt from y where rnk = 1

答案 1 :(得分:1)

您可以使用LEAD()LAG()窗口函数来查看上一条或下一条记录。 CTE会让眼睛看起来更容易,但我已经从另一个方向开始了。

DECLARE @Test TABLE
(
    ID INT,
    Value NVARCHAR(50)
)
INSERT @Test SELECT 1,'111,111,111,111'
INSERT @Test SELECT 2,'222,222,222,222'
INSERT @Test SELECT 3,'88,222,222,222,222'
INSERT @Test SELECT 4,'333,333,333,333'
INSERT @Test SELECT 5,'88,333,333,333,333'
INSERT @Test SELECT 6,'88,333,333,333,333'
INSERT @Test SELECT 7,'444,444,444,444,444'
INSERT @Test SELECT 8,'555,555,555,555,555'


SELECT
    Value=MAX(Value)    
FROM
(
    SELECT
        ContinuationGroup,
        Value=SUBSTRING((
            SELECT
                ','+Value
            FROM
            (
                SELECT
                    ID,Value,ContinuationGroup=SUM(ContinuationGroup) OVER (ORDER BY ID ROWS BETWEEN 99999 PRECEDING AND CURRENT ROW)       
                FROM
                (
                    SELECT  
                        ID, Value= REPLACE(Value,'88,',''), ContinuationGroup=CASE WHEN CHARINDEX('88,',Value) >0 THEN 0 ELSE 1 END   
                    FROM
                        @Test               
                )AS A       
            )AS B
            WHERE 
                B.ContinuationGroup=Y.ContinuationGroup
            ORDER BY ID FOR XML PATH( '' )
        ), 3, 1000 )    
    FROM
    (
        SELECT
            Value,ContinuationGroup=SUM(ContinuationGroup) OVER (ORDER BY ID ROWS BETWEEN 99999 PRECEDING AND CURRENT ROW)      
        FROM
        (
            SELECT  
                ID,Value= REPLACE(Value,'88,',''),ContinuationGroup=CASE WHEN CHARINDEX('88,',Value) >0 THEN 0 ELSE 1 END   
            FROM
                @Test

        )AS Z
    )AS Y
)AS X
GROUP BY
    ContinuationGroup