使用Upper来大写城市名称的第一个字母

时间:2016-12-05 17:43:34

标签: sql tsql

我正在进行一些数据清理,需要将城市名称的第一个字母大写。如何利用像Terra Bella这样的城市中的第二个单词。

  SELECT UPPER(LEFT([MAIL CITY],1))+
  LOWER(SUBSTRING([MAIL CITY],2,LEN([MAILCITY]))) 
  FROM masterfeelisting

我的结果是'Terra bella',我需要'Terra Bella'。提前谢谢。

4 个答案:

答案 0 :(得分:0)

这是使用APPLY处理此问题的一种方法。请注意,此解决方案最多支持3个子字符串(例如“Phoenix”,“New York”,“New York City”),但可以轻松更新以处理更多内容。

DECLARE @string varchar(100) = 'nEW yoRk ciTY';

WITH DELIMCOUNT(String, DC) AS 
(
  SELECT @string, LEN(RTRIM(LTRIM(@string)))-LEN(REPLACE(RTRIM(LTRIM(@string)),' ',''))
),
CIPOS AS
(
  SELECT  *
  FROM DELIMCOUNT
  CROSS APPLY (SELECT CHARINDEX(char(32), string,         1)) CI1(CI1)
  CROSS APPLY (SELECT CHARINDEX(char(32), string, CI1.CI1+1)) CI2(CI2)
)
SELECT 
  OldString = @string, 
  NewString = 
  CASE DC
  WHEN 0 THEN UPPER(SUBSTRING(string,1,1))+LOWER(SUBSTRING(string,2,8000))

  WHEN 1 THEN UPPER(SUBSTRING(string,1,1))+LOWER(SUBSTRING(string,2,CI1-1)) + 
              UPPER(SUBSTRING(string,CI1+1,1))+LOWER(SUBSTRING(string,CI1+2,100))

  WHEN 2 THEN UPPER(SUBSTRING(string,1,1))+LOWER(SUBSTRING(string,2,CI1-1)) + 
              UPPER(SUBSTRING(string,CI1+1,1))+LOWER(SUBSTRING(string,CI1+2,CI2-(CI1+1))) +
              UPPER(SUBSTRING(string,CI2+1,1))+LOWER(SUBSTRING(string,CI2+2,100))
  END
FROM CIPOS;

结果:

OldString       NewString     
--------------- --------------
nEW yoRk ciTY   New York City 

答案 1 :(得分:0)

这只会大写第二个单词的第一个字母。一种较短但不太灵活的方法。将@str替换为[Mail City]。

DECLARE @str AS VARCHAR(50) = 'Los angelas'

SELECT STUFF(@str, CHARINDEX(' ', @str) + 1, 1, UPPER(SUBSTRING(@str, CHARINDEX(' ', @str) + 1, 1)));

答案 2 :(得分:0)

这是一种为三个城市名称部分使用嵌入式选择的方法。 它使用CHARINDEX查找分隔符的位置。 (即空格)

我在Select周围放了一个'if'结构来测试你是否有超过3个城市名称的记录。如果您收到警告消息,则可以添加另一个子选择以处理另一个城市部分。

虽然......只是要清楚...... SQL不是进行复杂格式化的最佳语言。它被编写为数据检索引擎,其理念是另一个程序将获取该数据并将其按摩成更友好的外观。在另一个程序中处理格式可能更容易。但是如果你坚持使用SQL并且你需要考虑5个或更多部分的城市名称...你可能想要考虑使用游标,这样你就可以循环变量的可能性。 (但游标并不是一个很好的习惯。除非你已经用尽所有其他选择,否则不要这样做。)

无论如何,以下代码创建并填充表,以便您可以测试代码并查看其工作原理。享受!

CREATE TABLE 
   #masterfeelisting (
      [MAILCITY] varchar(30) not null
      );

Insert into #masterfeelisting select 'terra bella';
Insert into #masterfeelisting select ' terrA novA ';
Insert into #masterfeelisting select 'chicagO ';
Insert into #masterfeelisting select 'bostoN';
Insert into #masterfeelisting select 'porT dE sanTo';
--Insert into #masterfeelisting select ' porT dE sanTo pallo ';

