获取字符之间所有数字的脚本
Script to get all numbers between Characters
我需要找到一种方法来获取破折号之间的数字。这是我知道的唯一方法,但我知道并非我们所有的帐户长度都相同。所以我只是在寻找一种方法来获取破折号之前、之后和之间的所有内容。这是我们拥有的帐户类型的示例。 '2-0-200-325-0' 和 '1-0-1105-1500-1520' non-digit 字符只是破折号,没有别的。
declare @Department Int
declare @Account Int
declare @Company Int
declare @Location Int
declare @SubAccount Int
declare @AccountNo varchar(24) = '2-0-200-325-0'
declare @CommaPos Int
select @CommaPos = charindex('-',@accountno)
set @Company = substring(@accountno,1,@CommaPos-1)
select @Company as Company
set @Location = Substring(@AccountNo, @CommaPos+1, 1)
select @Location as Location
set @Department = Substring(@AccountNo, @CommaPos+3, 4)
select @Department as Department
set @Account = Substring(@AccountNo, @CommaPos+8, 4)
select @Account as Account
set @SubAccount = Substring(@AccountNo, @CommaPos+13, 4)
select @SubAccount as SubAccount
一个选项使用递归查询进行解析。这可以正确处理每个部分的可变长度 - 如果需要,可以轻松扩展以处理更多部分。
-- declare the variables
declare @AccountNo varchar(24) = '2-0-200-325-0';
declare @Department Int;
declare @Account Int;
declare @Company Int;
declare @Location Int;
declare @SubAccount Int;
-- parse and assign values to variables
with cte as (
select
substring(@AccountNo + '-', 1, charindex('-', @AccountNo + '-') - 1) val,
substring(@AccountNo + '-', charindex('-', @AccountNo + '-') + 1, len(@AccountNo)) rest,
1 lvl
union all
select
substring(rest, 1, charindex('-', rest) - 1),
substring(rest, charindex('-', rest) + 1, len(rest)),
lvl + 1
from cte
where charindex('-', rest) > 0
)
select
@Company = max(case when lvl = 1 then val end),
@Location = max(case when lvl = 2 then val end),
@Department = max(case when lvl = 3 then val end),
@Account = max(case when lvl = 4 then val end),
@SubAccount = max(case when lvl = 5 then val end)
from cte;
-- check the results
select
@AccountNo AccountNo,
@Company Company,
@Location Location,
@Department Department,
@Account Account,
@SubAccount SubAccount
;
AccountNo | Company | Location | Department | Account | SubAccount
:------------ | ------: | -------: | ---------: | ------: | ---------:
2-0-200-325-0 | 2 | 0 | 200 | 325 | 0
这是我的方法:
--首先我使用声明的 table 变量来模拟您的问题:
DECLARE @tbl TABLE(ID INT IDENTITY,ACCOUNT_NO VARCHAR(24))
INSERT INTO @tbl VALUES('2-0-200-325-0');
--查询
SELECT t.ID
,t.ACCOUNT_NO
,casted.value('x[1]','int') AS Company
,casted.value('x[2]','int') AS Location
,casted.value('x[3]','int') AS Department
,casted.value('x[4]','int') AS Account
,casted.value('x[5]','int') AS SubAccount
FROM @tbl t
CROSS APPLY(VALUES(CAST('<x>' + REPLACE(t.ACCOUNT_NO,'-','</x><x>') + '</x>' AS XML))) A(casted);
简而言之:
- 我们使用简单的字符串操作将您以破折号分隔的数字列表转换为 XML。
- 现在我们可以使用 XQuery 按位置检索每个元素(类型安全!)。
找到details here。在此 link 中,还有一种使用 JSON 支持(需要 v2016+)的更快方法:
SELECT t.ID
,t.ACCOUNT_NO
,A.*
FROM @tbl t
CROSS APPLY OPENJSON(CONCAT('[[',REPLACE(t.ACCOUNT_NO,'-',','),']]'))
WITH(Company INT '$[0]'
,Location INT '$[1]'
,Department INT '$[2]'
,Account INT '$[3]'
,SubAccount INT '$[4]') A;
这种JSON方法的想法:
- 我们再次使用一些简单的字符串操作将您的字符串转换为 JSON 数组。
- 使用两个数组括号 (
[[
) 允许使用带有 WITH
子句的 OPENJSON()
。
WITH
子句允许通过其(从零开始的)位置(类型安全)抓取每个片段。
WITH
子句是某种 隐式旋转 。
/*
-- First Create this function. This is what you need.
-- It will split a sentence into words, given a defined separator
CREATE FUNCTION [dbo].[udf_SplitString] (@Sentence varchar(max), @Separator char(1))
RETURNS @WordList TABLE (Word varchar(50))
AS
BEGIN
SET @Separator = ISNULL(@Separator, ' ')
DECLARE @Word varchar(50)
SET @Sentence = LTRIM(@Sentence) + @Separator
WHILE (CHARINDEX(@Separator, @Sentence) > 0)
BEGIN
SET @Word = SUBSTRING(@Sentence, 1, CHARINDEX(@Separator, @Sentence) - 1)
INSERT INTO @WordList SELECT LTRIM(@Word)
-- Remove word added to the List from the sentence.
SET @Sentence = SUBSTRING(@Sentence, CHARINDEX(@Separator, @Sentence) + 1, LEN(@Sentence))
SET @Sentence = LTRIM(@Sentence)
END
RETURN
END
GO
*/
DECLARE @AccountList TABLE (AccountNo varchar(20), Variable varchar(20))
INSERT INTO @AccountList VALUES
('1-0-1105-1200-1290','')
, ('1-0-1105-1500-1520','')
, ('1-0-1105-1500-1620','')
, ('1-0-1106-1200-1250','')
, ('1-0-1106-1200-1290','')
, ('1-0-1106-1500-1520','')
;
DECLARE @VariableList TABLE (OrderNo int, VariableName varchar(20))
INSERT INTO @VariableList VALUES
(1, 'Company ')
, (2, 'Location ')
, (3, 'Department ')
, (4, 'Account ')
, (5, 'SubAccount ')
;
SELECT
AccountNo
, Variable = (SELECT VariableName FROM @VariableList WHERE RowNo = OrderNo)
, Value = Word
FROM (
SELECT
RowNo = ROW_NUMBER() OVER(PARTITION BY AccountNo ORDER BY AccountNo)
, AccountNo = L.AccountNo
, Variable = ''
, Word = W.Word
FROM @AccountList L
CROSS APPLY dbo.udf_SplitString(L.AccountNo, '-') W -- Here how to use the function
) R
我需要找到一种方法来获取破折号之间的数字。这是我知道的唯一方法,但我知道并非我们所有的帐户长度都相同。所以我只是在寻找一种方法来获取破折号之前、之后和之间的所有内容。这是我们拥有的帐户类型的示例。 '2-0-200-325-0' 和 '1-0-1105-1500-1520' non-digit 字符只是破折号,没有别的。
declare @Department Int
declare @Account Int
declare @Company Int
declare @Location Int
declare @SubAccount Int
declare @AccountNo varchar(24) = '2-0-200-325-0'
declare @CommaPos Int
select @CommaPos = charindex('-',@accountno)
set @Company = substring(@accountno,1,@CommaPos-1)
select @Company as Company
set @Location = Substring(@AccountNo, @CommaPos+1, 1)
select @Location as Location
set @Department = Substring(@AccountNo, @CommaPos+3, 4)
select @Department as Department
set @Account = Substring(@AccountNo, @CommaPos+8, 4)
select @Account as Account
set @SubAccount = Substring(@AccountNo, @CommaPos+13, 4)
select @SubAccount as SubAccount
一个选项使用递归查询进行解析。这可以正确处理每个部分的可变长度 - 如果需要,可以轻松扩展以处理更多部分。
-- declare the variables
declare @AccountNo varchar(24) = '2-0-200-325-0';
declare @Department Int;
declare @Account Int;
declare @Company Int;
declare @Location Int;
declare @SubAccount Int;
-- parse and assign values to variables
with cte as (
select
substring(@AccountNo + '-', 1, charindex('-', @AccountNo + '-') - 1) val,
substring(@AccountNo + '-', charindex('-', @AccountNo + '-') + 1, len(@AccountNo)) rest,
1 lvl
union all
select
substring(rest, 1, charindex('-', rest) - 1),
substring(rest, charindex('-', rest) + 1, len(rest)),
lvl + 1
from cte
where charindex('-', rest) > 0
)
select
@Company = max(case when lvl = 1 then val end),
@Location = max(case when lvl = 2 then val end),
@Department = max(case when lvl = 3 then val end),
@Account = max(case when lvl = 4 then val end),
@SubAccount = max(case when lvl = 5 then val end)
from cte;
-- check the results
select
@AccountNo AccountNo,
@Company Company,
@Location Location,
@Department Department,
@Account Account,
@SubAccount SubAccount
;
AccountNo | Company | Location | Department | Account | SubAccount :------------ | ------: | -------: | ---------: | ------: | ---------: 2-0-200-325-0 | 2 | 0 | 200 | 325 | 0
这是我的方法:
--首先我使用声明的 table 变量来模拟您的问题:
DECLARE @tbl TABLE(ID INT IDENTITY,ACCOUNT_NO VARCHAR(24))
INSERT INTO @tbl VALUES('2-0-200-325-0');
--查询
SELECT t.ID
,t.ACCOUNT_NO
,casted.value('x[1]','int') AS Company
,casted.value('x[2]','int') AS Location
,casted.value('x[3]','int') AS Department
,casted.value('x[4]','int') AS Account
,casted.value('x[5]','int') AS SubAccount
FROM @tbl t
CROSS APPLY(VALUES(CAST('<x>' + REPLACE(t.ACCOUNT_NO,'-','</x><x>') + '</x>' AS XML))) A(casted);
简而言之:
- 我们使用简单的字符串操作将您以破折号分隔的数字列表转换为 XML。
- 现在我们可以使用 XQuery 按位置检索每个元素(类型安全!)。
找到details here。在此 link 中,还有一种使用 JSON 支持(需要 v2016+)的更快方法:
SELECT t.ID
,t.ACCOUNT_NO
,A.*
FROM @tbl t
CROSS APPLY OPENJSON(CONCAT('[[',REPLACE(t.ACCOUNT_NO,'-',','),']]'))
WITH(Company INT '$[0]'
,Location INT '$[1]'
,Department INT '$[2]'
,Account INT '$[3]'
,SubAccount INT '$[4]') A;
这种JSON方法的想法:
- 我们再次使用一些简单的字符串操作将您的字符串转换为 JSON 数组。
- 使用两个数组括号 (
[[
) 允许使用带有WITH
子句的OPENJSON()
。 WITH
子句允许通过其(从零开始的)位置(类型安全)抓取每个片段。WITH
子句是某种 隐式旋转 。
/*
-- First Create this function. This is what you need.
-- It will split a sentence into words, given a defined separator
CREATE FUNCTION [dbo].[udf_SplitString] (@Sentence varchar(max), @Separator char(1))
RETURNS @WordList TABLE (Word varchar(50))
AS
BEGIN
SET @Separator = ISNULL(@Separator, ' ')
DECLARE @Word varchar(50)
SET @Sentence = LTRIM(@Sentence) + @Separator
WHILE (CHARINDEX(@Separator, @Sentence) > 0)
BEGIN
SET @Word = SUBSTRING(@Sentence, 1, CHARINDEX(@Separator, @Sentence) - 1)
INSERT INTO @WordList SELECT LTRIM(@Word)
-- Remove word added to the List from the sentence.
SET @Sentence = SUBSTRING(@Sentence, CHARINDEX(@Separator, @Sentence) + 1, LEN(@Sentence))
SET @Sentence = LTRIM(@Sentence)
END
RETURN
END
GO
*/
DECLARE @AccountList TABLE (AccountNo varchar(20), Variable varchar(20))
INSERT INTO @AccountList VALUES
('1-0-1105-1200-1290','')
, ('1-0-1105-1500-1520','')
, ('1-0-1105-1500-1620','')
, ('1-0-1106-1200-1250','')
, ('1-0-1106-1200-1290','')
, ('1-0-1106-1500-1520','')
;
DECLARE @VariableList TABLE (OrderNo int, VariableName varchar(20))
INSERT INTO @VariableList VALUES
(1, 'Company ')
, (2, 'Location ')
, (3, 'Department ')
, (4, 'Account ')
, (5, 'SubAccount ')
;
SELECT
AccountNo
, Variable = (SELECT VariableName FROM @VariableList WHERE RowNo = OrderNo)
, Value = Word
FROM (
SELECT
RowNo = ROW_NUMBER() OVER(PARTITION BY AccountNo ORDER BY AccountNo)
, AccountNo = L.AccountNo
, Variable = ''
, Word = W.Word
FROM @AccountList L
CROSS APPLY dbo.udf_SplitString(L.AccountNo, '-') W -- Here how to use the function
) R