web-dev-qa-db-ja.com

値を1つのフィールドから2つに分割する

ユーザーの姓と名の両方を含むテーブルフィールドmembernameがあります。それらを2つのフィールドmemberfirstmemberlastに分割することはできますか?

すべてのレコードの形式は「名姓」です(引用符とスペースは不要です)。

112
tsiger

残念ながら、MySQLは分割文字列関数を備えていません。ただし、次の記事で説明するように、このために ユーザー定義関数 を作成できます。

その機能で:

DELIMITER $$

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255) DETERMINISTIC
BEGIN 
    RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');
END$$

DELIMITER ;

次のようにクエリを作成できます。

SELECT SPLIT_STR(membername, ' ', 1) as memberfirst,
       SPLIT_STR(membername, ' ', 2) as memberlast
FROM   users;

ユーザー定義関数を使用せず、クエリをもう少し冗長にしたい場合は、次のこともできます。

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(membername, ' ', 1), ' ', -1) as memberfirst,
       SUBSTRING_INDEX(SUBSTRING_INDEX(membername, ' ', 2), ' ', -1) as memberlast
FROM   users;
208
Daniel Vassallo

SELECTバリアント(ユーザー定義関数を作成しない):

SELECT IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, 1, LOCATE(' ', `membername`) - 1),
        `membername`
    ) AS memberfirst,
    IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, LOCATE(' ', `membername`) + 1),
        NULL
    ) AS memberlast
FROM `user`;

このアプローチでは次のことも行います。

  • membername スペースのない値:文字列全体をmemberfirstに追加し、memberlastをNULLに設定します。
  • membername 複数のスペースがある値:最初のスペースの前のすべてをmemberfirstに追加し、残り(追加のスペースを含む)をmemberlastに追加します。

更新バージョンは次のようになります。

UPDATE `user` SET
    `memberfirst` = IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, 1, LOCATE(' ', `membername`) - 1),
        `membername`
    ),
    `memberlast` = IF(
        LOCATE(' ', `membername`) > 0,
        SUBSTRING(`membername`, LOCATE(' ', `membername`) + 1),
        NULL
    );
63
smhg

クエリの一部としてこれを行う計画がある場合は、do n't それを行う (a)。真剣に、それはパフォーマンスキラーです。パフォーマンスを気にしない場合もあります(将来的にパフォーマンスを向上させるためにフィールドを分割する1回限りの移行ジョブなど)が、ミッキーマウスデータベース以外で定期的にこれを行う場合は、 「リソースを無駄にしています。

ever何らかの方法で列の一部のみを処理する必要がある場合、DB設計に欠陥があります。自宅のアドレス帳やレシピアプリケーション、または他の無数の小さなデータベースでも問題なく動作する可能性がありますが、「実際の」システムに拡張することはできません。

名前のコンポーネントを別々の列に保存します。文字検索で列を分割するよりも、列を単純な連結(完全な名前が必要な場合)で結合する方がほとんど常に高速です。

何らかの理由でフィールドを分割できない場合は、少なくとも追加の列を挿入し、挿入/更新トリガーを使用してそれらを設定します。 3NFではありませんが、これによりデータの一貫性が保証され、クエリが大幅に高速化されます。大文字と小文字の問題をいじる必要がないように、余分な列を同時に小文字にする(および検索する場合はインデックスを付ける)こともできます。

また、列とトリガーを追加することさえできない場合は、スケーラブルではないことに注意してください(クライアント用の場合はクライアントに認識させてください)。


(a) もちろん、このクエリを使用してスキーマをfixにしたい場合は、名前がtablequery、ではなく、私はそれが有効な使用であると考えます。しかし、繰り返しますが、クエリでそれを行うことは実際には良い考えではありません。

20
paxdiablo

既存の回答は複雑すぎるか、特定の質問に対する厳密な回答ではないようです。

簡単な答えは次のクエリだと思います:

SELECT
    SUBSTRING_INDEX(`membername`, ' ', 1) AS `memberfirst`,
    SUBSTRING_INDEX(`membername`, ' ', -1) AS `memberlast`
;

この特定の状況では、2ワード以上の名前を扱う必要はないと思います。適切に実行したい場合、場合によっては分割が非常に困難または不可能になることがあります。

  • エドガー・アランポー
  • ヨハン・ヴォルフガングフォン・ゲーテ
  • ヤコブ・ルートヴィッヒ・フェリックスメンデルスゾーン・バルトホルディ
  • リーメンデルスゾーン・バルトルディ
  • Petőfiサンドール
  • 黒澤

適切に設計されたデータベースでは、人間の名前を部分的にも全体的にも保存する必要があります。もちろん、これは常に可能というわけではありません。

15
Dávid Horváth

これを使って

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', 2 ),' ',1) AS b, 
SUBSTRING_INDEX(SUBSTRING_INDEX( `membername` , ' ', -1 ),' ',2) AS c FROM `users` WHERE `userid`='1'
7
Karthik

