拆分值对并使用 UDF 创建表

2023-12-13

我一直在尝试编写一个表值函数,它将值对作为参数并返回一个包含两列的表。

下面是我想要做的函数签名。

FUNCTION [dbo].[ValuePairParser]( @DelimitedValuePairs VARCHAR(MAX),
                                  @Delimiter CHAR(1), 
                                  @ValuePairDelimiter CHAR(1) ) 
  RETURNS @ValuePairTable
  TABLE ( Id INT, Code INT ) 

我想调用如下方法

@ValuePairs VARCHAR(MAX) = '1:1, 1:2, 1:4, 2:3, 1000:230, 130:120,'

ValuePairParser (@ValuePairs, ',', ':')

您能看到任何分割上面的值对字符串并创建一个包含两列的表的好方法吗?


十年后回顾,今天肯定有更好的方法来做到这一点。

SQL Server 2022、Azure SQL 数据库、托管实例

(example)

CREATE OR ALTER FUNCTION dbo.SplitWithPairs
(
    @List           nvarchar(max),
    @MajorDelimiter varchar(3) = ',',
    @MinorDelimiter varchar(3) = ':'
)
RETURNS TABLE WITH SCHEMABINDING
AS
  RETURN 
  (
    SELECT LeftItem = [1], RightItem = [2], Position
    FROM
    (
      SELECT Position = o.ordinal, 
             value    = TRIM(i.value),
             i.ordinal
        FROM        STRING_SPLIT(@List,   @MajorDelimiter, 1) AS o
        CROSS APPLY STRING_SPLIT(o.value, @MinorDelimiter, 1) AS i
      WHERE o.value > ''
    ) AS s PIVOT (MAX(value) FOR ordinal IN ([1],[2])) AS p
  );

SQL Server 2016 - 2019

(example)

在 SQL Server 2016 到 2019 中,进行了一些更改:

  • STRING_SPLIT在 SQL Server 2022 之前不支持序数,因此我们可以使用OPENJSON instead
  • 我们需要使用LTRIM/RTRIM since TRIM在 SQL Server 2017 中添加
  • key是从 0 开始的,所以我们增加 1 以获得等效的从 1 开始的位置

关于此功能的一个注意事项是您不能使用,作为次定界符而不改变函数,因为, is how OPENJSON划定界限。您可能希望在这两个分隔符中保留其他字符。

CREATE OR ALTER FUNCTION dbo.SplitWithPairs
(
    @List           nvarchar(max),
    @MajorDelimiter varchar(3) = ',',
    @MinorDelimiter varchar(3) = ':' -- can't be ,
)
RETURNS TABLE WITH SCHEMABINDING
AS
  RETURN 
  (
    SELECT LeftItem = [1], RightItem = [2], Position
    FROM
    (  
      SELECT Position = o.[key] + 1, 
             value    = LTRIM(RTRIM(i.value)),
             ordinal  = i.[key] + 1
      FROM OPENJSON
      (
        CONCAT('["', REPLACE(STRING_ESCAPE(@List, 'JSON'), 
          @MajorDelimiter, '","'), '"]')
      ) AS o
      CROSS APPLY OPENJSON
      (
        REPLACE(CONCAT('[', QUOTENAME(o.value, '"'), ']'), 
          @MinorDelimiter, '","')
      ) AS i
      WHERE o.value > ''
    ) AS s PIVOT (MAX(value) FOR ordinal IN ([1],[2])) AS p
  );

不再支持的版本

最后,原始答案适用于早于 SQL Server 2016 的版本,我将保持原样,但免责声明它可以改进(不乏阅读有关该内容的文章)here而且,一般来说,多语句表值函数(尤其是循环)是一个很大的危险信号):

