Postgresql

如何在 postgres 中僅儲存美國/加拿大電話號碼?

  • December 22, 2021

我只想在 Postgres TEXT 列中儲存美國和加拿大的電話號碼。我不想使用pg_libphonenumber.

為此,我應該使用什麼 CHECK 約束?

你需要在REGULAR EXPRESSION這裡掌握 s 。現在,PostgreSQL 在這個領域提供了一系列可能性,它遠遠超出了這裡的答案範圍來教授關於正則表達式的所有內容——它本身就是電腦科學的整個領域——恕我直言,是更好的教程網站之一。

首先要做的事情——電話號碼是一個字元串(PostgreSQL 方言中的 TEXT——其他人中的 VARCHAR())——一個不會加、減、乘或除電話號碼。此外,其中可能出現0-9 以外的字元(即()-.空格)。

正如@LaurenzAlbe 指出的那樣,清楚地了解實際需求是件好事。因此,您需要檢查您的字元串以確保它們對應於北美電話號碼(下面的所有程式碼都可以在此處的小提琴中找到)!

北美電話號碼的長度為 10 位,通常由空格分隔為三組,每組 3 位、3 位和 4 位。

因此,作為第一個近似值,您可以執行以下操作:

CREATE TABLE phnum_1
(
 num TEXT NOT NULL
 
 CONSTRAINT num_1_ck_1 
   CHECK (num ~ '^\d{3} \d{3} \d{4}$')

 CONSTRAINT num_1_ck_2
   CHECK (num ~ '^[0-9]{3} [0-9]{3} [0-9]{4}$')    

CONSTRAINT num_1_ck_3
   CHECK (num ~ '^[[:digit:]]{3} [[:digit:]]{3} [[:digit:]]{4}$')
);

請注意,所有這三個CONSTRAINTs 都做同樣的事情——只是表達方式不同。

這些是非常簡單的正則表達式(見下文),您只需確保每個條目num必須以 3 位數字開頭,後跟一個空格,後跟 4 位數字,另一個空格和 4 個最終數字。

正則表達式的解釋:

  • ^- 是一個"anchor"- 它指的是要檢查的字元串的開頭。
  • \d(或者$$ 0-9 $$或者$$ [:digit: $$]) 是數字字元的簡寫 - (即 0、1、2…、9)
  • {n}是一種說法n,並且只n出現前一件事 - 在這種情況下,是一個數字 - 例如,您可以說,{2,4}這意味著您的匹配出現 2 到 4 次。在上面,您可以根據需要使用冗餘的 {3,3}/{4,4} 嗎?
  • 然後是一個空格 - 文字空格字元 - 它在正則表達式中沒有特殊含義。
  • 然後\d{4} \d{4}- 4 位數字,一個空格,然後再增加 4 位數字。
  • 最後,另一個錨點——$作為字元串標記結尾的字元!

因此,正如您從小提琴中看到的那樣,按原樣'123 345 3434'接受987 654 3210,但'123-234-5678'被拒絕。

所以,這個正則表達式很簡單,但非常嚴格。現在,這個特殊要求的複雜程度可能很快就會變得平流層……

有左方括號和右方括號(())(國際程式碼),+或在國際程式碼之前沒有任何內容),本地交換程式碼是否有效,連字元(-)是否在數字組之間?真的,可能性幾乎是無限的……

我會敦促您在這裡查看,看看我們的姊妹網站 StackOverflow 上是如何處理一些/許多這些棘手問題的。

我已將其中一些正則表達式放入小提琴中,如下所示:

CREATE TABLE phnum_2 
(
 num TEXT NOT NULL
);

並用一些樣本潛在數字填充它:

INSERT INTO phnum_2 VALUES
('123-456-7890'),
('987 654 3210'),
('123-234-5678'),
('+1 123 456 7890'),
('+353 123 456 7890');

然後執行這個查詢:

SELECT 
 num ~ '\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$' AS re1,
 num ~ '^(\+\d{1,2}\s)?((\(\d{3}\))|(\d{3}))[\s.-]\d{3}[\s.-]\d{4}$' AS re2,
 num ~ '^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$' AS re3,
 num ~ '^(\+\d{1,2}\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$' AS re4,
 num ~ '^(\+1\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$' AS re5,
 num ~ '^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$' AS re6,
 num ~ '(\+\d{1,3}\s?)?((\(\d{3}\)\s?)|(\d{3})(\s|-?))(\d{3}(\s|-?))(\d{4})(\s?(([E|e]xt[:|.|]?)|x|X)(\s?\d+))?' AS re7
FROM 
 phnum_2;

結果:

re1     re2     re3     re4     re5     re6     re7
 t       t       t       t       t       t       t
 t       t       t       t       t       t       t
 t       t       t       t       t       t       t
 t       t       t       t       t       t       t
 t       f       t       f       f       t       t

我會敦促你看看那些失敗的,並試圖找出他們失敗的原因!

這裡有幾個不太複雜的,更複雜的執行緒可以在這裡找到這個站點提供了很多可能性,包括這個怪物

^(\+?1(-|\.|\s)?)?((\(((8(00|22|33|44|55|66|77|[8[0-9]))|900)\)|((8(00|22|33|44|55|66|77|[8[0-9]))|900))(-|\.|\s)?\d{3}(-|\.|\s)?\d{4}|(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))(-|\.|\s)?[2-9]([02-9]\d|1[02-9](-|\.|\s)?\d{4}))$

但是,我將把最後一句話留給這位指出

如果使用者想給你他們的電話號碼,那麼相信他們會做對。如果他們不想給你,那麼強迫他們輸入一個有效的數字會將他們發送到競爭對手的網站,或者讓他們輸入一個適合你的正則表達式的隨機字元串。我什至可能會想查找收費率占星熱線的號碼,然後輸入。

我還將以下任何一項視為網站上的有效條目:

  • “123 456 7890 至下午 6 點,然後撥打 098 765 4321”
  • “123 456 7890 或試試我的手機 098 765 4321”
  • “前目錄 - 管好自己的事”

此外,不要忘記正則表達式在處理能力方面的成本很高- 請參閱 StackExchange 的一位創始人的這篇文章,以及如何(部分)從StackOverflow 上最多產的正則表達式回答者之一那裡減輕這種情況。

因此,您真的應該考慮您的要求 - 以及最終答案將如何儲存 - 作為自由文本或嚴格作為 10 個系列

$$ valid $$數字?表中的數據越乾淨,使用優化索引策略的潛力就越大。

引用自:https://dba.stackexchange.com/questions/305271