SQL:メールドメイン名による並べ替え
-
06-07-2019 - |
質問
ドメイン名フラグメントで電子メールアドレスの列を持つテーブルをソートするための最短および/または効率的なSQLステートメントは何ですか?
これは、本質的に" @"の前にあるものはすべて無視します。メールアドレスで大文字と小文字を区別しません。このドメインの国際化されたドメイン名を無視しましょう。
ターゲット:mySQL、MSSQL、Oracle
TABLE1
id name email ------------------------------------------ 1 John Doe johndoe@domain.com 2 Jane Doe janedoe@helloworld.com 3 Ali Baba ali@babaland.com 4 Foo Bar foo@worldof.bar.net 5 Tarrack Ocama me@am-no-president.org
メールで注文
SELECT * FROM TABLE1 ORDER BY EMAIL ASC
id name email ------------------------------------------ 3 Ali Baba ali@babaland.com 4 Foo Bar foo@worldof.bar.net 2 Jane Doe janedoe@helloworld.com 1 John Doe johndoe@domain.com 5 Tarrack Ocama me@am-no-president.org
ドメインによる注文
SELECT * FROM TABLE1 ORDER BY ?????? ASC
id name email ------------------------------------------ 5 Tarrack Ocama me@am-no-president.org 3 Ali Baba ali@babaland.com 1 John Doe johndoe@domain.com 2 Jane Doe janedoe@helloworld.com 4 Foo Bar foo@worldof.bar.net
編集:
3つ以上のすべてのSQLエンジンで機能する単一のSQLステートメントを要求していません。どんな貢献も歓迎します。 :)
解決
これを試してください
クエリ(SQL Serverの場合):
select * from mytbl
order by SUBSTRING(email,(CHARINDEX('@',email)+1),1)
クエリ(Oracleの場合):
select * from mytbl
order by substr(email,INSTR(email,'@',1) + 1,1)
クエリ(MySQL用)
pygorex1 already answered
出力:
id name email
5 Tarrack Ocama me@am-no-president.org
3 Ali Baba ali@babaland.com
1 John Doe johndoe@domain.com
2 Jane Doe janedoe@helloworld.com
4 Foo Bar foo@worldof.bar.net
他のヒント
MySQLの場合:
select email, SUBSTRING_INDEX(email,'@',-1) AS domain from user order by domain desc;
大文字と小文字を区別しない場合:
select user_id, username, email, LOWER(SUBSTRING_INDEX(email,'@',-1)) AS domain from user order by domain desc;
このソリューションを拡張したい場合は、サブ列を抽出しようとしないでください 。テーブルが大きくなるにつれて、行ごとの関数が遅くなることで有名です。
この場合に行うべき正しいことは、抽出のコストを select
(多くの場合)から insert / update に変更することですcode>発生頻度の少ない場所(ほとんどの通常のデータベース)。
insert
および update
でのみコストが発生することにより、データベースの全体的な効率が大幅に向上します。それを行う必要があります(つまり、データが変更されるのはそれだけです)。
これを実現するには、メールアドレスをテーブル内の2つの異なる列、 email_user
と email_domain
に分割します)。その後、挿入/更新の前にアプリケーションで分割するか、データベースでトリガー(またはDBMSでサポートされている場合は事前に計算された列)を使用して自動的に実行します。
次に email_domain
でソートし、完全なメールアドレスが必要な場合は、 email_name | '@' | email_domain
を使用します。
または、 email
列全体を保持し、トリガーを使用して email_domain
のドメイン部分のみを複製することができます。列を連結することを心配する必要はありません。完全なメールアドレスを取得します。
何をしているのかわかっていれば、パフォーマンス上の理由から3NFから復帰することは完全に許容できます。この場合、2つの列のデータは、トリガーで許可されていないという理由だけで同期を取ることができません。これは、パフォーマンスのためにディスクスペース(比較的安価)を交換するのに適した方法です(常により多くの機能が必要です )。
そして、もしあなたが3NFからの復帰を嫌うような場合は、 email_name / email_domain
ソリューションがそれを修正します。
これは、 a @ b
の形式の電子メールアドレスのみを処理することを前提としています。有効な電子メールアドレスは他にもありますが、何年にもわたってそれらを目にしたことはありません。
SQL Serverの場合、計算列をテーブルに追加して、ドメインを別のフィールドに抽出できます。その列をテーブルに保持する場合、他のフィールドと同じように使用でき、さらにドメイン名でクエリを実行すると、速度を上げるためにインデックスを付けることができます。
ALTER TABLE Table1
ADD DomainName AS
SUBSTRING(email, CHARINDEX('@', email)+1, 500) PERSISTED
したがって、テーブルに追加の列" DomainName"が追加されます。 " @"の後のものが含まれます。メールアドレスにサインインしてください。
MySQL、Oracle、MSSQLに対応する必要がある場合、最も効率的な方法は、アカウント名とドメイン名を2つの別々のフィールドに保存することです。注文を行うことができます:
select id,name,email from table order by name
select id,name,email,account,domain from table order by email
select id,name,email,account,domain from table order by domain,account
ドニーが指摘するように、文字列操作関数は標準ではありません..そのため、データを冗長に保つ必要があります!
アカウントとドメインを3番目のクエリに追加しました。すべてのDBMSが選択したフィールドにないフィールドでクエリをソートするわけではないことを思い出してください。
postgresのクエリは次のとおりです。
SELECT * FROM table
ORDER BY SUBSTRING(email,(position('@' in email) + 1),252)
値 252
は、許可される最長のドメインです(電子メールの最大長は、ローカル部分 @
を含めて 254
であるため、およびドメイン。
詳細については、こちらをご覧ください:有効なメールアドレスの最大長?
ドメインを解析するには、テキスト操作関数を使用する必要があります。次に、新しい列で注文します。
MySQL、 right()のインテリジェントな組み合わせおよび instr()
SQL Server、 right()および patindex()
そして、他の誰かが言ったように、レコード数がまともな場合、where句の関数で電子メールフィールドをラップすると、RDBMSはその列にあるインデックスを使用できなくなります。そのため、ドメインを保持する計算列の作成を検討することをお勧めします。
100万件のレコードがある場合は、ドメイン名のみで新しい列を作成することをお勧めします。
これはOracleで動作します:
select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
私の提案は次のとおりです(mysqlの場合):
SELECT
LOWER(email) AS email,
SUBSTRING_INDEX(email, '@', + 1) AS account,
REPLACE(SUBSTRING_INDEX(email, '@', -1), CONCAT('.',SUBSTRING_INDEX(email, '.', -1)),'') -- 2nd part of mail - tld.
AS domain,
CONCAT('.',SUBSTRING_INDEX(email, '.', -1)) AS tld
FROM
********
ORDER BY domain, email ASC;
を追加するだけです
SQL Serverの元の答えはうまくいきませんでした。...
これはSQL Serverのバージョンです...
select SUBSTRING(email,(CHARINDEX('@',email)+1),len(email)), count(*)
from table_name
group by SUBSTRING(email,(CHARINDEX('@',email)+1),len(email))
order by count(*) desc
難しくなく賢く働く:
SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails