I'm trying to put together a postgres query that checks to see if a json field with an array of id's contains any id's from a subselect query. Eg: a typical user table looks like this:
User
.id // Int --> 1
.first_name // String --> Joe
.last_name // String --> Doe
.tags // JSON --> [4, 9, 21, 26, 39]
the tags table is this:
Tags
.id // Int --> 1
.name // String --> "Peaches"
But anyway, here is what I am trying to achieve:
select u.id, u.first_name from users u
where u.tags = any( array (
select t.id from tags t where t.name in ('Peaches', 'Nuts and Honey', 'Flour')
));
This results in the following error:
No function matches the given name and argument types. You might need to add explicit type casts.
Any thoughts on how to fix this would be awesome!
Related
Table Schema
Tags
----
["foo"]
["foo2", "bar"]
["bar", "foo_bar"]
["bar"]
The content of the Tags column is a json string.
Assuming the array is ["foo", "foo_bar"], any tag contained in this array needs to be filtered out, so the expected output will be
Tags
----
["foo2", "bar"]
["bar"]
The query statement I currently use is similar to the following
SELECT tags
FROM table
WHERE (
-- Translate the array into cases
CASE
WHEN tags like '%"foo"%' THEN false -- filter out "foo"
WHEN tags like '%"foo_bar"%' THEN false -- filter out "foo_bar"
... -- filter out others in the given array
ELSE true
END
)
I want to know if there is a more efficient way to do it?
If you pass the array as a json string, you can use JSON1 extension functions and aggregation with the condition in the HAVING clause:
WITH cte(tag) AS (SELECT json_each.value FROM json_each('["foo", "foo_bar"]'))
SELECT t.tags
FROM tablename t, json_each(tags)
GROUP BY t.tags
HAVING SUM(json_each.value IN cte) = 0
See the demo.
I have a table mytable and a JSONB column employees that contains data like this:
[ {
"name":"Raj",
"email":"raj#gmail.com",
"age":32
},
{
"name":"Mohan",
"email":"Mohan#yahoo.com",
"age":21
}
]
I would like to extract only the names and save them in a list format, so the resulting cell would look like this:
['Raj','Mohan']
I have tried
select l1.obj ->> 'name' names
from mytable t
cross join jsonb_array_elements(t.employees) as l1(obj)
but this only returns the name of the first array element.
How do I get the name of all array elements?
Thanks!
PostgreSQL 11.8
In Postgres 12, you can use jsonb_path_query_array():
select jsonb_path_query_array(employees, '$[*].name') as names
from mytable
In earlier versions you need to unnest then aggregate back:
select (select jsonb_agg(e -> 'name')
from jsonb_array_elements(employees) as t(e)) as names
from mytable
I want to use a keyset of a Map as a list parameter in a SQL query:
query = "select contentid from content where spaceid = :spaceid and title in (:title)"
sql.eachRow(query, [spaceid: 1234, title: map.keySet().join(',')]) {
rs ->
println rs.contentid
}
I can use single values but no Sets or Lists.
This is what I've tried so far:
map.keySet().join(',')
map.keySet().toListString()
map.keySet().toList()
map.keySet().toString()
The map uses Strings as key
Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Also, I don't get an error. I just get nothing printed like have an empty result set.
You appoach will not give the expected result.
Logically you are using a predicate such as
title = 'value1,value2,value3'
This is the reason why you get no exception but also no data.
Quick search gives a little evidence, that a mapping of a collections to IN list is possible in Groovy SQL.
Please check here and here
So very probably you'll have to define the IN list in a proper length and assign the values from your array.
title in (:key1, :key2, :key3)
Anyway something like this works fine:
Data
create table content as
select 1 contentid, 1 spaceid, 'AAA' title from dual union all
select 2 contentid, 1 spaceid, 'BBB' title from dual union all
select 3 contentid, 2 spaceid, 'AAA' title from dual;
Groovy Script
map['key1'] = 'AAA'
map['key2'] = 'BBB'
query = "select contentid from content where spaceid = :spaceid and title in (${map.keySet().collect{":$it"}.join(',')})"
println query
map['spaceid'] = 1
sql.eachRow(query, map) {
rs ->
println rs.contentid
}
Result
select contentid from content where spaceid = :spaceid and title in (:key1,:key2)
1
2
The key step is to dynamicall prepare the IN list with proper names of the bind variable using the experssion map.keySet().collect{":$it"}.join(',')
Note
You may also want to check the size if the map and handle the case where it is greater than 1000, which is an Oracle limitation of a single IN list.
It has worked for me with a little adaptation, I've added the map as a second argument.
def sql = Sql.newInstance("jdbc:mysql://localhost/databaseName", "userid", "pass")
Map<String,Long> mapProduitEnDelta = new HashMap<>()
mapProduitEnDelta['key1'] = 1
mapProduitEnDelta['key2'] = 2
mapProduitEnDelta['key3'] = 3
produits : sql.rows("""select id, reference from Produit where id IN (${mapProduitEnDelta.keySet().collect{":$it"}.join(',')})""",mapProduitEnDelta),
Display the 3 products (colums + values from the produit table) of id 1, 2, 3
I'm currently working with trying to compare an ID in Oracle(A VARCHAR2) with an array of IDs I have as input.
This is what I want to do:
Select user, city where id = :arrayOfIds
In Postgres with JDBC I would use:
Select user, city where id = any(:arrayOfIds)
Is there an equivalent function in Oracle, or a way to do this?
You should use:
Select user, city where id in (:arrayOfIds)
and in you code, you need to trasform your array in string with ids:
arrayOfIds[0] --> 1
arrayOfIds[1] --> 3
arrayOfIds[2] --> 5
...
in
1, 3, 5, ...
and you can use:
Array array = conn.createArrayOf("arrayOfIds", new Object[]{"1", "2","3"});
pstmt.setArray(1, array);
How to use an arraylist as a prepared statement parameter
I have a database as below:
TABLE_B:
ID Name LISTID
1 NameB1 1
2 NameB2 1,10
3 NameB3 1025,1026
To select list data of table with ID. I used:
public static List<ListData> GetDataById(string id)
{
var db = Connect.GetDataContext<DataContext>("NameConnection");
var sql = (from tblB in db.TABLE_B
where tblB.LISTID.Contains(id)
select new ListData
{
Name= tblB.Name,
});
return sql.ToList();
}
When I call the function:
GetDataById("10") ==> Data return "NameB2, NameB3" are not correct.
The data correct is "NameB2". Please help me about that?
Thanks!
The value 10 will cause unintended matches because LISTID is a string/varchar type, as you already saw, and the Contains function does not know that there delimiters that should be taken into account.
The fix could be very simple: surround both the id that you are looking for and LISTID with extra commas.
So you will now be looking for ,10,.
The value ,10, will be found in ,1,10, and not in ,1025,1026,
The LINQ where clause then becomes this:
where ("," + tblB.LISTID + ",").Contains("," + id + ",")