【问题标题】:SQL How to return column value based in other substring position delimited by commasSQL如何根据逗号分隔的其他子字符串位置返回列值
【发布时间】:2018-03-13 14:33:19
【问题描述】:

我的第一篇文章!我希望你能帮助我:)

我正在使用 SQL 2017,我有一个这样的表:

+----+------------------+------------------+ | ID | Col1 | Col2 | +-----+------------------+------------------+ | 110 | 450,2,50,110,600 | 3,45,30,901,1001 | | 250 | 2,250,300,1 | 1,33,540,900 | | 45 | 1,45,320 | 200,444,600 | +-----+------------------+------------------+

逻辑是在 Col1 中找到 ID 位置,并根据该位置返回 Col2 中的子字符串。

例子:

ID 110 匹配 Col1 中的第 4 个位置,因此应该在 Col2 中返回 901 值。
ID 250 匹配 Col1 中的第二个位置,因此应该在 Col2 中返回 33 值。
ID 45 匹配 Col1 中的第二个位置,因此应该在 Col2 中返回 400 值。

我做了不同的尝试都没有成功,可能我的方向错了。

你能帮忙吗?

我想要的输出是 Col2 的特定值。

谢谢!

【问题讨论】:

  • 您能否在问题中包含您希望最终输出的样子?
  • 不要像这样在 SQL 表中存储 CSV。即使你得到了答案,它也会有问题并且难以使用/维护。
  • 什么版本的 SQL Server?
  • 我同意@TimBiegeleisen。这里唯一有意义的答案是修复您的数据模型。你所拥有的东西违反了 1NF 并且使用起来很糟糕。
  • 请记住,很多人不拥有数据库,他们不设计数据库,但仍然必须在交给他们的某些条件下工作。所以 cmets 说这是糟糕的设计是正确的,但在这里根本没有帮助......

标签: sql sql-server indexing substring charindex


【解决方案1】:

对于 SQL Server 2016+(由于 STRING_SPLIT 支持,我不会更早地做一个

DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));

INSERT @BadDesign VALUES
    (110,'450,2,50,110,600', '3,45,30,901,1001'),
    (250,'2,250,300,1', '1,33,540,900'),
    (45 ,'1,45,320', '200,444,600')    

SELECT
    * 
FROM
    @BadDesign B
    CROSS APPLY
    (SELECT 
       rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value 
     FROM  
        STRING_SPLIT(B.Col1, ',')
    ) b1
    CROSS APPLY
    (SELECT 
        rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), value
     FROM
        STRING_SPLIT(B.Col2, ',')
     ) b2
WHERE
    B.ID = b1.value AND b1.rn = b2.rn

不保证 ROW_NUMBER 与 STRING_SPLIT 的输出一致。

编辑:还需要database compatibility to be 130 或更高版本(SQL Server 2016)

STRING_SPLIT 函数仅在兼容级别下可用 130.如果你的数据库兼容级别低于130,SQL Server将无法找到并执行STRING_SPLIT函数。你 可以使用以下方法更改数据库的兼容级别 命令:ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130

【讨论】:

【解决方案2】:

使用自定义字符串拆分函数(此答案使用 Aaron Bertrand 编写的函数),因此不限制在 SQL2016+ 上的使用

CREATE FUNCTION dbo.SplitStringsOrdered (
      @List         NVARCHAR(2000)
    , @Delimiter    NVARCHAR(32)
)
RETURNS TABLE
AS
RETURN (
        SELECT
            rn  = ROW_NUMBER() OVER (ORDER BY Number)
            , Item
        FROM
            (
                SELECT
                    Number
                    , Item = LTRIM(RTRIM(SUBSTRING(
                                                    @List
                                                    , Number
                                                    , CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number
                                                )
                                        )
                                )
                FROM
                    (
                        SELECT  ROW_NUMBER() OVER (ORDER BY [object_id])
                        FROM
                            sys.all_objects
                    ) AS n(Number)
                WHERE
                    Number                                                  <= CONVERT(INT, LEN(@List))
                AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter))  = @Delimiter
            ) AS y
    );
GO

并修改@gbn 在他/她的回答中创建的查询 - SO 是否允许这样做?

DECLARE @BadDesign table (ID int, Col1 varchar(200), Col2 varchar(200));

INSERT @BadDesign VALUES
    (110,'450,2,50,110,600', '3,45,30,901,1001'),
    (250,'2,250,300,1', '1,33,540,900'),
    (45 ,'1,45,320', '200,444,600')    

SELECT
    B.*, Col1Value=b1.Item, Cal2Value = B2.Item
FROM
    @BadDesign B
    CROSS APPLY
    (SELECT 
       rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F.Item
     FROM  
        dbo.SplitStringsOrdered(B.Col1, ',') F
    ) b1
    CROSS APPLY
    (SELECT 
        rn = ROW_NUMBER() OVER (ORDER BY (SELECT 1)), F1.Item
     FROM
        dbo.SplitStringsOrdered(B.Col2, ',') F1
     ) b2
WHERE
    b1.rn = b2.rn

【讨论】:

  • 是的,这是允许的,我为早期版本 +1
  • 我感谢 +1 @gbn
  • 嗨@Cool_Br33ze!感谢您的回答!有效!!您的脚本返回的正是我所需要的 :) +1 为您服务。顶!!
  • @DinisFonseca 我很乐意为您提供帮助
猜你喜欢
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 2012-11-01
  • 2017-07-22
  • 2014-03-16
  • 2013-09-30
相关资源
最近更新 更多