在SQL中将CHAR字符串转换为字母字符串中的第n个字母

时间:2015-07-27 08:44:28

标签: sql sql-server

我必须构建一个采用VARCHAR字符串(例如'AHT559')的进程,并通过根据字母表中的第n个字母将字母字符转换为INTEGERS将其转换为仅INT字符串。因此上述结果将导致:010820559。

之前我在SAS中做过这个,但我对SQL比较陌生。在SQL中执行此操作的最佳方法是什么?

以下是我在SAS所做的事情:

 $scope.isCheckboxChecked = function () {
      for(var i =0 ; i <$scope.tempData.length ; i++){
        if($scope.tempData[i].checked){
          return true;
        }
      }
    }

6 个答案:

答案 0 :(得分:4)

如果值的格式始终与您在注释中声明的相同,并且您只需要一次处理一个值,您可以执行一些简单的字符串操作,以使用{{3}将字符转换为整数},并减去64以获得字母字符的数字:

SELECT ASCII('A')      -- produces 65
SELECT ASCII('A') - 64 -- produces 1

这有点长篇大论,可以用更少的代码完成,但为了清晰起见,它是分开的。

DECLARE @val NVARCHAR(10) = 'AHT559'

-- get first, second and third character numeric values
DECLARE @first INT = ASCII(SUBSTRING(@val, 1, 1)) - 64
DECLARE @second INT = ASCII(SUBSTRING(@val, 2, 1)) - 64
DECLARE @third INT = ASCII(SUBSTRING(@val, 3, 1)) - 64

-- join them together adding a '0' if < 10
SELECT  RIGHT('0' + CAST(@first  AS VARCHAR(2)), 2)
      + RIGHT('0' + CAST(@second AS VARCHAR(2)), 2)
      + RIGHT('0' + CAST(@third  AS VARCHAR(2)), 2)
      + RIGHT(@val, 3)

测试了400万行:

-- temp table creation - takes approx 100 seconds on my machine
CREATE TABLE #temp (val NVARCHAR(6))

DECLARE  @rowno INT = 1
SELECT @rowno = 1
WHILE @rowno <= 4000000
BEGIN
    INSERT INTO #temp ( val ) VALUES  ( 'AHT559' )
    SELECT @rowno = @rowno + 1
END

对整个临时表运行此代码需要&lt;在我的机器上20秒:

SELECT val AS OrignalValue,
        RIGHT('0' + CAST( ASCII(SUBSTRING(val, 1, 1)) - 64  AS VARCHAR(2)), 2)
      + RIGHT('0' + CAST( ASCII(SUBSTRING(val, 2, 1)) - 64 AS VARCHAR(2)), 2)
      + RIGHT('0' + CAST( ASCII(SUBSTRING(val, 3, 1)) - 64  AS VARCHAR(2)), 2)
      + RIGHT(val, 3) AS FormattedValue
FROM #temp

答案 1 :(得分:2)

这是sqlserver的类似脚本,任何非大写字母的字符都假定为此语法中的数字:

DECLARE @x varchar(100) = 'AHT559'
DECLARE @p int = len(@x)

WHILE @p > 0
SELECT @x = 
  CASE WHEN substring(@x, @p, 1) between 'A' and 'Z' 
  THEN stuff(@x, @p, 1, right(ascii(substring(@x, @p, 1)) - 64 + 100, 2))
  ELSE @x END,
  @p -= 1

SELECT @x

结果:

010820559

答案 2 :(得分:1)

您可以使用类似下面的内容,可能作为标量函数来执行此转换。

DECLARE @i INT    
DECLARE @Item NVARCHAR(4000) = 'AHT1234'

DECLARE @ItemTable TABLE 
(
    Item NCHAR(1)
)

SET @i = 1

--Split the input string into separate characters, store in temp table
WHILE (@i <= LEN(@Item))
BEGIN
    INSERT INTO @ItemTable(Item) 
    VALUES(SUBSTRING(@Item, @i, 1))
    SET @i = @i + 1
END 


DECLARE @AlphaTable TABLE (
    Letter NCHAR(1),
    Position NVARCHAR(2)
)

