2016-12-05 8 views
1

私はいくつかのデータを整理しており、都市名の最初の文字を大文字にする必要があります。どのように私はテラベラのような都市で2番目の単語を大文字にするのですか?都市名の最初の文字を大文字にする

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

私の結果は「Terra Bella」で、「Terra Bella」が必要です。前もって感謝します。

+1

可能な重複・ホープ[SQL Serverの:適切なケース/タイトルケースにすべて大文字にします](http://stackoverflow.com/questions/230138/sql-server-make-all -upper-case-to-proper-case-title-case) – JNevill

+0

これは実際には重複ではありません。スレッドには、部分文字列の数に制限がない場合の解決策があります。この問題は、より効率的に解決することができます。 –

+0

(可能であれば)代わりに、アプリケーションコードでこのようなことを行うことを検討してください。 SQLは文字列の書式設定/処理ではあまり良くありません。 – Blorgbeard

答えて

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フィールドを作成しようとしています。

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

1)これが行われる方法(これは、VARCHAR 'TERRA NOVA' から構築される)は、REPLACE関数を使用することです。

文字列はノードの先頭を指定するために'<N>'で始まります。その後:

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

これは、効果的に全体[MAILCITY]文字列を通過し、'</N><N>'

で各 ' 'を置き換えた後、文字列が'</N>'で終わります。ここで、'</N>'は各ノードの終わりを示します。

これで、いくつかの空のノードを持つ美しいXML文字列と、「テキストセグメント」が自分のノードにうまく配置されました。すべての「スペース」が削除されました。

2)次に、文字列をxmlにキャストする必要があります。そしてそのフィールドに[nodeField]という名前をつけます。今度は、新しく作成したレコードセットでxml関数を使用できます。 (。便利な[xmlNodeRecordSet]という名前)

3)今、私たちはメイン、サブセレクト示すことによってに[xmlNodeRecordSet]を読むことができます:

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

これは、我々がノードとして[nodeField]を読んでいる私達に告げます'/N'の区切り文字を使用します。

as [xmlField]([xmlNode]) FOR xml path(''), type 

をこれは、それぞれ[xmlField】XML文字列内の各【にxmlNode]のために解析されることを意味する。

ノードフィールドのこのテーブルは、次に示すことによって解析されます。

4)だからで主副セレクト:

各ブランクノード'<N></N>'が破棄されます。 (または処理されません)

'テキストセグメント'が含まれている各ノードが解析されます。すなわち<N>terrA</N>

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

このコードは、フィールドの外に、各ノードを取得し、その内容'.'を取り、最初の文字だけ'char(1)'をつかむだろう。それは大文字の文字になります。 (末尾のプラス記号は、それがコードの次のビットでこの手紙を連結することを意味:

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

は今ここに美しさがある... STUFFがために、位置から、文字列を取る関数であります。長さ、および代替別の文字列

STUFF

だから、私たちの文字列です(文字列は、位置、長さ、置換文字列を開始):全体strinをつかむ

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

gは現在のノードの内部では'varchar(max)'なので、

開始位置は1です。長さは1です。置換文字列は''です。これは効果的に最初の文字を何も置き換えずに取り除きます。したがって残りの文字列はすべて小文字にしたい他の文字です。だからこそ、私たちは何をしているのですか?我々はそれらをすべて小文字にするためにLOWERを使用します。そして、この結果は、私たちがすでに大文字で書いていた最初の手紙と結びついています。

お待ちください...まだ完了していません...まだ+ ' 'を追加する必要があります。これは、大文字の 'テキストセグメント'の後​​に空白を追加します。このノードが完了した後にもう1つの「テキストセグメント」がある場合のみです。

このメインサブSelectは、[xmlField]内の各ノードを解析し、それらをすべてうまく連結します。

5)しかし、私たちは1つの大きなハッピーコンカチネーションがあるので、xmlフィールドからSQL varcharフィールドに戻す必要があります。したがって、メインのサブ選択の後には、

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

が必要です。これにより、[MAILCITY]がSQLのvarcharに戻されます。

6)しかし、ホールド...私たちはまだ行われていません。我々はそれぞれの 'テキストセグメント'の最後に余分なスペースを入れていることを覚えていますか?さて、最後のテキストセグメントにはまだ余分なスペースがあります。だから我々はRTRIMを使ってその空間を右にトリムする必要がある。

7)とバックas [MAILCITY]

8への最後のフィールドの名前を変更することを忘れてはいけない)そして、それはそれです。このコードは未知の量の「テキストセグメント」を取り、それらのそれぞれをフォーマットします。すべてXMLの楽しさを使用し、それはノードパーザーです。

役立ちます:)の

0

これは、APPLYを使用してこれを処理する方法の1つです。このソリューションでは、最大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 
0

は、これが唯一の2番目の単語の最初の文字を大文字にします。短くて柔軟性に欠けるアプローチ。 @strを[Mail City]に置き換えてください。

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

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

これは、3つの都市名の部分に埋込みセレクトを使用する方法です。 CHARINDEXを使用して区切り文字の位置を検索します。

市区町村の3つ以上のレコードを持っているかどうかをテストするために「if」構造体を配置します。警告メッセージが表示された場合は、もう1つのサブセレクトを追加して、別の都市部を処理することができます。

...明快に... 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; 
関連する問題