2016-04-02 36 views
18

Làm cách nào để đếm số lần xuất hiện của chuỗi con trong chuỗi trong PostgreSQL?Đếm số lần xuất hiện của chuỗi con trong chuỗi trong PostgreSQL


Ví dụ:

Tôi có một bảng

CREATE TABLE test."user" 
(
    uid integer NOT NULL, 
    name text, 
    result integer, 
    CONSTRAINT pkey PRIMARY KEY (uid) 
) 

Tôi muốn viết một truy vấn để các result chứa cột có bao nhiêu lần xuất hiện của chuỗi o cột name chứa. Ví dụ: nếu trong một hàng, namehello world, cột result phải chứa 2, vì có hai o trong chuỗi hello world.

Nói cách khác, tôi đang cố gắng để viết một truy vấn mà sẽ mất đầu vào:

enter image description here

và cập nhật các result cột:

enter image description here


tôi nhận thức được chức năng regexp_matches và tùy chọn g, cho biết toàn bộ chuỗi (g = toàn cầu) cần phải được quét để biết tất cả các lần xuất hiện của chuỗi con).

Ví dụ:

SELECT * FROM regexp_matches('hello world', 'o', 'g'); 

lợi nhuận

{o} 
{o} 

SELECT COUNT(*) FROM regexp_matches('hello world', 'o', 'g'); 

lợi nhuận

2 

Nhưng tôi không thấy cách viết truy vấn UPDATE sẽ cập nhật cột result theo cách nó sẽ chứa số lần xuất hiện của chuỗi con o cột name chứa.

+0

có thể trùng lặp của [PostgreSQL số ​​đếm lần chuỗi xảy ra trong văn bản] (http://stackoverflow.com/questions/25757194/postgresql -nỗi-of-lần-substring-xảy ra-trong-văn bản) –

Trả lời

21

Một giải pháp thông thường được dựa trên logic này: thay thế các chuỗi tìm kiếm với một chuỗi rỗng và chia phần chênh lệch giữa chiều dài cũ và mới bằng chiều dài của chuỗi tìm kiếm

(CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'substring', ''))) 
/CHAR_LENGTH('substring') 

Do đó:

UPDATE test."user" 
SET result = 
    (CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'o', ''))) 
    /CHAR_LENGTH('o'); 
+0

Đây là một câu trả lời vững chắc, và nó là đúng. Bạn có thể quan tâm đến việc viết lên [tất cả các phương pháp làm việc này] (http://dba.stackexchange.com/a/166763/2639) –

+0

Cảm ơn! Có ai biết, tại sao không có cách nào đơn giản hơn? Ý tôi là, REPLACE đã trải qua những rắc rối khi quét toàn bộ chuỗi cho tất cả các lần xuất hiện, tại sao không có thứ gì đó thực hiện một nửa công việc REPLACE - chỉ đếm số lần xuất hiện –

+0

@AleksandrLevchuk: Vâng, bạn có thể viết Chức năng do Người dùng Xác định thực hiện phép tính này, ví dụ có 'REGEXP_COUNT' của Oracle trong https://www.enterprisedb.com/docs/en/9.5/eeguide/EDB_Postgres_Enterprise_Guide.1.041.html. – dnoeth

13

Cách Postgres'y làm điều này chuyển đổi chuỗi thành mảng và đếm chiều dài của mảng (và sau đó trừ 1):

select array_length(string_to_array(name, 'o'), 1) - 1 

Lưu ý rằng điều này làm việc với các bản chất dài hơn.

Do đó:

update test."user" 
    set result = array_length(string_to_array(name, 'o'), 1) - 1; 
+2

Nếu ai đó cần regexp, giải pháp này với "regexp_split_to_array" thay vì "string_to_array" cũng hoạt động. –

+0

Giải pháp này chậm hơn đáng kể so với đề xuất của @ dnoeth. Tôi không nghĩ đó là Postgres-y hơn. Khi mọi thứ nhanh hơn và di động hơn theo một phương pháp khác, tôi nghĩ chúng ta gọi đó là * tốt hơn *. =) –

+1

@EvanCarroll Thật không may, câu trả lời của dnoeth sẽ không hoạt động cho các trận đấu regex, vì bạn có thể không biết độ dài của trận đấu. Câu trả lời này sẽ hoạt động cho cả hai đối sánh regex và đối sánh chuỗi thô. Tôi nghĩ rằng những gì chúng ta gọi _better_ là giải pháp hoạt động cho mọi thứ bạn đang cố gắng làm :) – WebWanderer

0

cách khác:

UPDATE test."user" SET result = length(regexp_replace(name, '[^o]', '', 'g')); 
Các vấn đề liên quan