質問に正確に答えているわけではありませんが、同じ問題に直面しています。

UPDATE people_exit SET last_name = SUBSTRING_INDEX(fullname,' ',-1)
UPDATE people_exit SET middle_name = TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(fullname,last_name,1),' ',-2))
UPDATE people_exit SET middle_name = '' WHERE CHAR_LENGTH(middle_name)>3 
UPDATE people_exit SET first_name = SUBSTRING_INDEX(fullname,concat(middle_name,' ',last_name),1)
UPDATE people_exit SET first_name = middle_name WHERE first_name = ''
UPDATE people_exit SET middle_name = '' WHERE first_name = middle_name
5
commonpike

このような関数が必要な唯一のケースは、FirstnameとLastnameを別々のフィールドに格納するようにテーブルを変更するUPDATEクエリです。

データベース設計は特定のルールに従う必要があり、 データベースの正規化 は最も重要なルールの1つです

3

MySQLでは、これはこのオプションで機能しています。

SELECT Substring(nameandsurname, 1, Locate(' ', nameandsurname) - 1) AS 
       firstname, 
       Substring(nameandsurname, Locate(' ', nameandsurname) + 1)    AS lastname 
FROM   emp  
3
Irakli Kardava

姓と名の両方が1つの列にある列がありました。姓と名はコンマで区切られています。以下のコードは機能しました。エラーのチェック/修正はありません。ただの愚かな分割。 phpMyAdminを使用してSQLステートメントを実行しました。

UPDATE tblAuthorList SET AuthorFirst = SUBSTRING_INDEX(AuthorLast,',',-1) , AuthorLast = SUBSTRING_INDEX(AuthorLast,',',1);

13.2.10 UPDATE構文

1
Steve R.

これはここからsmhgを取得し、 MySQLの指定された部分文字列の最後のインデックス からそれらを結合します。これはmysqlの場合です。必要なのは、名字がfirst_name last_nameになり、姓が単一のWord、名前がその単一のWordの前のすべて、名前がnull、1単語、2単語、または2単語以上。すなわち:ヌル;メアリー;メアリー・スミス;メアリーA.スミス;メアリー・スー・エレン・スミス;

したがって、nameが1ワードまたはnullの場合、last_nameはnullです。名前が> 1ワードの場合、last_nameは最後のワードであり、first_nameは最後のワードの前のすべてのワードです。

Joe Smith Jr.のようなものはすでに削除していることに注意してください。ジョー・スミス・エスクといった具合に、手作業はもちろん苦痛でしたが、それを行うには十分に小さかったので、使用する方法を決定する前に、名前フィールドのデータを実際に確認してください。

これにより結果もトリミングされるため、名前の前後にスペースが入らないことに注意してください。

私はここで自分のやり方をグーグルで探しているかもしれない他の人のためにこれを投稿しています。これは、もちろん、最初にselectでテストします。

これは一度きりのことなので、効率については気にしません。

SELECT TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        LEFT(`name`, LENGTH(`name`) - LOCATE(' ', REVERSE(`name`))),
        `name`
    ) 
) AS first_name,
TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        SUBSTRING_INDEX(`name`, ' ', -1) ,
        NULL
    ) 
) AS last_name
FROM `users`;


UPDATE `users` SET
`first_name` = TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        LEFT(`name`, LENGTH(`name`) - LOCATE(' ', REVERSE(`name`))),
        `name`
    ) 
),
`last_name` = TRIM( 
    IF(
        LOCATE(' ', `name`) > 0,
        SUBSTRING_INDEX(`name`, ' ', -1) ,
        NULL
    ) 
);
1
Lizardx

データがすべてfirst_nameフィールドに到着したときに、first_nameをfirst_nameとlast_nameに分割する方法。これにより、姓フィールドに最後の単語のみが入力されるため、「john phillips sousa」は「john phillips」名、「sousa」名になります。また、すでに修正されたレコードを上書きすることも避けます。

set last_name=trim(SUBSTRING_INDEX(first_name, ' ', -1)), first_name=trim(SUBSTRING(first_name,1,length(first_name) - length(SUBSTRING_INDEX(first_name, ' ', -1)))) where list_id='$List_ID' and length(first_name)>0 and length(trim(last_name))=0
0
TheSatinKnight
UPDATE `salary_generation_tbl` SET
    `modified_by` = IF(
        LOCATE('$', `other_salary_string`) > 0,
        SUBSTRING(`other_salary_string`, 1, LOCATE('$', `other_salary_string`) - 1),
        `other_salary_string`
    ),
    `other_salary` = IF(
        LOCATE('$', `other_salary_string`) > 0,
        SUBSTRING(`other_salary_string`, LOCATE('$', `other_salary_string`) + 1),
        NULL
    );
0
Aniket