【问题标题】:split alpha and numeric using sql使用 sql 拆分字母和数字
【发布时间】:2015-01-16 14:01:52
【问题描述】:

我有一张桌子,它有 3 列。 first column是包含值(数值)和单位(百分比等)的数据,第二列是numeric column,第三列是Unit column。我想要做的是从第一列中拆分数字和单位,然后将这些拆分后的数据放到其指定的列中。

这是我的桌子:

我试过这个函数:SO link here...,它确实可以拆分字母和数字,但是我是使用 SQL 函数的新手,我的问题是参数必须在字符串 STRING 中,所以我所做的是改变它到子查询,但它给了我错误。

示例代码:

SQL 函数:

create function [dbo].[GetNumbersFromText](@String varchar(2000))
returns table as return
(
  with C as
  (
    select cast(substring(S.Value, S1.Pos, S2.L) as int) as Number,
           stuff(s.Value, 1, S1.Pos + S2.L, '') as Value
    from (select @String+' ') as S(Value)
      cross apply (select patindex('%[0-9]%', S.Value)) as S1(Pos)
      cross apply (select patindex('%[^0-9]%', stuff(S.Value, 1, S1.Pos, ''))) as S2(L)
    union all
    select cast(substring(S.Value, S1.Pos, S2.L) as int),
           stuff(S.Value, 1, S1.Pos + S2.L, '')
    from C as S
      cross apply (select patindex('%[0-9]%', S.Value)) as S1(Pos)
      cross apply (select patindex('%[^0-9]%', stuff(S.Value, 1, S1.Pos, ''))) as S2(L)
    where patindex('%[0-9]%', S.Value) > 0
  )
  select Number
  from C
)

带有 SUB 查询的 SELECT STATEMENT:

declare @S varchar(max)
select number from GetNumbersFromText(Select SomeColm From Table_Name) option (maxrecursion 0)

顺便说一句,我使用的是 sql server 2005。

谢谢!

【问题讨论】:

  • 第一个空格之前的字符串是你的第二列值,空格之后的字符串是你的单位值。使用 charindex 和 substring 函数。
  • @knkarthick24 它没有与space 分隔,有些数据只有一行.. 比如percentage
  • 一个更好的数据集真的会帮助那些回答最好的人。问题中未正确显示您的数据的许多细微差别。
  • @Chris 我更新了我的数据。
  • 看看我尝试处理你的所有场景。

标签: sql-server sql-server-2005 split


【解决方案1】:

如果数字部分总是在开头,那么你可以这样使用:

PATINDEX('%[0-9][^0-9]%', ConcUnit)

获取最后一位的索引。

因此,这个:

DECLARE @str VARCHAR(MAX) = '4000 ug/ML' 

SELECT LEFT(@str, PATINDEX('%[0-9][^0-9]%', @str )) AS Number,
       LTRIM(RIGHT(@str, LEN(@str) - PATINDEX('%[0-9][^0-9]%', @str ))) As Unit

给你:

Number  Unit
-------------
4000    ug/ML

编辑:

如果数字数据也包含双精度值,那么您可以使用这个:

SELECT LEN(@str) - PATINDEX ('%[^0-9][0-9]%', REVERSE(@str))

获取最后一位数字的索引

因此,这个:

SELECT LEFT(@str, LEN(@str) - PATINDEX ('%[^0-9][0-9]%', REVERSE(@str)))

给你数字部分。

还有这个:

SELECT LEFT(@str, LEN(@str) - PATINDEX ('%[^0-9][0-9]%', REVERSE(@str))) AS Numeric,
       CASE 
          WHEN CHARINDEX ('%', @str) <> 0 THEN LTRIM(RIGHT(@str, LEN(@str) - CHARINDEX ('%', @str)))
          ELSE LTRIM(RIGHT(@str, PATINDEX ('%[^0-9][0-9]%', REVERSE(@str))))
       END AS Unit

为您提供数字和单位部分。

以下是我使用您发布的数据进行的一些测试:

输入:

DECLARE @str VARCHAR(MAX) = '50 000ug/ML'

输出:

Numeric Unit
------------
50 000  ug/ML

输入:

DECLARE @str VARCHAR(MAX) = '99.5%'

输出:

Numeric Unit
------------
99.5    

输入:

DECLARE @str VARCHAR(MAX) = '4000 . 35 % ug/ML'

输出:

Numeric     Unit
------------------
4000 . 35   ug/ML

【讨论】:

  • 我试过了.. 它有一些价值,但不适用于dot,如下所示:DECLARE @str VARCHAR(MAX) = '45.5%'
  • .5%UNIT 列上。
  • @Unknownymous2 对不起,我以为数值总是整数
  • 不,先生。抱歉,如果我的帖子中没有说明它也包含双数。但我相信你的代码接近我的预期结果,你会更新你的答案。
  • '%[0-9][^0-9\.]%' 可能适用于 PATINDEX 中的双打
【解决方案2】:

这是我的答案。检查SQLFiddle 中的输出是否相同。

create TABLE temp
(
      string NVARCHAR(50)
)

INSERT INTO temp (string)
VALUES 
    ('4000 ug\ml'),
    ('2000 ug\ml'),
    ('%'),
    ('ug\ml')

SELECT subsrtunit,LEFT(subsrtnumeric, PATINDEX('%[^0-9]%', subsrtnumeric+'t') - 1)
FROM (
    SELECT subsrtunit = SUBSTRING(string, posofchar, LEN(string)),
  subsrtnumeric = SUBSTRING(string, posofnumber, LEN(string))
    FROM (
        SELECT string, posofchar = PATINDEX('%[^0-9]%', string),
      posofnumber = PATINDEX('%[0-9]%', string)
        FROM temp
    ) d
) t