-- Populate this with the whole alphabet obviously.  Could be a permanent rather than temp table.
INSERT INTO @AlphaTable
        ( Letter, Position )
VALUES  ( N'A', '01'),
          (N'H', '08'),
          (N'T', '20')  

DECLARE @Output NVARCHAR(50)

-- Convert the output and concatenate it back to a single output.
SELECT @Output = COALESCE(@output, '') + Converted
FROM (
    SELECT CASE WHEN ISNUMERIC(Item) = 1
        THEN CONVERT(NVARCHAR(1), Item)
        ELSE (SELECT Position FROM @AlphaTable WHERE Letter = CONVERT(NCHAR(1), Item))
        END AS Converted
    FROM @ItemTable
) AS T1

SELECT @Output

GO

答案 3 :(得分:1)

试试这个。

DECLARE @STR    VARCHAR(MAX)= 'AHT559',
        @SP     INT,
        @SP_STR VARCHAR(50),
        @OUTPUT VARCHAR(MAX)=''
DECLARE @TEMP_STR VARCHAR(50)

SET @TEMP_STR = @STR

WHILE Patindex('%[A-Z]%', @TEMP_STR) <> 0
  BEGIN
      SELECT @SP = Patindex('%[A-Z]%', @TEMP_STR)
      SELECT @SP_STR = Upper(LEFT(@TEMP_STR, @SP))
      SELECT @SP_STR = ( Ascii(@SP_STR) - 65 ) + 1
      SELECT @TEMP_STR = Stuff(@TEMP_STR, 1, @SP, '')
      SET @OUTPUT += RIGHT('0' + @SP_STR, 2)
  END

SELECT @OUTPUT + Substring(@STR, Patindex('%[0-9]%', @STR), Len(@STR)) 

答案 4 :(得分:1)

如何使用CTE创建前3个字母的每个组合并使用它来匹配:

SQL Fiddle

MS SQL Server 2008架构设置

class LoginForm(Form):
    username = TextField(gettext(u'Username'), validators=[validators.Required(message='Validation failed for username')])
    password = PasswordField('Password', validators=[validators.Required(message='Validation failed for password')])

查询1

CREATE TABLE Accounts
(
    Account VARCHAR(6)
)

INSERT INTO Accounts
VALUES ('AHT559'), ('BXC556'),
       ('CST345')

<强> Results

;WITH AlphaToNum
AS
(
    SELECT *
    FROM (VALUES
        ('A', '01'), ('B', '02'), ('C', '03'), ('D', '04'),
        ('E', '05'), ('F', '06'), ('G', '07'), ('H', '08'),
        ('I', '09'), ('J', '10'), ('K', '11'), ('L', '12'),
        ('M', '13'), ('N', '14'), ('O', '15'), ('P', '16'),
        ('Q', '17'), ('R', '18'), ('S', '19'), ('T', '20'),
        ('U', '21'), ('V', '22'), ('W', '23'), ('X', '24'),
        ('Y', '25'), ('Z', '26')
        ) X(alpha, num)
),
MappingTable
As
(
    SELECT  A1.alpha + A2.alpha + A3.alpha as match, A1.num + A2.num + A3.num as val
    FROM AlphaToNum A1
    CROSS APPLY AlphaToNum A2
    CROSS APPLY AlphaToNum A3
)
SELECT A.Account, M.val + SUBSTRING(A.Account,4, 3) As ConvertedAccount
FROM MappingTable M
INNER JOIN Accounts A
    ON LEFT(A.Account,3) = M.match

答案 5 :(得分:-1)

这可能是使用CLR UDF最好的方法,但对于这种格式,完整答案太长了。

基本上你需要创建一个UDF(用户定义的函数),它接受一个字符串(nvarchar ...)作为输入并返回一个字符串作为输出。你可以很容易地用C#做到这一点,你需要用CLR集成要求来包装它。

您可以查看here了解相关信息。

代码可能类似于:

def round_up_to_odd(f):
    f = int(np.ceil(f))
    return f + 1 if f % 2 == 0 else f