Redshift LIKE from a list of values - amazon-redshift

I would like to filter from my table orders all zipcodes that start with the letters "B1", "NW1", "C13", etc. For example, postcodes in the UK can be "NW8 8AB".
I am using this query in Redshift but it is very inefficient now that I have a list of 500 codes.
select * from orders
where zipcode like 'B1%' or zipcode like 'NW1%' or zipcode like 'C13%'
Is there a way of doing it in a more efficient way?
I was thinking something like:
select * from orders
where zipcode like ('B1', 'NW1', 'C13') + %
But, obviously, it doesn't work.
Thank you very much.

I found the solution, which looks at all the content before the first space, which for this case it works given that I only have the first part of the postcodes before the space.
select * from orders
where split_part(zipcode, ' ', 1) like ('B1', 'NW1', 'C13')

Related

How to unnest single quoted json array in Postgresql

I have a postgresql table containing a column (movies) with json array. The column type is text. Below is example of table:
name
movies
bob
['movie1', 'movie2']
mary
['movie1', 'movie3']
How can I unnest the above table to look like below:
name
movie
bob
movie1
bob
movie2
mary
movie1
mary
movie3
Also note that the elements in the json array are single quoted
Im using postgresql database on AWS RDS engine version 10.17.
Thanks in advance
That is not JSON, that is "something vaguely inspired by JSON". we don't know how it will deal with things like apostrophes in the titles, or non ASCII characters, or any of the other things that an actual standard should specify but something vaguely inspired by a standard doesn't.
If you want to ignore such niceties and make something that works on this one example, we could suppress the characters '[] (done by regexp_replace) and then split/unnest on commas followed by optional space (done by regexp_split_to_table).
with t as (select 'bob' name ,$$['movie1', 'movie2']$$ movies union select 'mary',$$['movie1', 'movie3']$$)
select name, movie from t, regexp_split_to_table(regexp_replace(movies,$$['\[\]]$$,$$$$,'g'),', ?') g(movie);
Another slightly more resilient option would be to swap ' for " then use an actual JSON parser:
with t as (select 'bob' name ,$$['lions, and tigers, and bears', 'movie2']$$ movies union select 'mary',$$['movie1','movie3']$$)
select name, movie from t, jsonb_array_elements_text(regexp_replace(movies,$$'$$,$$"$$,'g')::jsonb) g(movie);

Postgresql Query - Return all matching search terms for each result row when using an ANY query and LIKE

Essentially what I'm trying to figure out is if there is a way to return all matching search terms in addition to the matched row when running a query that looks up a list of items using ANY or IN. In most cases the search term will exactly match the returned column value but in cases such as text search or with certain extensions like IP4r this is not always the case. In addition, you can have multiple search terms match on a single row.
To make this concrete suppose this is my query:
SELECT id, item_name, description FROM items WHERE description LIKE ANY('{%gaming%, %computer%, %socks%, %men%}');
and it returns the following two rows:
id, item_name, description
1, 'computer', 'super fast gaming computer that will help you win'
5, 'socks', 'These socks are sure to please the men in your family'
What I'd like to know is which original search terms map to the result row that was returned. In other words, I'd like the returned rows to look like this:
id, search_terms, item_name, description
1, '{%gaming%, %computer%}', 'computer', 'super fast gaming computer that will help you win'
5, '{%socks%, %men%}', 'socks', 'These socks are sure to please the men in your family'
Is there a way to efficiently do this in PostgreSQL? In the example above we're using LIKE with strings but in my real-world scenario I'm using the IP4r extension to do IP lookups against CIDR ranges where you can have multiple IP addresses in the same returned CIDR range.
I previously asked this question: PostgreSQL 9.5: Return matching search terms in each result row when using LIKE which used a CASE statement to almost solve the problem I'm describing here.
The added complexity in the scenario above is that you can have multiple search terms match a single row (e.f., gaming and computer are both matches for the description super fast gaming computer that will help you win). If you use a CASE statement then only the first match in the CASE statement gets set as the search term and you miss any other matching search terms.
Thank you for your help!
This would be a way using VALUES:
SELECT i.id, i.item_name, i.description, m.pat
FROM items AS i
JOIN (VALUES ('%gaming%'), ('%computer%'), ('%socks%'), ('%men%')) AS m(pat)
ON i.description LIKE m.pat;

Postgresql json like query

I have the following table called module_data. Currently it has three rows of entries:
id data
0ab5203b-9157-4934-8aba-1512afb0abd0 {"title":"Board of Supervisors Meeting","id":"1i3Ytw1mw98"}
7ee33a18-63da-4432-8967-bde5a44347a0 {"title":"Board of Supervisors Meeting","id":"4-dNAg2mn6o"}
8d71ca35-74eb-4751-b635-114bf04843f1 {"title":"COPD 101", "id":"l9O0jCR-sxg"}
Column data's datatype is jsonb. I'm trying to query it using like operator. Something like the following:
SELECT * FROM module_data WHERE title LIKE '%Board%';
I've been looking at the jsonb support and there doesn't seem to be a like operator. If anyone has any advice.
If the data column is text type, then use ->> on cast:
select * from module_data where data::json->>'title' like '%Board%'
If it's already json:
select * from module_data where data->>'title' like '%Board%'
I found the following is more straight-forward and easier for jsonb type of columns:
select * from table_name
where
column_name::text like '%Something%'
Found a good article on more examples and implementations:
https://www.compose.com/articles/faster-operations-with-the-jsonb-data-type-in-postgresql/
Hope it helps!
One other option which may be sufficient for other people who've found this page is to just cast the column to text type. Eg
select * from module_data where data::text like '%Board%'
Note though, this will search over the entire json and should only be used if you can guarantee the other fields won't be a problem.
I Think it should be like
select * from module_data where data->>'$."title"' like '%Board%'
then only it worked for me.

TSQL: Multiple rows into single column in query result

I feel I am missing a simple T-SQL answer to this question. I have a Measurements table, and an Activity table related by MeasurementID column, and there are at least 3 activities (sometimes more) related to a single measurement. How do I construct a query such that the output would look like this:
Measurement ID Activities
1 Running:Walking:Eating
2 Walking:Eating:Sleeping
I would also be satisfied if the output looked like this:
Measurement ID Activity1 Activity2 Activity3
1 Running Walking Eating
Is there a simple single query way to do this, or must I use (shudder) cursors to do the trick?
Unfortunately, there is no GROUP_CONCAT() in T-SQL. There is a trick to simulate it, though:
SELECT
MeasurmentID,
Activities = REPLACE((SELECT Activity AS [data()]
FROM MeasurmentActivities
WHERE MeasurmentID = ma.MeasurmentID
FOR xml path('')), ' ', ':')
FROM
MeasurmentActivities AS ma
GROUP BY
MeasurmentID
If you know in advance the number of activies by measurement, you can try the PIVOT operator.
Otherwise there is no easy way to do it.
If you can, I would suggest you to "horizontalize" the rows on your application-end.
If that is not an option, the only way I suppose would work in Transact-SQL is to convert your result in XML output and tweak it using XPATH queries.

Stuck with T-SQL Query

I'm having big troubles with a more complicated (or my mind makes it so) SQL query. Ill try to explain as best as I can what is needed.
This is how it looks like essentially: http://i.imgur.com/obWY7.png
The idea is that there will be sport games where kids team up with pro's and they have a tournament. Now everything works fine untill I get to the score part.
I need a query that return a game's outcome in 4 colomns:
winchildname, winproname, losechildname, loseproname.
This way its easy to display in my C# project. If i use this query:
SELECT * FROM Games WHERE g_win = 1 OR g_lose = 1
This returns every game played by child with the k_id 1 but the outcome is in ints instead actual text. I know how to inner join 1 int so it becomes text, but not 2. Because g_win and g_lose are both a k_id out of the child table.
Is there someone that can give me a hint, because I feel that im overthinking this big time.
You can join multiple times on the same table by giving the table an alias:
WITH Names AS (
SELECT k_id AS id, k_name, p_name
FROM Child
JOIN Pro ON k_pro = p_id
)
SELECT win.k_name AS win_k_name, win.p_name AS win_p_name, lose.k_name AS win_k_name, lose.p_name AS lose_p_name
FROM Games
JOIN Names AS win ON g_win = win.id
JOIN Names AS lose ON g_lose = lose.id