Using List inside a postgres Query - sql

i have a dynamic list.
list=['a','b','c','d' ..... ] so length may change
i want to compare these list values in a query
select * from student where name in(all the list values);
i want to pass list values into this query
how i can do this.. ??? please help
Thank you

In Postgres, you can use arrays. The syntax in the where clause looks like:
where name = any (array[1, 2, 3])
or
where name = any (list_parameter)

You can write a function that gets a list as a parameter and return a string like "'one', 'two','three'".
// need a string like this 'one', 'two'
private String arrayToSqlInChecker(List<String> loc_list) {
StringBuilder value = new StringBuilder("");
for (int i = 0; i < loc_list.size(); i++) {
value.append("'" + loc_list.get(i) + "'");
if (i != loc_list.size() - 1) {
value.append(",");
}
}
return value.toString();
}
And then you have to append this string into you PostgreSQL IN query
"id IN (" + this.arrayToSqlInChecker(loc_list) + ")"
You can also handle null or empty values in the function

Related

How to dynamically generate SQL query column names and values from arrays?

I have about 20 columns in one row and not all columns are required to be filled in when row created also i dont want to cardcode name of every column in SQL query and on http.post request on frontend. All values are from form. My code:
var colNames, values []string
for k, v := range formData {
colNames = append(colNames, k)
values = append(values, v)
}
Now i have 2 arrays: one with column names and second with values to be inserted. I want to do something like this:
db.Query("insert into views (?,?,?,?,?,?) values (?,?,?,?,?,?)", colNames..., values...)
or like this:
db.Query("insert into views " + colNames + " values" + values)
Any suggestions?
Thanks!
I assume your code examples are just pseudo code but I'll state the obvious just in case.
db.Query("insert into views (?,?,?,?,?,?) values (?,?,?,?,?,?)", colNames..., values...)
This is invalid Go since you can only "unpack" the last argument to a function, and also invalid MySQL since you cannot use placeholders (?) for column names.
db.Query("insert into views " + colNames + " values" + values)
This is also invalid Go since you cannot concatenate strings with slices.
You could fromat the slices into strings that look like this:
colNamesString := "(col1, col2, col3)"
valuesString := "(val1, val2, val3)"
and now your second code example becomes valid Go and would compile but don't do this. If you do this your app becomes vulnerable to SQL injection and that's something you definitely don't want.
Instead do something like this:
// this can be a package level global and you'll need
// one for each table. Keep in mind that Go maps that
// are only read from are safe for concurrent use.
var validColNames = map[string]bool{
"col1": true,
"col2": true,
"col3": true,
// ...
}
// ...
var colNames, values []string
var phs string // placeholders for values
for k, v := range formData {
// check that column is valid
if !validColNames[k] {
return ErrBadColName
}
colNames = append(colNames, k)
values = append(values, v)
phs += "?,"
}
if len(phs) > 0 {
phs = phs[:len(phs)-1] // drop the last comma
}
phs = "(" + phs + ")"
colNamesString := "(" + strings.Join(colNames, ",") + ")"
query := "insert into views " + colNamesString + phs
db.Query(query, values...)

JbdcTemplate - PreparedStatements with Dynamic SQL Query

I know jdbcTemplate can be used to create PreparedStatements if you set it up to do so:
i.e.
private JdbcTemplate jdbcTemplate;
String sqlQuery = "Select * from table where column = ?";
String value = "value";
this.jbdcTemplate.query(sqlQuery, new Object[] { value }, rs, rowNum -> {
System.out.println(rs.getString("column"));
});
However, I have a query with many AND operators in the Where clause, and depending on some condition, a specific AND statement may or may not be added to the query string.
i.e.
private JdbcTemplate jdbcTemplate;
StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 "); //base query
if(someCondition)
sqlQuery.append("And column1 = '" + value1 + "'");
if(someCondition2)
sqlQuery.append("And column2 = '" + value2 + "'");
if(someCondition3)
sqlQuery.append("And column3 = '" + value3 + "'");
//etc...
With this type of dynamic query, I am unable to know exactly how many values to place in the new Object[] {} field at compile time, because the someCondition fields are always changing at runtime.
Is there a way to write the this.jdbcTemplate.query(sqlQuery.toString(), new Object[] {}... to accommodate these dynamic AND statements?
I found a solution after taking into consideration what #mustaccio said in his comment to my original question. I also took part of the solution from this stackoverflow question and used it in my own solution.
The main issue I was having was dynamically creating an Object[] array at runtime, since you can't dynamically add elements to an Object[] array. They must have a defined size when initialized.
First, I create an arraylist of strings called queryArgs. Every time one of the if conditions proves true and we add an AND statement to the query, I also add another line of code that adds the value to be plugged in the preparedStatement to the queryArgs arraylist. Once that's done, I create a new Object[] array whose size is initialized to the size of the queryArgs arraylist. Lastly, I loop through each element in the Object[] array, setting them equal to the values in queryArgs.
private JdbcTemplate jdbcTemplate;
List<QueryResults> jdbcQuery(QueryParams queryParams) {
/* base query */
StringBuilder sqlQuery = new StringBuilder("Select * from table where 1=1 ");
/* stores the dynamic preparedStatement arguments */
List<String> queryArgs = new ArrayList<>();
if(someCondition){
sqlQuery.append("And column1 = ? ");
queryArgs.add(queryParams.value1);
}
if(someCondition2){
sqlQuery.append("And column2 = ? ");
queryArgs.add(queryParams.value2);
}
if(someCondition3){
sqlQuery.append("And column3 = ? ");
queryArgs.add(queryParams.value3);
}
//etc...
/* this is the part I used from the above stackoverflow question */
Object[] preparedStatementArgs = new Object[queryArgs.size()];
for(int i = 0; i < preparedStatementArgs.length; i++){
preparedStatementArgs[i] = queryArgs.get(i);
}
/* Lastly, execute the query */
return this.jdbcTemplate.query(sqlQuery.toString(),
preparedStatementArgs, (rs, rowNum) -> {
QueryResults result = new QueryResults();
/* store the results of the query... */
});
}
The outlier is that one of the dynamic AND statements above is written like this:
AND column4 IN ('x','y','z','etc..'‌​)
, where the values inside of the parentheses are also dynamic at runtime. My service receives a string value that looks like this:
String queryParams.value4 = "x,y,z,etc...";
I can't write the preparedStatement like this: AND column4 IN (?) and then simply plug in queryParams.value4 because it will treat queryParams.value4 as a string literal, which leads to errors.
To solve this issue, I create another arraylist of strings called value4Array. I loop through every character in queryParams.value4, and I check if the current character in the loop is equal to a comma, our delimiter. If it is, then I create a substring of all the characters leading up to that comma, and add that newly created string to value4Array.
The next step is to create the dynamic AND column4 IN (?) statement. I do this by looping through each string value in the value4Array arraylist we just created, and doing a sql.append("?"), based on how many strings are in value4Array. After this, the rest of the logic is the same as my solution above.
/* this function takes the comma delimited string literal (value4 : "x,y,z,etc...")
and parses it into an array of strings. */
private List<String> parseValue4(String value4){
int valueIndex= 0;
List<String> value4Array = new ArrayList<>();
for(int i = 0; i < value4.length(); i++){
if(value4.charAt(i) == ','){
value4Array.add(value4.substring(valueIndex, i));
valueIndex = i + 1;
}
else if(i == value4.length() - 1){
value4Array.add(value4.substring(valueIndex, value4.length()));
}
}
return value4Array;
}
if(someCondition4){
List<String> value4Array = parseValue4(queryParams.value4);
sqlQuery.append("And column4 IN ("); /* base AND statement */
for(int i = 0; i < value4Array.size(); i++){
if(i == value4Array.size() - 1)
sqlQuery.append("?)");
else /* dynamically appending ?'s */
sqlQuery.append("?,");
queryArgs.add(value4Array.get(i));
}
}
You are taking list of string type (List<String> queryArgs = new ArrayList<>();).
What if the parameter is an integer type? Is there any way to store multiple typle of data?

split function to change order

i used a methode to get treepath i get it like this
[dc=example,dc=com,ou=Usres] and i need to make it look like this
ou=Usres,dc=example,dc=com
so i tried this methode to change the order
public static String changeString(String old)
{
old = old.replace('[', ' ');
old = old.replace(']', ' ');
old.trim();
String array[] = old.split(",");
String result = "";
for (int i = 1; i <= array.length; i++) {
if(i != 1)
result +=","+ array[array.length-i];
else
result += array[array.length-i];
}
but i get the like this ou=Usres,dc=com,dc=example
how can i do to change only the position of ou=users
If you are using Java, I would suggest you use the UnboundID SDK. Using the DN class, you can break down the items with public RDN[] getRDNs(), which returns a RDN[]
Then you could simply reorder the RDN[] and then create the new DN with DN(RDN... rdns).

DataContext.ExecuteQuery<object> returns object {}

I'm trying to write function for selecting optional columns in linq(columns that may not exist). The problem is in linq like this:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? t.B : -1; //this is optional column
}}
Unfortunately, this won't work because the fragment near Optional will be translated to case statement and error arises that column not exists.
So i decided to "cover" it with function:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? OptionalColumnValue<int>("table","B","id_table",t.id_table) : -1; //this is optional column
}}
I want this function to be universal. It should work like that" If there is no value or column is nullable and value is null then return default value for type.
I came up with something like this:
//table,column - obvious,id_column - PK column of table, id - id of currently processing record
public static T OptionalColumnValue<T>(string table,string column,string id_columm,int id) T t = default(T);
DataDataContext db = new DataDataContext();
IEnumerable<object> value = db.ExecuteQuery<object>("select " + column + " from " + table + " where " + id_columm + " = " + id.ToString());
List<object> valueList = value.ToList();
if (valueList.Count == 1)//here is the problem
t = (T)valueList.First();
return t;
}
When there is null value db.ExecuteQuery return something like object{}. I'm assuming this is "empty" object,with nothing really in there. I was thinking about checking for "emptiness" of this object( BTW this is not DBull).
When i realised that this is no way either with concrete value in this column(it cannot cast it to return correct type), then I tried db.ExecuteQuery<T>. Then concrete value - OK, null - Exception.
I thought, maybe Nullable<T> as return value. Nop, because string also can be T.
I don't know what to do next. Maybe there's another solution to this problem.

