Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

In postgresql, I need to extract the first two words in the value for a given column. So if the value is "hello world moon and stars" or "hello world moon" or even just "hello world", I need "hello world".

I was hoping to use regexp_split_to_array but it doesn't seem that I can use this and access the elements returned in the same query?

Do I need to create a function for what I'm trying to do?

share|improve this question

3 Answers 3

You can use POSIX regular expressions with PostgreSQL's substring():

select substring('hello world moon' from E'^\\w+\\s+\\w+');

Or with a very liberal interpretation of what a word is:

select substring('it''s a nice day' from E'^\\S+\\s+\\S+');

Note the \S (non-whitespace) instead of \w ("word" character, essentially alphanumeric plus underscore).

Don't forget all the extra quoting nonsense though:

  • The E'' to tell PostgreSQL that you're using extending escaping.
  • And then double backslashes to get single backslashes past the string parser and in to the regular expression parser.

If you really want to use regexp_split_to_array, then you can but the above quoting issues apply and I think you'd want to slice off just the first two elements of the array:

select (regexp_split_to_array('hello world moon', E'\\s+'))[1:2];

I'd guess that the escaping was causing some confusion; I usually end up adding backslashes until it works and then I pick it apart until I understand why I needed the number of backslashes that I ended up using. Or maybe the extra parentheses and array slicing syntax was an issue (it was for me but a bit of experimentation sorted it out).

share|improve this answer
    
You can use the dollar-quoted string syntax to avoid the double backslashes: $$^\w+\s+\w+$$ –  Joey Adams Mar 21 '11 at 2:04
    
@Joey Adams: But then you run into issues with regular expressions that are anchored at the end. I usually just use E'' syntax so that I don't have to remember yet another set of quoting rules. –  mu is too short Mar 21 '11 at 4:44
    
@mu yes, it's ugly and almost ridiculous, but still far easier IMO than escaping which is IMO a minefield - for anyone else reading these comments, just choose a pattern that doesn't clash with the end, eg: $re$^\w+\s+\w+$$re$ –  Jack Douglas Mar 21 '11 at 7:59
    
@mu note that select substring(E'it\'s a nice day' from E'^\\w+\\s+\\w+'); probably does not give the desired result –  Jack Douglas Mar 21 '11 at 8:21
    
@JackPDouglas: I think we're dangerously close to fighting over vi versus emacs now (for the record: ed(1) is the standard text editor; ed man! man ed!). I find it harder to find the regex in a twisted pile of dollar signs than to mentally undouble the backslashes. In the end, use whatever works and move on to more interesting problems :) –  mu is too short Mar 21 '11 at 8:26
select substring(my_text from $$^\S+\s+\S+$$) from v;

  substring
-------------
 hello world
 hello world
 hello world
(3 rows)

where for the purpose of demonstration, v is:

create view v as select 'hello world moon and stars' as my_text union all 
                 select 'hello world mood' union all 
                 select 'hello world';

if you want to ignore whitespace at the beginning:

select substring(my_text from $$^\s*\S+\s+\S+$$) from v;
share|improve this answer
    
I still prefer the regexp_split_to_array(text, E'\\s+'))[1:2] approach, that seems to match the intent better than messing around with substring and what a "word" is. –  mu is too short Mar 21 '11 at 8:41
    
@mu I'd be concerned about how heavy that would be on my system when the strings are long. There is no reason to suppose from the question that there aren't tens of thousands of words in the field –  Jack Douglas Mar 21 '11 at 15:10
    
True enough. Hard to say what the best approach would be without more details and, most importantly, experimentation on real data. I tend to start with clarity and a direct expression of my intent; if that isn't good enough, then it is time for cleverness and cycle bumming. –  mu is too short Mar 21 '11 at 19:32

found one answer:

select split_part('hello world moon', ' ', 1) || ' ' || split_part('hello world moon', ' ', 2);
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.