CREATE FUNCTION [dbo].[SplitWithPairs]
(
    @List NVARCHAR(MAX),
    @MajorDelimiter VARCHAR(3) = ',',
    @MinorDelimiter VARCHAR(3) = ':'
)
RETURNS @Items TABLE
(
    Position  INT IDENTITY(1,1) NOT NULL,
    LeftItem  INT NOT NULL,
    RightItem INT NOT NULL
)
AS
BEGIN
    DECLARE
        @Item      NVARCHAR(MAX),
        @LeftItem  NVARCHAR(MAX),
        @RightItem NVARCHAR(MAX),
        @Pos       INT;

    SELECT
        @List = @List + ' ',
        @MajorDelimiter = LTRIM(RTRIM(@MajorDelimiter)),
        @MinorDelimiter = LTRIM(RTRIM(@MinorDelimiter));

    WHILE LEN(@List) > 0
    BEGIN
        SET @Pos = CHARINDEX(@MajorDelimiter, @List);

        IF @Pos = 0 
            SET @Pos = LEN(@List) + LEN(@MajorDelimiter);

        SELECT
            @Item = LTRIM(RTRIM(LEFT(@List, @Pos - 1))),
            @LeftItem = LTRIM(RTRIM(LEFT(@Item,
            CHARINDEX(@MinorDelimiter, @Item) - 1))),
            @RightItem = LTRIM(RTRIM(SUBSTRING(@Item,
            CHARINDEX(@MinorDelimiter, @Item)
            + LEN(@MinorDelimiter), LEN(@Item))));

        INSERT @Items(LeftItem, RightItem)
            SELECT @LeftItem, @RightItem;

        SET @List = SUBSTRING(@List,
            @Pos + LEN(@MajorDelimiter), DATALENGTH(@List));
    END
    RETURN;
END
GO

DECLARE @ValuePairs VARCHAR(MAX) = '1:1, 1:2, 1:4, 2:3,1000:230, 130:120,';

SELECT LeftItem, RightItem
  FROM dbo.SplitWithPairs(@ValuePairs, ',', ':')
  ORDER BY Position;
GO
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

