SQL Server从自定义分隔文本创建行

时间:2019-05-31 16:29:07

标签: sql sql-server tsql split

我要计算飞行路线的二氧化碳排放量。航班行程可以包含1跳,例如DXB / CDG或ABJ / ADD / BKK / KUL / ADD / ABJ,共5跳。我的挑战是我需要将行程信息分解为单独的航班信息,因为每次航班都会计算出二氧化碳排放量:

来源ABJ/ADD/BKK/KUL/ADD/ABJ

并将其转换为:

enter image description here

2 个答案:

答案 0 :(得分:1)

我建议采用这种方法:

DECLARE  @fligth VARCHAR(100)='ABJ/ADD/BKK/KUL/ADD/ABJ';

WITH Casted(flightXML) AS
    (SELECT CAST('<x>' + REPLACE(@fligth,'/','</x><x>') + '</x>' AS XML))
,Tally(Nmbr) AS 
    (SELECT TOP((SELECT flightXML.value('count(/x)','int') FROM Casted)) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values)
SELECT flightXML.value('(/x[sql:column("Nmbr")]/text())[1]','varchar(10)') AS FromAirport
      ,flightXML.value('(/x[sql:column("Nmbr")+1]/text())[1]','varchar(10)') AS ToAirport
FROM Casted
CROSS JOIN Tally
WHERE flightXML.value('(/x[sql:column("Nmbr")+1]/text())[1]','varchar(10)') IS NOT NULL;

想法:

我们通过将分隔符替换为标签,将分隔的字符串转换为XML。这样我们就得到

<x>ABJ</x>
<x>ADD</x>
<x>BKK</x>
<x>KUL</x>
<x>ADD</x>
<x>ABJ</x>

现在,XQuery允许as按其位置检索值。因此,第二个CTE创建了一个即时提示。它将返回从到n的运行数字,其中n是字符串中的停靠点数。

最终查询将使用sql:column()将计数编号引入XQuery。您可以将其读取为在位置<x>上找到Nmbr并返回其内容。现在在位置<x>上找到Nmbr+1

答案 1 :(得分:0)

要获得预期的结果,您可以创建一个函数,该函数将使用提供的定界符将字符串分成行。之后,您可以根据需要进行进一步调整或对返回的数据进行更改。

步骤1:创建函数

dist^2

步骤2:使用该功能获取所需数据

sqrt

输出将是-

CREATE  FUNCTION [dbo].[splitstring] ( @stringToSplit VARCHAR(MAX) ,@Delimiter VARCHAR(10))
RETURNS @returnList TABLE ([Word] [nvarchar] (500))
AS
BEGIN
    DECLARE @name NVARCHAR(255)
    DECLARE @pos INT

    WHILE CHARINDEX(@Delimiter, @stringToSplit) > 0
    BEGIN
    SELECT @pos  = CHARINDEX(@Delimiter, @stringToSplit)  
    SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

    INSERT INTO @returnList 
    SELECT @name

    SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
END

INSERT INTO @returnList
SELECT @stringToSplit

RETURN
END

您还可以使用如下所示的SQL LEAD函数获得以上输出-

SELECT A.Word+'/'+B.Word FROM
(
    SELECT Word,
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN 
    FROM [dbo].[splitstring]('ABJ/ADD/BKK/KUL/ADD/ABJ','/') 
) A
INNER JOIN 
(
    SELECT Word,
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN 
    FROM [dbo].[splitstring]('ABJ/ADD/BKK/KUL/ADD/ABJ','/')
)B ON A.RN = B.RN-1