【问题标题】:Use Split String Table Value Function in a Select statement在 Select 语句中使用拆分字符串表值函数
【发布时间】:2018-07-24 17:49:28
【问题描述】:

我有一张来自第三方的表格,我无法控制。每个地址字段都包含完整的地址,包括邮政编码。每个地址都包含动态数量的单独地址字段。我有一个 Split() TVF,可以将地址字段拆分为单独的行。但是,当我将 TVF 表交叉应用回 SELECT 查询时,它会为 TVF 表中的每个 ro 返回一行。如何让它为主表返回一行并将 COLUMNS 与 TVF 表中的行分开?

提供的地址示例:

一个。 1 街道、地区、城镇、县、邮政编码

b. 2 建筑物、街道、城镇、邮政编码

c。 3 楼 3 楼街道、地区、城镇、县、邮政编码

TVF 使用“,”作为分隔符将这些值作为每行返回一个值。然后,我需要将该数据连接回原始数据,作为每个地址字段的一列。

这是我的选择查询:

select DISTINCT TOP 5 ttp.ProjectID
  ,cac.ID
  ,cac1.Proprietor1Address1
  --,CASE WHEN addr.ID = 1 THEN addr.Data END AS Address1
FROM ArdentTest.ardent.LRTitlesToProcess ttp

JOIN LandRegistryData.landreg.CommercialandCorporateOwnershipData cac
    ON ttp.TitleNo = cac.TitleNumber

JOIN (SELECT TitleNumber
            ,Proprietor1Address1
       FROM LandRegistryData.landreg.CommercialandCorporateOwnershipData
       WHERE 1 = 1
            AND ISNULL(Proprietor1Address1, '') <> '') cac1
    ON ttp.TitleNo = cac1.TitleNumber

CROSS APPLY DBAdmin.resource.Split(cac1.Proprietor1Address1, ', ') addr

WHERE 1 = 1
AND ttp.DateLRRequestSent IS NULL
AND cac.ID IN (50764, 78800, 157089, 206049, 449112)
ORDER BY 1

这会产生以下结果:

ProjectID   ID      Proprietor1Address1
1010        50764   Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010        78800   Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010        157089  Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010        206049  Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010        449112  Church House, Great Smith Street, London SW1P 3AZ

我需要使用函数中的行将单独的地址列添加到结果集中,但我不知道该怎么做。

【问题讨论】:

  • 您不能编写将返回 未知 列数的查询。每个查询总是产生一个具有固定“形状”的结果集——列数、名称和类型。
  • @Damien_The_Unbeliever 使用dynamic pivot...时除外
  • @ZoharPeled - 但我认为这是因为当您使用动态 SQL 时,您正在构建一个要执行的 new 查询。当然,该新查询可能具有您选择的任何形状。它不会改变任何特定查询给出具有固定形状的结果的基本前提。
  • @Damien_The_Unbeliever 我接受你的说法。不过,动态支点可以帮助 OP 获得所需的输出。
  • 我最初的问题可能不是特别清楚。术语 DYNAMIC 的使用不适用于表中的行数或列数。它适用于来自外部数据源的 SINGLE 列中包含的地址字段数。我需要将此 SINGLE 列拆分为不同的地址列,以便为它要进入的数据库正确格式化。

标签: sql tsql


【解决方案1】:

如果您可以做出一些假设,例如地址最多可以包含 10 个部分。您可以使用此脚本。我使用了 STRING_SPLIT 而不是你的 split 函数。

DECLARE @Table TABLE (Id INT, Address VARCHAR(500))
INSERT INTO @Table VALUES
(1, '1 The Street, The Locality, The Town, The County, The Postcode'),
(2, '2 The Building, The Street, The Town, The Postcode'),
(3, 'Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode')

SELECT * FROM @Table T
CROSS APPLY(
    SELECT * FROM (SELECT ROW_NUMBER()OVER(ORDER BY (SELECT NULL)) RN, * FROM STRING_SPLIT(T.Address, ','))  SRC
    PIVOT (MAX(value) FOR RN IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) PVT
) X

结果:

Id          Address                                                                          1                     2                     3                     4                     5                     6                     7                     8                     9                     10
----------- -------------------------------------------------------------------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
1           1 The Street, The Locality, The Town, The County, The Postcode                   1 The Street           The Locality          The Town              The County            The Postcode         NULL                  NULL                  NULL                  NULL                  NULL
2           2 The Building, The Street, The Town, The Postcode                               2 The Building         The Street            The Town              The Postcode         NULL                  NULL                  NULL                  NULL                  NULL                  NULL
3           Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode          Floor 3                3 The Street          The Locality          The Town              The County            The Postcode         NULL                  NULL                  NULL                  NULL

【讨论】:

  • STRING_SPLIT 是 SQL 2016 中的新功能。不幸的是,我们还没有升级。仍在使用 SQL 2014 :-(
  • 我使用 STRING_SPLIT 进行测试,您可以使用自己的拆分函数来代替它。
  • 这种方法的一个问题是,STRING_SPLIT 不保证以给定的顺序返回元素......还有其他选择将这些部分与索引一起返回(例如 Jeff Moden 的 DelimitedSplit8K )
【解决方案2】:

您可以从连接的字符串中创建一个 XML,并通过索引对每个部分进行寻址

--表格(谢谢 Serkan,我复制了你的 DDL)

DECLARE @Table TABLE (Id INT, Address VARCHAR(500))
INSERT INTO @Table VALUES
(1, '1 The Street, The Locality, The Town, The County, The Postcode'),
(2, '2 The Building, The Street, The Town, The Postcode'),
(3, 'Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode');

--此查询将逐个返回部分

WITH Splitted AS
(
    SELECT *
          ,CAST('<x>' + REPLACE((SELECT [Address] AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AsXml
    FROM @Table
)
SELECT *
      ,AsXml.value('/x[1]','nvarchar(max)') AS Col1 
      ,AsXml.value('/x[2]','nvarchar(max)') AS Col2 
      ,AsXml.value('/x[3]','nvarchar(max)') AS Col3 
      ,AsXml.value('/x[4]','nvarchar(max)') AS Col4 
      ,AsXml.value('/x[5]','nvarchar(max)') AS Col5 
      ,AsXml.value('/x[6]','nvarchar(max)') AS Col6 
FROM Splitted

--结果

/*+----+----------------+--------------+--------------+--------------+--------------+--------------+
| ID | Col1           | Col2         | Col3         | Col4         | Col5         | Col6         |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 1  | 1 The Street   | The Locality | The Town     | The County   | The Postcode | NULL         |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 2  | 2 The Building | The Street   | The Town     | The Postcode | NULL         | NULL         |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 3  | Floor 3        | 3 The Street | The Locality | The Town     | The County   | The Postcode |
+----+----------------+--------------+--------------+--------------+--------------+--------------+*/

--您可以在所有步骤中使用REVERSE。这将在所有情况下将邮政编码放在首位(只要邮政编码是那里的最后一个元素)

WITH Splitted AS
(
    SELECT *
          ,CAST('<x>' + REPLACE((SELECT REVERSE([Address]) AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AsXml
    FROM @Table
)
SELECT *
      ,REVERSE(AsXml.value('/x[1]','nvarchar(max)')) AS Col1 
      ,REVERSE(AsXml.value('/x[2]','nvarchar(max)')) AS Col2 
      ,REVERSE(AsXml.value('/x[3]','nvarchar(max)')) AS Col3 
      ,REVERSE(AsXml.value('/x[4]','nvarchar(max)')) AS Col4 
      ,REVERSE(AsXml.value('/x[5]','nvarchar(max)')) AS Col5 
      ,REVERSE(AsXml.value('/x[6]','nvarchar(max)')) AS Col6 
FROM Splitted;

--结果

/*+----+--------------+------------+------------+----------------+--------------+---------+
| ID | Col1         | Col2       | Col3       | Col4           | Col5         | Col6    |
+----+--------------+------------+------------+----------------+--------------+---------+
| 1  | The Postcode | The County | The Town   | The Locality   | 1 The Street | NULL    |
+----+--------------+------------+------------+----------------+--------------+---------+
| 2  | The Postcode | The Town   | The Street | 2 The Building | NULL         | NULL    |
+----+--------------+------------+------------+----------------+--------------+---------+
| 3  | The Postcode | The County | The Town   | The Locality   | 3 The Street | Floor 3 |
+----+--------------+------------+------------+----------------+--------------+---------+*/

【讨论】:

    猜你喜欢
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 2017-10-20
    相关资源
    最近更新 更多