欄位中的字數(全部和唯一) - 有沒有更優雅/最佳的方式?
回答這個問題,
鑑於此表(根據問題建構):
CREATE TABLE wordcount (id SERIAL NOT NULL PRIMARY KEY, description TEXT NOT NULL); INSERT INTO wordcount (description) VALUES ('What a great day'); INSERT INTO wordcount (description) VALUES ('This is a product. It is useful');
產生這個結果:
id | word_count | unique_word_count | Description ---------+------------+-------------------+--------------- 1 | 4 | 4 | What a great day 2 | 7 | 6 | This is a product. It is useful
我給出了(正確的)答案,你可以在這裡找到。
然而,在評論中,OP 然後又問了一個問題——如果有問題的字元串是
['a', ' ', ' ', 'b']
並且我的解決方案完全崩潰了怎麼辦——對於初學者來說,字元串甚至不會INSERT
進入表格。所以,現在的問題是,如何處理這樣的字元串 - 即撇號、方括號和 c。我將給出自己的答案,並為更優雅的解決方案提供獎金。
具有多種選擇的解決方案將受到高度評價,那些顯示出“跳出框框思考”證據的解決方案也將受到高度重視(對於陳詞濫調感到抱歉 - 但它適合這裡!:-))。我還將詳細解釋我的推理 - 這也將獲得榮譽!提及其他伺服器的選項也將獲得優勢。顯然,我只能將獎金獎勵給一個人,但我會贊成所有體面的答案。
我只能在兩天內提供獎金 - 所以我會發布我的答案並在允許時提供獎金(+100)。此外,任何處理我自己無法處理的字元串的解決方案 - 還沒有經過詳盡的測試。
至於您的解決方案:聰明且有可靠的解釋。但是這些情況呢:
''
,NULL
,'"§$%'
,'-'
? 沒有言語。計數應該是0
- 但您的解決方案完全刪除了這些行。此外,任何解決方案首先取決於 “word” 的確切定義,這可能會有很大的不同……
基於正則表達式的字元串處理
與您的解決方案類似,但有一些替代建議:
SELECT id , COALESCE(cardinality(arr), 0) AS word_count , unique_word_count , description FROM ( SELECT * , string_to_array(trim(regexp_replace(description, '\W+', ' ', 'g')), ' ') AS arr FROM wordcount ) a LEFT JOIN LATERAL ( SELECT count(DISTINCT elem) AS unique_word_count FROM unnest(arr) elem ) b ON true;
db<>fiddle here(擴展測試案例)
核心是
regexp_replace(description, '\W+', ' ', 'g')
將非單詞字元的所有子字元串替換為單個空格。請參閱正則表達式類速記轉義。這消除了遊戲早期的所有噪音。隨後以便宜
trim()
的方式刪除前導/尾隨空格,string_to_array()
並將準備好的字元串轉換為數組。
word_count
直接從數組中獲取。再次:便宜。
unique_word_count
來自帶有 的子LATERAL
查詢count(DISTINCT ...)
。該部分可能會或可能不會比總的未嵌套/聚合慢。這有點簡單。
COALESCE
外部SELECT
處理輸入(原始NULL
問題未提及NOT NULL
約束)。可選,以防您需要0
而不是NULL
.或者(在使用短字元串的快速測試中更快):
SELECT id , count(*) AS word_count , count(DISTINCT elem) AS unique_word_count , description FROM ( SELECT id, description , unnest(string_to_array(trim(regexp_replace(description, '\W+', ' ', 'g')), ' ')) AS elem FROM wordcount ) sub GROUP BY id, description;
這會像您的答案一樣刪除0 個單詞的行。
(Ab-)使用文本搜尋解析器
使用文本搜尋功能
ts_parse()
更簡單。可能會或可能不會更快。但首先研究文本搜尋解析器辨識的各種標記,看看哪些符合您對“單詞”的定義:SELECT * FROM ts_token_type('default')
僅適用於“ASCII Words”:(與上面不同,下劃線 (
_
) 在這裡不被視為單詞字元):SELECT w.id , count(*) AS word_count , count(DISTINCT token) AS unique_word_count , w.description FROM wordcount w, ts_parse('default', w.description) t WHERE t.tokid = 1 -- 'asciiword' GROUP BY w.id;
為了
_
避免分隔單詞,replace()
請先使用 simple:SELECT w.id , count(*) AS word_count , count(DISTINCT token) AS unique_word_count , w.description FROM wordcount w, ts_parse('default', replace(w.description, '_', 'x')) t WHERE t.tokid = 1 -- 'asciiword' GROUP BY w.id;
同樣,要保留所有行:
SELECT w.id , count(token) AS word_count , count(DISTINCT token) AS unique_word_count , w.description FROM wordcount w LEFT JOIN LATERAL ( SELECT t.token FROM ts_parse('default', w.description) t WHERE t.tokid = 1 -- 'asciiword' ) t ON true GROUP BY w.id;
db<>在這裡擺弄
有關的: