【问题标题】:Issue using CHARINDEX function in SQL Server在 SQL Server 中使用 CHARINDEX 函数的问题
【发布时间】:2021-12-13 10:18:54
【问题描述】:

有人可以帮助我吗?我正在尝试在分隔列中获取特定值。

Column_A 是我的数据 Column_B 是我能得到的 Column_C是我想要的

基本上我正在尝试获取第三个“:”和第四个“:”之间的值

我在这里使用这段代码:

select SourceID
     , SUBSTRING(SourceID,CHARINDEX(':', SourceID, CHARINDEX(':', SourceID) + 1) + 1,
       CHARINDEX(':', SourceID, CHARINDEX(':', SourceID, CHARINDEX(':', SourceID) + 1) + 1) -6)
 from  temp.table

提前致谢

【问题讨论】:

  • SQL Server 具有设计 用于存储多个值的类型。它们被称为表(带有列和行)。当你把所有东西都塞进一个不是为存储多个值而设计的字符串中,然后使用像 T-SQL 这样的字符串处理能力很差的语言时,你会陷入困境。
  • Basically I'm trying to get the values between the 3rd ":" and the 4th ":" 你的意思是在第二和第三之间: ?
  • 当然,如前所述,真正的解决方案是修复您的设计。
  • 您已经硬编码了- 6,这是42:41: 的长度,但这些字符串的大小可能会有所不同。你应该做的是计算第二个:的位置,用它来计算第三个:的位置,然后提取从pos1开始的子字符串,length = pos2 - pos1 - 1(可能需要加或减1 )

标签: sql sql-server substring charindex


【解决方案1】:

您可以根据需要尝试使用递归 CTE 检索字符串的任何部分。像这样的

CREATE TABLE #Temp
(
    MyString NVARCHAR(2000)
)

INSERT INTO #TEMP
VALUES('42:45:ABCD:GGRFG34:SADSAD'),('65:213:5435423:234234')

;WITH CTE AS
(
    SELECT
        ParentSTring = MyString,
        MyString = CASE CHARINDEX(':',MyString) WHEN 0 THEN NULL ELSE SUBSTRING(MyString,CHARINDEX(':',MyString)+1,LEN(MyString)) END,
        Part = CASE CHARINDEX(':',MyString) WHEN 0 THEN MyString ELSE SUBSTRING(MyString,1,CHARINDEX(':',MyString)-1) END,
        Seq = 1
    FROM 
        #Temp

    UNION ALL

    SELECT
        ParentSTring,
        MyString = CASE CHARINDEX(':',MyString) WHEN 0 THEN NULL ELSE SUBSTRING(MyString,CHARINDEX(':',MyString)+1,LEN(MyString)) END,
        Part = CASE CHARINDEX(':',MyString) WHEN 0 THEN MyString ELSE SUBSTRING(MyString,1,CHARINDEX(':',MyString)-1) END,
        Seq = ISNULL(Seq,0)+1
    FROM 
        CTE
    WHERE 
        ISNULL(MyString, '') <> ''
)
SELECT
    *
FROM 
    CTE
WHERE 
    Seq = 3 -- for retrieving the 3rd string, change this accordingly

结果

【讨论】:

  • 嗨@Jayasurya,感谢您的输入,但这不起作用,我有一张大桌子要阅读,所以我需要更简单的东西,但是,谢谢
【解决方案2】:

首先,如果性能很重要,那么递归 CTE 不是您想要的。我马上说明原因。

我有一个简单的解决方案here,称为 SubstringBetween8K,但它对你正在做的事情来说有点过头了。为此,一个简单的Cascading APPLY 将发挥作用并发挥最佳作用。首先是样本数据:

IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp;
GO
CREATE TABLE #temp (SourceId VARCHAR(1000));
INSERT #temp VALUES('42:45:10856x2019035x1200:GGRFG34:SADSAD.9999999999999999'),
                   ('65:213:999555x2019035x9444:5435423:234234,123123.111'),
                   ('999:12344:5555511056x35x9111:5435423:234234,555555555555'),
                   ('225:0:11056x2019035x9444:5435423:ABAFLHG.882');

