String match in Postgresql - postgresql

I am trying to make separate columns in my query result for values stored in in a single column. It is a string field that contains a variety of similar values stored like this:
["john"] or ["john", "jane"] or ["john", "john smith', "jane"],etc... where each of the values in quotes is a distinct value. I cannot seem to isolate just ["john"] in a way that will return john and not john smith. The john smith value would be in a separate column. Essentially a column for each value in quotes. Note, I would like the results to not contain the quotes or the brackets.
I started with:
Select name
From namestbl
Where name like %["john"]%;
I think this is heading in the wrong direction. I think this should be in select instead of where.
Sorry about the format, I give up trying to figure out the completely useless error message when i try to save this with table markdown.

Your data examples represent valid JSON array syntax. So cast them to JSONB array and access individual elements by position (JSON arrays are zero based). The t CTE is a mimic of real data. In the illustration below the number of columns is limited to 6.
with t(s) as
(
values
('["john", "john smith", "jane"]'),
('["john", "jane"]'),
('["john"]')
)
select s::jsonb->>0 name1, s::jsonb->>1 name2, s::jsonb->>2 name3,
s::jsonb->>3 name4, s::jsonb->>4 name5, s::jsonb->>5 name6
from t;
Here is the result.
name1
name2
name3
name4
name5
name6
john
john smith
jane
john
jane
john

Related

Postgres 13 join from another table on JSONB array of String

I have a table with JSONB column. In this column we store identifiers of another table as json array of strings. How can I join the tables
Table Customer:
CustomerID
Name
Campaigns (JSONB)
1
John
[ "rxuatoak", "vsnxcvdsl", "jkiasokd" ]
2
Mick
[ "jdywmsks", "nxbsvwios", "jkiasokd" ]
Table Campaign:
CampaignID
Identifier
CampaignName
1
rxuatoak
Alpha
2
vsnxcvdsl
Bravo
3
jkiasokd
Charlie
4
jdywmsks
Delta
5
nxbsvwios
Echo
Result something like:
CustomerID
Name
CampaignNames
1
John
Alpha, Bravo, Charlie
2
Mick
Delta, Echo, Charlie
I tried many ways, and could only find online help with json objects inside the jsonb column. My jsonb column has simple array of strings.
Using POSTGRES 13
You can apply a JOIN operation between the two tables on condition that an identifier is found within a campaign (using ? operator). Then apply aggregation with STRING_AGG, with respect to the "CustomerID" and "Name"
SELECT customer.CustomerID,
customer.Name_,
STRING_AGG(campaign.CampaignName, ',') AS CampaignNames
FROM customer
INNER JOIN campaign
ON customer.Campaigns ? campaign.Identifier
GROUP BY customer.CustomerID,
customer.Name_
Check the demo here.

How to use ts_query with ANY(anyarray)

I currently have a query in PostgreSQL like:
SELECT
name
FROM
ingredients
WHERE
name = ANY({"string value",tomato,other})
My ingredients table is simply a list of names:
name
----------
jalapeno
tomatoes
avocados
lime
My issue is that plural values in the array will not match single values in the query. To solve this, I created a tsvector column on the table:
name | tokens
---------------+--------------
jalapeno | 'jalapeno':1
tomatoes | 'tomato':1
avocados | 'avocado':1
lime | 'lime':1
I'm able to correctly query single values from the table like this:
SELECT
name,
ts_rank_cd(tokens, plainto_tsquery('tomato'), 16) AS rank
FROM
ingredients
WHERE
tokens ## plainto_tsquery('tomato')
ORDER BY
rank DESC;
However, I need to query values from the entire array. The array is generated from another function, so I have control over the type of each of items in the array.
How can I use the ## operand with ANY(anyarray)?
That should be straight forward:
WHERE tokens ## ANY
(ARRAY[
plainto_tsquery('tomato'),
plainto_tsquery('celery'),
plainto_tsquery('vodka')
])

Return only capitalised names from a SQL query

I have a table storing first names and surnames; some may be stored with capitalisation. Is there a query I could use to return only those rows with capitalisation?
For instance, if I have the following entries:
firstname | surname
-----------+-----------
Bob | Jones
john | bobbins
I'd only expect to be returned the record for "Bob Jones".
I'm sure it's not a difficult thing to do, but I haven't been able to find any examples anywhere.
Compare the value with the value where the first character is upper-case:
select *
from the_table
where firstname = initcap(firstname)
and surname = initcap(surname);
The function initcap() converts the first letter of each word to upper case and the rest to lower case.

Extract some digits after word id

I have a table with a Name column and a Log column.
Name Log
Michelle Bad 222 news travels id 54585 fast.
Lucy Barking 333 dogs id 545584 seldom bite.
Green Beauty is 444 in the id 85955 eyes of the beholder.
Gail Beggars 123 can't be ID 4658 choosers.
I want to extract only the ID digits from log column. Note that the word ID could be capitalized or not. Hence, the output should be like this:
Name ID
Michelle 54585
Lucy 545584
Green 85955
Gail 4658
I tried to use the following query:
select name
, substring(log from E'^(.*?)[id< ]') as id
from mytable;
However, I cannot have the output I need.
Something along these lines should work. Since you didn't provide CREATE TABLE and INSERT statements, I just used one row in a common table expression.
with data as (
select 'Michelle' as name, 'Bad 333 id 54342 wibble' as log
)
select name, substring(substring(log::text, '((id|ID) [0-9]+)'), '[0-9]+')
from data
where log::text ~* 'id [0-9]+';
The nested substring() calls first return the id number along with the string 'id', then return just the id number.

postgres coalesce fields, sum and group by

maybe someone can help me out with a postgres query.
the table structure looks like this
nummer nachname vorname cash
+-------+----------+----------+------+
2 Bert Brecht 0,758
2 Harry Belafonte 1,568
3 Elvis Presley 0,357
4 Mark Twain 1,555
4 Ella Fitz 0,333
…
How can I coalesce the fields where "nummer" are the same and sum the cash values?
My output should look like this:
2 Bert, Brecht 2,326
Harry, Belafonte
3 Elvis, Presley 0,357
4 Mark, Twain 1,888
Ella, Fitz
I think the part to coalesce should work something like this:
array_to_string(array_agg(nachname|| ', ' ||coalesce(vorname, '')), '<br />') as name,
Thanks for any help,
tony
SELECT
nummer,
string_agg(nachname||CASE WHEN vorname IS NULL THEN '' ELSE ', '||vorname END, E'\n') AS name,
sum(cash) AS total_cash
FROM Table1
GROUP BY nummer;
See this SQLFiddle; note that it doesn't display the newline characters between names, but they're still there.
The CASE statement is used instead of coalesce so you don't have a trailing comma on entries with a last name but no first name. If you want a trailing comma, use format('%s, %s',vorname,nachname) instead and avoid all that ugly string concatenation business:
SELECT
nummer, string_agg(format('%s, %s', nachname, vorname), E'\n'),
sum(cash) AS total_cash
FROM Table1
GROUP BY nummer;
If string_agg doesn't work, get a newer PostgreSQL, or mention the version in your questions so it's clear you're using an obsolete version. The query is trivially rewritten to use array_to_string and array_agg anyway.
If you're asking how to sum numbers that're actually represented as text strings like 1,2345 in the database: don't do that. Fix your schema. Format numbers on input and output instead, store them as numeric, float8, integer, ... whatever the appropriate numeric type for the job is.