Is there a way to retrieve the raw query string being generated from a call like the following? I'm trying to figure out how the "?" placeholders get populated.
Cursor cursor = database.query(
adapter.getTable(), // The table to query - String
adapter.getColumns(), // The columns to return - String[]
adapter.getWhereClause(), // The columns for the WHERE clause - String
adapter.getWhereClauseArgs(), // The values for the WHERE clause - String[]
null, // Group by - String
null, // Groups having - String
adapter.getSortBy(), // The sort order - String
adapter.getLimit()); // The limit - String
I'm curious of the order of operations. For example, if the above query translated to the select below with the whereClause args below, would i get result1 or result2? Does it work like the order of operations in math, where statements in parenthesis get executed first? or does it strictly rely on the position of the "?"'s in the string.
String select = "SELECT * FROM table1 WHERE someField = ? AND _id in(SELECT _id FROM table2 WHERE status = ?)";
String[] args = new String[]{ "blue", "active" };
String result1 = "SELECT * FROM table1 WHERE someField = 'blue' AND _id in(SELECT _id FROM table2 WHERE status = 'active')";
String result2 = "SELECT * FROM table1 WHERE someField = 'active' AND _id in(SELECT _id FROM table2 WHERE status = 'blue')";
A quick test will show that it substitutes selection args by the position in the string, without any concept of order of operations.
Related
I am working on a project and created a database with SQLite. In my database I have just two columns, column names are r_id and m_id. I want to take the first element of the r_id and assign it in to a string. The elements of the r_id column is like 1, 2, 3.. in this situation my String has to be 1.
My code; creating a db query:
There is no problem I can add data correcly.
my_table = "CREATE TABLE "my_table"("r_id" Text, "m_id" Text);";
db.execSQL(my_table );
Code to take the first element of the column;
public String getSetting() {
String result = "";
String[] columns = {"r_id"};
String[] selectionArgs = {"1"};
String LIMIT = String.valueOf(1); // <-- number of results we want/expect
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor c = db.query(true, "r_id", columns, "row", selectionArgs, null, null, null, LIMIT);
if (c.moveToFirst()) {
result = result + c.getString(0);
} else {
result = result + "result not found";
}
c.close();
databaseHelper.close();
return result;
}
The error I am getting:
android.database.sqlite.SQLiteException: no such column: row (code 1 SQLITE_ERROR): , while compiling: SELECT DISTINCT r_id FROM my_table WHERE row LIMIT 1
The 4th argument of query() is the WHERE clause of the query (without the keyword WHERE) and for it you pass "row".
Also, the 2nd argument is the table's name for which you pass "r_id", but the error message does not contain ...FROM r_id... (although it should), so I guess that the code you posted is not your actual code.
So your query (translated in SQL) is:
SELECT DISTINCT r_id FROM my_table WHERE row LIMIT 1
which is invalid.
But you don't need a WHERE clause if you want just the min value of the column r_id.
You can do it with a query like:
SELECT MIN(r_id) AS r_id FROM my_table
without DISTINCT and a WHERE clause.
Or:
SELECT r_id FROM my_table ORDER BY r_id LIMIT 1;
So your java code should be:
public String getSetting() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor c = db.rawQuery("SELECT MIN(r_id) AS r_id FROM my_table", null);
String result = c.moveToFirst() ? c.getString(0) : "result not found";
c.close();
databaseHelper.close();
return result;
}
I used rawQuery() here instead of query().
Or:
public String getSetting() {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor c = db.query(false, "my_table", new String[] {"r_id"}, null, null, null, null, "r_id", "1");
String result = c.moveToFirst() ? c.getString(0) : "result not found";
c.close();
databaseHelper.close();
return result;
}
I am trying to generate sql query based on user input. There are 4 search fields on the UI:
FIRST_NAME, LAST_NAME, SUBJECT, MARKS
Based on user input I am planning to generate SQL query. Input can be of any combination.
eg: select * from TABLE where FIRST_NAME="some_value";
This query needs to be generated when FIRST_NAME is given and other fields are null
select * from TABLE where FIRST_NAME="some_value" and LAST_NAME="some_value";
This query needs to be generated when FIRST_NAME and LAST_NAME are given and other fields are null
Since there are 4 input fields, number of possible queries that can be generated are 24 (factorial of 4).
One idea is to write if condition for all 24 cases.
Java pseudo code:
String QUERY = "select * from TABLE where ";
if (FIRST_NAME!=null) {
QUERY = QUERY + "FIRST_NAME='use_input_value';"
}
if (LAST_NAME!=null) {
QUERY = QUERY + "LAST_NAME='use_input_value';"
}
if (SUBJECT!=null) {
QUERY = QUERY + "SUBJECT='use_input_value';"
}
if (MARKS!=null) {
QUERY = QUERY + "MARKS='use_input_value';"
}
I am not able to figure out how to generate SQL queries with AND coditions for multiple Input values.
I have been through concepts on dynamically generate sql query but couldn't process further.
Can someone help me on this.
FYI: I have been through How to dynamically generate SQL query based on user's selections?, still not able to generate query string based on user input.
Let's think about what would happen if you just ran the code you wrote and both FIRST_NAME and LAST_NAME are provided. You'll wind up with this:
select * from TABLE where FIRST_NAME='use_input_value';LAST_NAME='use_input_value';
There are two problems here:
The query is syntactically incorrect.
It contains the literals 'use_input_value' instead of the values you want.
To fix the first problem, let's first add and to the start of each expression, and remove the semicolons, something like this:
String QUERY = "select * from TABLE where";
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME='use_input_value'";
}
Notice the space before the and. We can also remove the space after where.
Now the query with both FIRST_NAME and LAST_NAME will look like this:
select * from TABLE where and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value'
Better but now there's an extra and. We can fix that by adding a dummy always-true condition at the start of the query:
String QUERY = "select * from TABLE where 1=1";
Then we append a semicolon after all the conditions have been evaluated, and we have a valid query:
select * from TABLE where 1=1 and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value';
(It may not be necessary to append the semicolon. Most databases don't require semicolons at the end of a single query like this.)
On to the string literals. You should add a placeholder instead, and simultaneously add the value you want to use to a List.
String QUERY = "select * from TABLE where";
List<String> args = new ArrayList<>();
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME=?";
args.add(FIRST_NAME);
}
After you've handled all the conditions you'll have a string with N '?' placeholders and a List with N values. At that point just prepare a query from the SQL string and add the placeholders.
PreparedStatement statement = conn.prepareStatement(QUERY);
for (int i = 0; i < args.size(); i++) {
statement.setString(i + 1, args[i]);
}
For some reason columns and parameters are indexed starting at 1 in the JDBC API, so we have to add 1 to i to produce the parameter index.
Then execute the PreparedStatement.
I have written a function that I would like to call in Java. But I don't think it is able to do anything with the query that I passed. Following is my code from java:
String QUERY_LOCATION = "select (license_plate) as test from carInst( (select category_name from reservation where rid = ?) , (select lname from reservation where rid = ?))";
//PreparedStatement check_location = null;
PreparedStatement check_location = connection.prepareStatement(QUERY_LOCATION);
check_location.setInt(1, rid);
check_location.setInt(2, rid);
rs = check_location.executeQuery();
if (rs.next()) {
System.out.print("Car found: "+rs.getString("test")+"\n");
license_plate = rs.getString("test");
update_reservation.setString(5, license_plate);
bool = false;
} else {
System.out
.print("There is no car available\n");
}
And following is my stored procedure written in PL/pgSQL (PostgreSQL):
CREATE OR REPLACE FUNCTION carInst(cname varchar(20), loc varchar(20) )
RETURNS TABLE (license_plate varchar(6) ) AS $$
BEGIN
DECLARE cur CURSOR
FOR SELECT carinstance.license_plate, carmodel.category_name, carinstance.lname FROM carinstance,carmodel
WHERE carinstance.mid = carmodel.mid ;
BEGIN
FOR rec IN cur LOOP
RETURN QUERY SELECT distinct carinstance.license_plate FROM Carinstance
WHERE rec.category_name = cname
AND rec.lname = loc
AND rec.license_plate=carinstance.license_plate;
END LOOP;
END;
END;
$$ LANGUAGE plpgsql;
When I run the code in Java, the print statement prints a null value for Car found. I would really appreciate some help here.
Problems
Most importantly, the query in the LOOP is nonsense. You select rows from carinstance, but all conditions are on rec. This select all rows multiple times.
One END too many. FOR has no END, only LOOP has.
Whenever you feel the temptation to work with an explicit cursor in plpgsql, stop right there. Chances are, you are doing it wrong. A FOR loop has an implicit cursor anyway.
Don't mess with mixed case identifiers without double quotes. I converted all identifiers to lower case.
You use one simple query, spread out over a cursor and another query. This can all be much simpler.
Solution
Try this simple SQL function instead:
CREATE OR REPLACE FUNCTION car_inst(_cname text, _loc text)
RETURNS TABLE (license_plate text)
LANGUAGE sql AS
$func$
SELECT DISTINCT ci.license_plate
FROM carmodel cm
JOIN carinstance ci USING (mid)
WHERE cm.category_name = $1
AND ci.lname = $2
$func$;
Call:
SELECT license_plate AS test FROM car_inst(
(SELECT category_name FROM reservation WHERE rid = ?)
, (SELECT lname FROM reservation WHERE rid = ?)
);
Or build it all into your function:
CREATE OR REPLACE FUNCTION car_inst(_cname text, _loc text)
RETURNS TABLE (license_plate text)
LANGUAGE sql AS
$func$
SELECT DISTINCT ci.license_plate
FROM carmodel cm
JOIN carinstance ci USING (mid)
JOIN reservation r1 ON r1.category_name = cm.category_name
JOIN reservation r2 ON r2.lname = ci.lname
WHERE r1.rid = $1
AND r2.rid = $2;
$func$;
Call:
"SELECT license_plate AS test FROM car_inst(? , ?)";
Remember: The OUT parameter license_plate is visible anywhere in the body of the function. Therefore you must table-qualify the column of the same name at all times to prevent a naming collision.
DISTINCT may or may not be redundant.
I have a database table with multiple columns
I use custom List<> and populate it from database
What i want to do is filter what will go into the list from database depending on user input
for example if i had a table like this:
name|phone|date|address
User can specify any filter(by name, by phone, by date... or all of it) and only items that matches all criteria will go into the list
Is there a way to do this?
Method that returns all items from database
public List<MoviesDatabaseEntry> getAllMovies(String table)
{
List<MoviesDatabaseEntry> lists = new ArrayList<MoviesDatabaseEntry>();
// Select All Query
String selectQuery = "SELECT * FROM " + table;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst())
{
do {
MoviesDatabaseEntry list = new MoviesDatabaseEntry();
list.set_id(Integer.parseInt(cursor.getString(0)));
list.set_title(cursor.getString(1));
list.set_runtime(cursor.getString(2));
list.set_rating(cursor.getDouble(3));
list.set_genres(cursor.getString(4));
list.set_type(cursor.getString(5));
list.set_lang(cursor.getString(6));
list.set_poster(cursor.getString(7));
list.set_url(cursor.getString(8));
list.set_director(cursor.getString(9));
list.set_actors(cursor.getString(10));
list.set_plot(cursor.getString(11));
list.set_year(cursor.getInt(12));
list.set_country(cursor.getString(13));
list.set_date(cursor.getInt(14));
// Adding to list
lists.add(list);
} while (cursor.moveToNext());
}
// return list
db.close();
cursor.close();
return lists;
}
You can filter the entries you get in the SQL query you are building in this line:
String selectQuery = "SELECT * FROM " + table;
To filter the dataset your retrieve, you would add a WHERE clause to it. When you would, for example, only want those entries where the rating is over 3, you would change this to:
String selectQuery = "SELECT * FROM " + table + " WHERE rating > 3";
SQL is a very powerful language which offers a lot of possibilities. It's an essential skill when you work with relational databases. When you want to learn it, I can recommend you the interactive tutorial website http://sqlzoo.net/
You have to change your database query for getting specific data from the query.
You have one function that returns all rows from database like so: getAllMovies(String table)
Here you are using:
String selectQuery = "SELECT * FROM " + table;
Make a new function like this:
public List<MoviesDatabaseEntry> getSelectedMovies(String table)
{
List<MoviesDatabaseEntry> lists = new ArrayList<MoviesDatabaseEntry>();
Cursor cursor = db.query(true, TABLE_NAME, new String[] { <your row names> },
**check condition(as string)**, null,
null, null, null, null);
...
}
Now just call this function when required with your specific query string
Make as many functions as you want!
I'm having a rawQuery() with following sql string similar to this:
selectionArgs = new String[] { searchString };
Cursor c = db.rawQuery("SELECT column FROM table WHERE column=?", selectionArgs);
but now I have to include a wildcard in my search, so my query looks something like this:
SELECT column FROM table WHERE column LIKE 'searchstring%'
But when the query contains single quotes the following SQLite Exception is thrown: android.database.sqlite.SQLiteException: bind or column index out of range
How can I run a rawQuery with selectionArgs inside a SQL query with wildcard elements?
You have to append the % to the selectionArgs itself:
selectionArgs = new String[] { searchString + "%" };
Cursor c = db.rawQuery("SELECT column FROM table WHERE column=?", selectionArgs);
Note: Accordingly % and _ in the searchString string still work as wildcards!
The Sqlite framework automatically puts single-quotes around the ? character internally.
String [] selectionArgs = {searchString + "%"};
Cursor c;
// Wrap the next line in try-catch
c = db.rawQuery("SELECT column FROM table WHERE like ?", selectionArgs);
That's it.
Brad Hein's and Mannaz's solution did not work for me, but this did:
String query = "SELECT column FROM table WHERE column=%s";
String q = String.format(query, "\""+searchString + "%\"");
Cursor c = db.rawQuery(q, null);