接下来是级联应用解决方案。

SELECT      Item = SUBSTRING(t.SourceId,  f2.Pos+1, f3.Pos-f2.Pos-1)
FROM        #temp AS t
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId)))          AS f1(Pos)
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId,f1.Pos+1))) AS f2(Pos)
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId,f2.Pos+1))) AS f3(Pos);

结果:

Item
------------------------
10856x2019035x1200
999555x2019035x9444
5555511056x35x9111
11056x2019035x9444

现在是一个快速的性能测试,它将展示为什么不使用递归 CTE。

--==== Sample data
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp;
GO
CREATE TABLE #temp (SourceId VARCHAR(1000));
INSERT #temp VALUES('42:45:10856x2019035x1200:GGRFG34:SADSAD.9999999999999999'),
                   ('65:213:999555x2019035x9444:5435423:234234,123123.111'),
                   ('999:12344:5555511056x35x9111:5435423:234234,555555555555'),
                   ('225:0:11056x2019035x9444:5435423:ABAFLHG.882');

--==== Add 10K rows for performance testing
INSERT #temp
SELECT TOP (100000) sourceId 
FROM   #temp
CROSS JOIN sys.all_columns, sys.all_columns AS b
GO

--==== Performance Test
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2;
GO

SET STATISTICS TIME, IO ON;

PRINT CHAR(10)+'Cascading CTE'+CHAR(10)+REPLICATE('-',90);

SELECT      Item = SUBSTRING(t.SourceId,  f2.Pos+1, f3.Pos-f2.Pos-1)
INTO        #t1
FROM        #temp AS t
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId)))          AS f1(Pos)
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId,f1.Pos+1))) AS f2(Pos)
CROSS APPLY (VALUES(CHARINDEX(':',t.SourceId,f2.Pos+1))) AS f3(Pos);


PRINT CHAR(10)+'Recursive CTE'+CHAR(10)+REPLICATE('-',90);
;WITH CTE AS
(
    SELECT
        ParentSTring = SourceId,
        SourceId = CASE CHARINDEX(':',SourceId) WHEN 0 THEN NULL ELSE SUBSTRING(SourceId,CHARINDEX(':',SourceId)+1,LEN(SourceId)) END,
        Part = CASE CHARINDEX(':',SourceId) WHEN 0 THEN SourceId ELSE SUBSTRING(SourceId,1,CHARINDEX(':',SourceId)-1) END,
        Seq = 1
    FROM  #temp 
    UNION ALL
    SELECT
        ParentSTring,
        MyString = CASE CHARINDEX(':',SourceId) WHEN 0 THEN NULL ELSE SUBSTRING(SourceId,CHARINDEX(':',SourceId)+1,LEN(SourceId)) END,
        Part = CASE CHARINDEX(':',SourceId) WHEN 0 THEN SourceId ELSE SUBSTRING(SourceId,1,CHARINDEX(':',SourceId)-1) END,
        Seq = ISNULL(Seq,0)+1
    FROM  CTE
    WHERE ISNULL(SourceId, '') <> ''
)
SELECT Part
INTO   #t2
FROM   CTE
WHERE  Seq = 3

SET STATISTICS TIME, IO OFF;

测试结果:

Cascading CTE
------------------------------------------------------------------------------------------
Table '#temp'. Scan count 9, logical reads 807, physical reads 0...

 SQL Server Execution Times: CPU time = 327 ms,  elapsed time = 111 ms.

Recursive CTE
------------------------------------------------------------------------------------------
Table 'Worktable'. Scan count 2, logical reads 4221845, physical reads 0...
Table '#temp'. Scan count 1, logical reads 807, physical reads 0...

 SQL Server Execution Times: CPU time = 8781 ms,  elapsed time = 9370 ms.

从 1/10 秒到 10 秒。大约 100 倍的性能提升。递归 CTE 的部分问题是过多的 IO(读取)。请注意简单的 10K 行的 430 万次读取。

【讨论】:

  • 嗨@Alan Burstein,感谢您的回答,我会检查一下
猜你喜欢
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2014-01-03
相关资源
最近更新 更多