hibernate how to assign ParameterList for the IN clause

I need to use the IN clause in the SQL sentence.
I have data in one table with the type on Int(11).
And Y have a String from another table that is the criteria.
For example, in table A i have the value 3 of type Int.
In table/process B i have the String "0123".
I need to query table A to meet this criteria:
Select * from Table A where attrib_1 IN (0,1,2,3)
Because record n have value 3, it should be returned.
So i'm trying to use .setParameterList, like this:
List<BloqueCruzamiento> bloques = session.createQuery("FROM BloqueCruzamiento AS b WHERE b.anio=:anio AND b.activo=true AND b.grupo=:categoria AND b.pr IN(:pr_set)ORDER BY b.nroParcela, b.cruza, b.pedigree")
.setParameter("anio", grupo.getAnio())
.setParameter("categoria", grupo.getCategoria())
.setParameterList("pr_set", pr_parm)
.list();
the quid is on "pr_set" parameter.
I want to know how to convert a String , "0123", to a Collection of Integers (0,1,2,3).
So I can pass this parameter to setParameterList() method.
Anapproach that I'm right now is to convert the String to a Char Array, then loop, and convert each element into an Integer Array.
Can somebody give anothe solution ?
Regards
you can use code below to get list from String
String s = "0123";
List<Integer> pr_parm = new ArrayList<Integer>();
for(int i=0;i<s.length();i++) {
if (Character.isDigit(s.charAt(i))) {
pr_parm.add(Integer.parseInt(String.valueOf(s.charAt(i))));
}
}
System.out.println(pr_parm);
Then you can use the list in your setParameterList("pr_set", pr_parm)
this was the solution.
String[] sele = grupo.getPr_sel().split(",");
Integer[] pr_parm_int = new Integer[sele.length];
for (int x=0; x<sele.length;x++){
pr_parm_int[x] = Integer.valueOf(sele[x]);
}
the first line is to parse the string and strip comas.