2017-08-17 229 views
1

,我有以下我的数据库中的文本字符串:SQL Server的一个字符串中删除多个字符串

Value1 - Value2: Value3 - Value4: Value5 - Value6: 

我需要删除破折号之间的破折号和一切,直到结肠

的上述结果将变成:

Value1: Value3: Value5: 

基本上,有可能是值的无穷无尽的,但也可能仅只是一个系列的一员。

需要注意的是:值可以是任何字符串!

有没有简单的方法来做到这一点?优选没有UDF。任何人都可以帮我解决这个问题吗?提前致谢!

编辑:我同意这是一个非常糟糕的实施。数据库的其余部分本身并不是这样。这只是一张桌子。我从中得到的查询将用于所有值分离为多个别名的视图中。感谢您的谅解

+1

在开始之前,它看起来像执行非常差在单个列使用文本EAV'的'。我强烈建议停止并规范您的模式。或者至少使用某种类型的结构化数据,比如'XML' /'JSON' – lad2025

+1

您应该修复数据模型,使每个实体有一行,每个值在单独的行中。如果你不能这样做,你应该解释为什么你要在一个字符串中存储多个值 - 这不是存储数据的SQLish方式。 –

+2

请考虑重构您的数据库。这是一个糟糕的设计。 阅读[在数据库列中存储分隔列表真的不好吗?](http://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-那么 - 坏),在那里你会看到很多原因,为什么这个问题的答案是**绝对是!** –

回答

0
SELECT substring(NameValue, 1, charindex('_', NameValue)-1) AS Names, 
    substring(NameValue, charindex('_', NameValue)+1, LEN(NameValue)) AS Values 
FROM Table 

编辑:像这样的东西放一个函数或存储过程与临时表组合应该适用于多行,这取决于你前行分隔符,你也应该删除CHAR(13)开始:

DECLARE @helper varchar(512) 
DECLARE @current varchar(512) 
SET @helper = NAMEVALUE 
WHILE CHARINDEX(CHAR(10), @helper) > 0 BEGIN 
    SET @current = SUBSTRING(@helper, 1, CHARINDEX(CHAR(10), NAMEVALUE)-1) 
    SELECT SUBSTRING(@current, 1, CHARINDEX('_', @current)-1) AS Names, 
     SUBSTRING(@current, CHARINDEX('_', @current)+1, LEN(@current)) AS Names 
    SET @helper = SUBSTRING(@helper, CHARINDEX(CHAR(10), @helper)+1, LEN(@helper)) 
END 
SELECT SUBSTRING(@helper, 1, CHARINDEX('_', @helper)-1) AS Names, 
    SUBSTRING(@helper, CHARINDEX('_', @helper)+1, LEN(@helper)) AS Names 
+1

请不要使用并建议分割字符串的循环。这种类型的分路器的性能是可怕的。这是一个更好的选择。 http://www.sqlservercentral.com/articles/Tally+Table/72993/和其他一些选项。 http://sqlperformance.com/2012/07/t-sql-queries/split-strings –

1

您可以使用拆分功能......尽管您的值不应该像这样存储在第一位。

declare @table table (col1 varchar(256)) 
insert into @table 
values 
('Value1 - Value2: Value3 - Value4: Value5 - Value6:') 

select 
    ReturnVal = replace(ltrim(left(Item,charindex('-',Item))),'-',':') 
from 
    @table 
    cross apply dbo.DelimitedSplit8K(col1,':') 
where 
    Item <> '' 

退货

+-----------+ 
| ReturnVal | 
+-----------+ 
| Value1 : | 
| Value3 : | 
| Value5 : | 
+-----------+ 

或者,一个丑陋的黑客攻击拿回来你想要的

select distinct 
    --ReturnVal = replace(ltrim(left(Item,charindex('-',Item))),'-',':') 
    ReturnVal = 'V' + STUFF((
      SELECT replace(left(Item,charindex('-',Item)),'-',':') 
      FROM 
      @table 
      cross apply dbo.DelimitedSplit8K(col1,':') 
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') 
from 
    @table 
    cross apply dbo.DelimitedSplit8K(col1,':') 
where 
    Item <> '' 

退货

ReturnVal 
Value1 : Value3 : Value5 : 

JEFF MODEN SPLITTER

CREATE FUNCTION [dbo].[DelimitedSplit8K] (@pString VARCHAR(8000), @pDelimiter CHAR(1)) 
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE! 

RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 

/* "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000... 
enough to cover VARCHAR(8000)*/ 

    WITH E1(N) AS (
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
       SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
       ),       --10E+1 or 10 rows 
     E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows 
     E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max 
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front 
        -- for both a performance gain and prevention of accidental "overruns" 
       SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
       ), 
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter) 
       SELECT 1 UNION ALL 
       SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
       ), 
cteLen(N1,L1) AS(--==== Return start and length (for use in substring) 
       SELECT s.N1, 
         ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000) 
        FROM cteStart s 
       ) 
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found. 
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
     Item  = SUBSTRING(@pString, l.N1, l.L1) 
    FROM cteLen l 
; 
GO 
相关问题