Declare @intSpaceCount as integer;

SELECT @intSpaceCount =  max (len(RTRIM(LTRIM([MAILCITY]))) - len(replace([MAILCITY],' ',''))) FROM #masterfeelisting;

if @intSpaceCount > 2 
   SELECT 'You need to account for more than 3 city name parts ' as Warning, @intSpaceCount as SpacesFound;

else

   SELECT 
      cThird.[MAILCITY1] + cThird.[MAILCITY2] + cThird.[MAILCITY3] as [MAILCITY]
   FROM 
      (SELECT 
         bSecond.[MAILCITY1] as [MAILCITY1]
         ,SUBSTRING(bSecond.[MAILCITY2],1,bSecond.[intCol2]) as [MAILCITY2]
         ,UPPER(SUBSTRING(bSecond.[MAILCITY2],bSecond.[intCol2] + 1, 1)) +
            SUBSTRING(bSecond.[MAILCITY2],bSecond.[intCol2] + 2,LEN(bSecond.[MAILCITY2]) - bSecond.[intCol2]) as [MAILCITY3]
      FROM 
         (SELECT 
            SUBSTRING(aFirst.[MAILCITY],1,aFirst.[intCol1]) as [MAILCITY1]
            ,UPPER(SUBSTRING(aFirst.[MAILCITY],aFirst.[intCol1] + 1, 1)) +
               SUBSTRING(aFirst.[MAILCITY],aFirst.[intCol1] + 2,LEN(aFirst.[MAILCITY]) - aFirst.[intCol1]) as [MAILCITY2]
            ,CHARINDEX ( ' ', SUBSTRING(aFirst.[MAILCITY],aFirst.[intCol1] + 1, LEN(aFirst.[MAILCITY]) - aFirst.[intCol1]) ) as intCol2
         FROM 
            (SELECT 
               UPPER (LEFT(RTRIM(LTRIM(mstr.[MAILCITY])),1)) +
                  LOWER(SUBSTRING(RTRIM(LTRIM(mstr.[MAILCITY])),2,LEN(RTRIM(LTRIM(mstr.[MAILCITY])))-1)) as [MAILCITY]
              ,CHARINDEX ( ' ', RTRIM(LTRIM(mstr.[MAILCITY]))) as intCol1
            FROM 
               #masterfeelisting as mstr    -- Initial Master Table
            ) as aFirst     -- First Select Shell
         ) as bSecond   -- Second Select Shell
      ) as cThird;  -- Third Select Shell

Drop table #masterfeelisting;

答案 3 :(得分:0)

好的,我知道我之前已经回答了这个问题,但它让我觉得我们无法写出一些有效的东西来处理未知数量的文本片段。

因此,重新思考并研究,我发现了一种将[MAILCITY]字段更改为XML节点的方法,其中每个文本段都在其中。在xml字段中为其分配了自己的节点。然后可以逐个节点地处理这些xml字段,连接在一起,然后更改回SQL varchar。它很复杂,但它确实有效。 :)

以下是代码:

CREATE TABLE 
   #masterfeelisting (
      [MAILCITY] varchar(max) not null
      );

INSERT INTO #masterfeelisting VALUES 
   ('terra bellA')
   ,(' terrA novA ')
   ,('chicagO ')
   ,('bostoN')
   ,('porT dE sanTo')
   ,(' porT dE sanTo pallo ');

SELECT 
   RTRIM
   (
      (SELECT 
         UPPER([xmlField].[xmlNode].value('.', 'char(1)')) +
            LOWER(STUFF([xmlField].[xmlNode].value('.', 'varchar(max)'), 1, 1, '')) + ' '
      FROM [xmlNodeRecordSet].[nodeField].nodes('/N') as [xmlField]([xmlNode]) FOR 
         xml path(''), type
      ).value('.', 'varchar(max)')
   ) as [MAILCITY]
