0

SQL noob trying to return db results if a table value is found in an array. I'm using Node JS and Postgres.

So far, I can figure out how to return the result for a single item:

SELECT * FROM table WHERE position(value in 'someval1')>0
// returns [{ id: 1, value: 'val1' }]

I don't know how to replace the single item above ('someval1') with an array.

EXAMPLE

Given the following table:

id value
1 val1
2 val2
3 val3

and the array: ['foo', 'someval1', 'anotherval2', 'bar']

how might I check that table "value" exists within each array item to return:

[
  { id: 1, value: 'val1' },
  { id: 2, value: 'val2' }
]
1
  • You want to return rows from a table if values in the array contains strings that contain the table row values? Just need some clarity. Or do you want to return rows that contain values from the array of strings?
    – Kevin
    Commented Jan 30, 2022 at 0:59

4 Answers 4

1

This is backwards. Normally you would do something like...

select * from theTable where searchField like '%text1%' or searchField like '%text2%'

But you seem to be trying to pull rows from a table when the row's data is contained by any of several values in the criteria array. What I think you might be looking for is temporary tables (though this exact syntax might be deprecated soon and I don't see the replacement at the moment). You would create the temporary table with just the one field with your text values from the array in it. Then you can use table joining to get the behavior you're trying for. Something like...

select dt.*, tt.SearchString  
from DataTable dt 
right join TempTable tt 
on tt.SearchString like '%'+dt.value+'%'

And I didn't run that through a tester of any kind, but with the right join, it should only include rows that have a match in the temp table. Assuming my code has typos in it, look into the temp tables (or alternative) and then joins.

Edit: Figured I'd offer a little more on the temporary tables since you mentioned being new to SQL. I think you'd want code like...

create temporary table TempTable (searchString varchar(100));
insert into TempTable values 
    ('foo'), 
    ('someval1'), 
    ('anotherval2'), 
    ('bar');

And of course, you're running that before you do the join with the real table.

2
  • Thanks for your answer. I ended up changing my approach because, like you mentioned, this seems backwards. After researching temporary tables though, I think that solution would have worked.
    – calipoop
    Commented Feb 1, 2022 at 5:38
  • Please see my answer below – it solves my problem, but it would be nice to have confirmation on best practice, etc.
    – calipoop
    Commented Feb 2, 2022 at 23:10
1

Okay, I thought of a slight variation of the approach you can use if temp tables aren't an option (which is why I'm making this a separate answer in case it's the one that ends up working for you.

Create a normal table you use specifically for the purpose of containing the array values. If multiple users might be running this process at the same time, you'll need an ID (session ID, user ID, something reliably unique) to make sure you're only using the values relevant to that person. So, you'd want a table like...

create table SearchTerms (ID int not null AUTO_INCREMENT, sessionID varchar(25), searchTerm varchar(50));

Then, when you run your queries, you start with inserts to load the terms...

insert into SearchTerms values
    ('0129205017_smith', 'foo'), 
    ('0129205017_smith', 'someval1'), 
    ('0129205017_smith', 'anotherval2'), 
    ('0129205017_smith', 'bar');

Next, you run your actual query that looks like...

select dt.*, st.searchTerm 
from SearchTerms st 
left join DataTable dt 
  on st.searchTerm like '%'+dt.value+'%' 
where st.sessionID = '0129205017_smith';

And then you might want to do clean up so the search terms table doesn't get clogged with stuff...

delete from SearchTerms where sessionID = '0129205017_smith';
1

You might consider using regex. It is slightly less performant than LIKE, but unless your dataset really needs a lot of optimization you will probably never notice. I have also included an alternative that uses a join to a list of values and LIKE to produce the same results. See this fiddle. I have set the version to postgres 14, since you didn't specify:

https://dbfiddle.uk/?rdbms=postgres_14&fiddle=7062f6828a161c934c3e8ef96110dd05

CREATE and INSERT:

create table SearchTerms (ID serial primary key, sessionID varchar(25), searchTerm varchar(50));
insert into SearchTerms (sessionID, searchTerm) values
('0129205017_smith', 'foo'), 
('0129205017_smith', 'someval1'), 
('0129205017_smith', 'anotherval2'), 
('0129205017_smith', 'bar');

Solution using regex (~):

select * from searchTerms 
where searchTerm ~ 'val1|val2';

Solution using LIKE and a join to a list of values:

select * from searchTerms s
join (SELECT 'val1' as term UNION ALL SELECT 'val2' as term) v
on s.searchTerm like concat('%', v.term, '%');

I personally prefer regex over like for its flexibility and terseness, and I very rarely find a situation where using LIKE offers sufficient performance improvements to use it in favor of regex.

6
  • Thanks for your answer. Yours is similar to @Kevin's – marking his correct since I like the concept of temporary tables.
    – calipoop
    Commented Feb 1, 2022 at 5:40
  • Thanks for your upvote. I did take the solutions discussed here (including the temporary table) and put them in a fiddle with EXPLAIN to show how they might be executed by the engine. dbfiddle.uk/… Commented Feb 1, 2022 at 21:21
  • Thanks for your input! I posted a solution that solves my problem and appears to be simple-enough – a second pair of eyes on it would be fantastic!
    – calipoop
    Commented Feb 2, 2022 at 23:12
  • Hey, I added that solution to a fiddle. I usually work in mySQL so unnesting an array wasn't top of mind for me, but you can see the explain plan. There is something similar in mySQL 8+, where you can use a json array as a table. I didn't see the same functionality in the postGres docs, so I didn't add that in this: dbfiddle.uk/… Commented Feb 3, 2022 at 5:13
  • 1
    But again, you are unlikely to run into real performance problems with any of these solutions unless you have a whole lot of data to plow through. Whichever one is the tersest and easiest to maintain is probably the best, and your unnest query is very terse. Commented Feb 3, 2022 at 5:14
0

After tinkering with this a bit, I think I found the solution that works best for me and avoids creating temp tables:

SELECT value FROM table 
    JOIN UNNEST (array['foo', 'someval1', 'anotherval2', 'bar']) AS array_val
    ON array_val ~ value;

Interested in confirmation whether this indeed is simpler/more efficient than posted answers – or input on how it can be improved!

1
  • Going to be honest and say I don't understand why that query works for you. Tilde is the confusing part for me. I thought was a negation operation, and not a comparison by itself. I also thought you'd have to make that a right join, so you won't get values from the main table that don't have a match in the unnest table. But if it works... then... I might need to freshen up my knowledge on mySQL. :)
    – Kevin
    Commented Feb 9, 2022 at 16:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.