更新版本以处理 99.5 ug\ml

create TABLE temp
(
      string NVARCHAR(50)
)

INSERT INTO temp (string)
VALUES 
    ('4000 ug\ml'),
    ('2000 ug\ml'),
    ('%'),
    ('ug\ml'),
    ('99.5 ug\ml')

SELECT subsrtunit,LEFT(subsrtnumeric, PATINDEX('%[^0-9.]%', subsrtnumeric+'t') - 1)
FROM (
    SELECT subsrtunit = SUBSTRING(string, posofchar, LEN(string)),
  subsrtnumeric = SUBSTRING(string, posofnumber, LEN(string))
    FROM (
        SELECT string, posofchar = PATINDEX('%[^0-9.]%', string),
      posofnumber = PATINDEX('%[0-9.]%', string)
        FROM temp
    ) d
) t

更新版本:处理1 000 ug\ml,20 000ug\ml

create TABLE temp
(
      string NVARCHAR(50)
)

INSERT INTO temp (string)
VALUES 
    ('4000 ug\ml'),
    ('2000 ug\ml'),
    ('%'),
    ('ug\ml'),
    ('99.5 ug\ml'),
    ('1 000 ug\ml'),
    ('20 000ug\ml')

SELECT substring(replace(subsrtunit,' ',''),PATINDEX('%[0-9.]%', replace(subsrtunit,' ',''))+1,len(subsrtunit)),
LEFT(replace(subsrtnumeric,' ',''), PATINDEX('%[^0-9.]%', replace(subsrtnumeric,' ','')+'t') - 1)
FROM (
    SELECT subsrtunit = SUBSTRING(string, posofchar, LEN(string)),
  subsrtnumeric = SUBSTRING(string, posofnumber, LEN(string))
    FROM (
        SELECT string, posofchar = PATINDEX('%[^0-9.]%', replace(string,' ','')),
      posofnumber = PATINDEX('%[0-9.]%', replace(string,' ',''))
        FROM temp
    ) d
) t

查看SQLFiddle 以获取相同信息。

【讨论】:

  • 它不适用于 double 号码,如下所示:45.5% .5%subsrtunit 列上。
  • 以及带有spacing的4位数字,例如:1 000
  • 立即查看处理99.5 ug\ml的答案
  • 试试这个:1 000ug\ml(每 3 位有空格,数字和单位没有空格)它似乎对我不起作用。
  • 首先,您为什么要拥有这种数据?无论你要求什么,都有一定的意义。这在任何地方都不是有效的方案。请考虑相应地清理您的数据。
【解决方案3】:

这样的东西会起作用吗?根据显示的数据,它看起来会这样。

将其作为选择应用于您的数据集,如果您喜欢结果,则可以从中进行更新。

WITH cte as (SELECT 'ug/mL' ConcUnit, 500 as [Numeric], '' as Unit 
   UNION ALL SELECT '2000 ug/mL',     NULL,             '')

SELECT
    [ConcUnit]                  as [ConcUnit],
    [Numeric]                   as [Original Numeric],
    [Unit]                      as [Original Unit],
    CASE WHEN ConcUnit LIKE '% %' THEN 
        SUBSTRING(ConcUnit, 1, CHARINDEX(' ', ConcUnit) - 1) 
        ELSE [Numeric] END      as [New Numeric],
    CASE WHEN ConcUnit LIKE '% %' 
        THEN SUBSTRING(ConcUnit, CHARINDEX(' ', ConcUnit) + 1, LEN(ConcUnit)) 
        ELSE ConcUnit END       as [New Unit]
FROM cte

【讨论】:

  • 它不是用space分隔的,其他值没有spacing比如percentage:WITH cte as (SELECT 'ug/mL' ConcUnit, 500 as [Numeric], '' as Unit UNION ALL SELECT '2000%', NULL, '')
【解决方案4】:

分别更改@concunit 和@unitx

 DECLARE @concunit varchar(10)='45.5%'
DECLARE @unitx varchar(10)='%'

BEGIN
SELECT RTRIM(SUBSTRING( @concunit , 1 , CHARINDEX( @unitx , @concunit
                                              ) - 1
                )) AS Number, 
       RTRIM(SUBSTRING( @concunit , CHARINDEX( @unitx , @concunit
                                          ) , LEN( @concunit
                                                 ) - (CHARINDEX( @unitx , @concunit
                                                               ) - 1)
                )) AS Unit

end

【讨论】:

  • 不适用于percentage 先生。它给了我错误:Msg 537, Level 16, State 2, Line 5 Invalid length parameter passed to the LEFT or SUBSTRING function.
  • 我用这个:DECLARE @concunit varchar(10)='45.5%'
  • DECLARE var concunit varchar(10)='45.5%' DECLARE var unitx varchar(10)='%'
【解决方案5】:

我也有同样的困境,但在我的例子中,字母在数字前面。

所以使用@Giorgos Betsos 在他的答案中添加的逻辑,我只是​​将其颠倒过来。

即,当您的输入是:

abc123

你可以这样拆分:

declare @input  varchar(30) = 'abc123'

    select
        replace(@input,reverse(LEFT(reverse(@input), PATINDEX('%[0-9][^0-9]%', reverse(@input) ))),'')  Alpha
    ,   reverse(LEFT(reverse(@input), PATINDEX('%[0-9][^0-9]%', reverse(@input) ))) Numeric

结果:

【讨论】:

    猜你喜欢
    • 2016-09-15
    • 1970-01-01
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-14
    相关资源
    最近更新 更多