Search code examples
sqlpostgresqlhstore

Hstore search on values with wildcard


Using PostgreSQL, I want to be able to find all of the key-value pairs in an HStore field where the value matches a given query. So, for example, given a table like the following:

Name        Parentage (Hstore)
_____       ___________________
Rover       Mother => Yellow Lab, Father => Black Lab
Fido        Mother => Black Lab, Father => Rottweiler
Rex         Mother => Labrador Retriever, Father => Springer Spaniel 
Lassie      Mother => Border Collie, Father => Collie

How could I do a query for any dog that has a '%lab%' in its family tree? I.e. the search would bring up Rover, Fido and Rex, but not Lassie. The only examples I've seen are of searches within a single key - I need a search within all values that allows wildcards.

I have looked at this similar question, but it seems to only do a search on a particular key, not on all of the values found in the Hstore field across all keys.

Note that this is a constructed example, I was trying to make it accessible. In my actual database, I have keys for language codes followed by values of translations of the same words in the different language. I need to be able to do a search that could hit any of the values, regardless of what language it is in.


Solution

  • Break out the hstore into rows of name/parent and then select distinct names of dogs where the parent column matches your search criteria.

    Depending on the nature of your actual data, this may want additional indexes. I wouldn't use hstore for this, but your actual data may be different.

    % psql -qe -f hstore.sql
    begin;
    create extension hstore;
    create temp table dogs (
        "name" text,
        parentage hstore
    );
    insert into dogs values
    ('Rover', 'Mother => "Yellow Lab",Father => "Black Lab"')
    ,('Fido', 'Mother => "Black Lab",Father => "Rottweiler"')
    ,('Rex', 'Mother => "Labrador Retriever",Father => "Springer Spaniel"')
    ,('Lassie', 'Mother => "Border Collie",Father => "Collie"')
    ;
    table dogs;
      name  |                          parentage                           
    --------+--------------------------------------------------------------
     Rover  | "Father"=>"Black Lab", "Mother"=>"Yellow Lab"
     Fido   | "Father"=>"Rottweiler", "Mother"=>"Black Lab"
     Rex    | "Father"=>"Springer Spaniel", "Mother"=>"Labrador Retriever"
     Lassie | "Father"=>"Collie", "Mother"=>"Border Collie"
    (4 rows)
    
    select * from dogs where "name" in
    (select distinct "name" from (
                select "name", unnest(avals(parentage)) as parent
            ) as plist
            where parent ilike '%lab%'
    );
     name  |                          parentage                           
    -------+--------------------------------------------------------------
     Rover | "Father"=>"Black Lab", "Mother"=>"Yellow Lab"
     Fido  | "Father"=>"Rottweiler", "Mother"=>"Black Lab"
     Rex   | "Father"=>"Springer Spaniel", "Mother"=>"Labrador Retriever"
    (3 rows)
    
    rollback;