FROM 
  (SELECT
     CAST('<N>' + REPLACE([MAILCITY],' ','</N><N>')+'</N>' as xml) as [nodeField]
  FROM #masterfeelisting
  ) as [xmlNodeRecordSet];

Drop table #masterfeelisting; 

首先,我创建一个表并用虚拟值填充它。

现在这里是代码之美:

对于#masterfeelisting中的每条记录,我们将创建一个xml字段,其中包含每个&#39;文本段的节点&#39;。

即。 '<N></N><N>terrA</N><N>novA</N><N></N>'

(这是由varchar&#39; terrA novA&#39;构建的)

1)这样做的方法是使用REPLACE函数。

字符串以'<N>'开头,以指定节点的开头。然后:

REPLACE([MAILCITY],' ','</N><N>')

这有效地遍历整个[MAILCITY]字符串并替换每个字符串 ' ''</N><N>'

。{

然后字符串以'</N>'结尾。其中'</N>'指定每个节点的结束。

所以现在我们有一个漂亮的XML字符串,其中包含几个空节点和&#39;文本段&#39;很好地坐落在自己的节点中。所有的空间&#39;已被删除。

2)然后我们必须将字符串CAST到xml中。我们将该字段命名为[nodeField]。现在我们可以在新创建的记录集上使用xml函数。 (方便地命名为[xmlNodeRecordSet]。)

3)现在我们可以通过陈述来读取[xmlNodeRecordSet]到主子选择中:

FROM [xmlNodeRecordSet].[nodeField].nodes('/N')

这告诉我们正在将[nodeField]作为带有'/N'分隔符的节点进行读取。

然后通过声明:

来解析此节点字段表
as [xmlField]([xmlNode]) FOR xml path(''), type

这意味着将为xml字符串中的每个[xmlNode]解析每个[xmlField]。

4)所以在主要的子选择中:

每个空白节点'<N></N>'都将被丢弃。 (或未处理。)

每个节点都带有&#39;文本段&#39;在它将被解析。即<N>terrA</N>

UPPER([xmlField].[xmlNode].value('.', 'char(1)')) +

此代码将从字段中抓取每个节点并获取其内容'.',并仅抓取第一个字符'char(1)'。然后它将大写该字符。 (最后的加号表示它会将此字母与下一段代码连接起来:

LOWER(STUFF([xmlField].[xmlNode].value('.', 'varchar(max)'), 1, 1, ''))

现在这里是美... STUFF是一个函数,它将从一个位置获取一个字符串,一个长度,并替换另一个字符串。

STUFF(字符串,起始位置,长度,替换字符串)

所以我们的字符串是:

[xmlField].[xmlNode].value('.', 'varchar(max)')

它抓取当前节点内的整个字符串,因为它是'varchar(max)'

起始位置为1.长度为1.并且替换字符串为''。这样就可以通过替换任何东西来有效地剥离第一个角色。所以剩下的字符串是我们想要小写的所有其他字符。这就是我们所做的......我们使用LOWER使它们全部为小写。这个结果连接到我们已经高调的第一封信。

但是等等......我们还没有完成......我们仍然需要追加+ ' '。在我们优秀的大写文本片段之后添加了一个空白区域&#39;。以防有另一个&#39;文本段&#39;完成此节点后。

这个主要的子Select现在将解析我们的[xmlField]中的每个节点,并将它们完美地连接在一起。

5)但是现在我们有一个很大的快乐连接,我们仍然需要将它从xml字段更改回SQL varchar字段。所以在主要子选择之后我们需要:

.value('.', 'varchar(max)')

这会将我们的[MAILCITY]更改回SQL varchar。

6)但坚持......我们仍然没有完成。请记住,我们在每个文本段的末尾添加了一个额外的空格&#39; ???那么最后的文本片段后面还有额外的空间。因此,我们需要使用RTRIM对该空间进行右边修剪。

7)并且不要忘记将最终字段重命名为as [MAILCITY]

8)那就是它。此代码将采用未知数量的文本段&#39;并格式化每一个。所有这些都使用了XML及其节点解析器的乐趣。

希望有所帮助:)