拆分值对并使用 UDF 创建表 的相关文章

  • 带可选参数的 SQL 更新命令?

    我将大约 500 000 个对象插入数据库 其中许多对象是相同的 在数据库中具有相同的主键表示 但其他字段可能不同 因此我使用方法 更新 如果没有行受影响 插入 问题是 有时一个对象的某些字段设置为 null 从文件中无法读取 并且已经在数
  • mssql 的 UUID 疯狂

    我的数据库条目有一个 UUID 及其值 使用 Microsoft SQL Server Management Studio 提取 CDF86F27 AFF4 2E47 BABB 2F46B079E98B 将其加载到我的 Scala 应用程序
  • 在 SQL 中查询行序列

    假设我正在存储events有关联users如下表 其中dt代表事件的时间戳 dt user event 1 1 A 2 1 D 3 1 B 4 1 C 5 1 B 6 2 B 7 2 B 8 2 A 9 2 A 10 2 C 这样我们就可以
  • 即使在不活动状态下,Hangfire 也会继续运行 SQL 查询

    我正在开发一个 ASP net MVC 5 网站 并使用 Hangfire 来安排一些任务 在本例中每 3 分钟一次 我知道一个事实是 运行这样的任务 以及与之相关的数据库查询 只需要几秒钟 我面临的问题是 Hangfire 似乎让我的 S
  • SQL Server 2014执行计划创建需要很长时间(旧版本中很快)

    我在 SQL Server 2014 中遇到一个查询问题 第一次运行该查询时 需要很长时间才能生成执行计划 奇怪的是 它在 SQL Server 的所有早期版本 2012 2008 R2 2008 等 中都运行良好 它似乎与所涉及的表之一上
  • 排除任何字段中具有 NULL 值的行结果?

    我有一个像这样的简单选择 SELECT FROM table WHERE fk id 10020 它可以工作 但有一些字段为 NULL 没有模式所以做了 SELECT FROM table WHERE fk id 10020 AND NOT
  • 有没有办法将应用程序上下文与非 Sybase DB 服务器中的数据库连接进行通信(类似于 Sybase 中的 set_appcontext)?

    Sybase 有一种让应用程序进行通信的方法 上下文 数据 http manuals sybase com onlinebooks group as asg1250e sag Generic BookTextView 38861 hf 0
  • PDO 和 Microsoft SQL:必须声明表变量“@P1”

    我正在尝试使用 PDO 中的绑定从 Microsoft SQL 数据库中选择一些条目 我正在使用的代码看起来与我在文档中找到的代码类似 但是 当我运行它时 我收到以下警告 警告 PDOStatement execute pdostateme
  • mysql变量赋值:如何强制赋值顺序?

    由于mysql是一种声明性语言 我找不到强制赋值变量顺序的方法 采取这个查询 SET v1 0 SET v2 0 SELECT v1 v2 FROM MyTable table WHERE v1 v2 is not null AND v2
  • 找出会话的默认 SQL Server 架构

    我需要知道正在执行某些 DDL 的 SQL 脚本中当前的默认架构是什么 我不需要设置架构 但我确实需要将对它的引用 名称或 ID 放入变量中 该脚本可能以 Windows 登录身份运行 因此以下内容还不够 SELECT name defau
  • 删除 Sql 服务器中最后一次出现特殊字符之前的子字符串

    我想删除最后一次出现句点之前的子字符串 查询应该转换r k Lee Brown to Lee Brown 所以 基本上我需要最后一个点之前的子字符串 并将其替换为 尝试这个 SELECT RIGHT str CHARINDEX REVERS
  • T-SQL 中的不等式测试

    我刚刚在 WHERE 子句中遇到了这个 AND NOT t id id 这与以下内容相比如何 AND t id id Or with AND t id lt gt id 我总是自己写后者 但显然其他人有不同的想法 其中一个的表现会比另一个更
  • 删除 SQL Server 上的所有扩展属性

    如何以可编写脚本的方式删除 SQL Server 上的所有扩展属性 如果您想要一个能够一次性删除所有扩展属性的脚本 请使用 Jamie Thomson 创建的脚本 该脚本将为所有扩展属性生成删除 您可以从这里下载article http s
  • 使用聚合函数时减少 Athena 扫描的数据量

    以下查询扫描 100 MB 的数据 select from table where column1 val and partition id 20190309 然而 下面的查询扫描了 15 GB 的数据 有超过 90 个分区 select
  • 使用 sql 查询选择最近 30 天

    我正在查找过去 30 天内周一 周二 周三 周四 周五 周六 周日的数量 我可以在没有实际数据库表的情况下选择最近 30 天的日期和星期几吗 就像是 SELECT everything between convert date GETDAT
  • 为什么实体框架 6 在插入后不只选择scope_identity()?

    当您使用 EF 6 1 保存实体时 将生成并执行以下 SQL 代码 exec sp executesql N INSERT dbo Customers Name FirstName VALUES 0 1 SELECT CustomerId
  • 简单的t-sql而不是触发器

    任何人都可以帮助解决简单的 t sql 脚本与板载触发器的问题吗 我使用非常简单的触发器将数据从一个表复制到另一个表 这些表之间没有关系 当我尝试在触发器创建后 从同一脚本 直接第一次插入数据时 我得到了所需的结果 但所有接下来的尝试都会失
  • 计算行数并仅获取表中的最后一行

    我有一张桌子叫employeexam其结构和数据是这样的 id course id employee id degree date 1 1 3 8 2013 01 14 2 2 4 15 2013 01 14 3 2 4 17 2013 0
  • 根据 SQL 查询的集合生成成员的“散点图”结果

    我有一个staff包含工作人员的数据库表 其中user no and user name列 我还有一个 department 包含员工可以加入的部门的表 其中dept no and dept name作为列 因为员工可以是多个部门的成员 所
  • SQL Server XQuery 返回错误

    我正在 SQL Server 2012 中对 XML 数据类型列执行查询 数据示例如下

随机推荐