Android Sqlite Inner Join - java

I'm trying to get this
I have 2 tables - Words Table (ID, NAME, TRANSLATION) and WordSynonym Table(synonym_id1, synonym_id2).
All my words are going into first table, and when I need I am creating connection between words via second table.
Now I need to make method to get all synonyms by specific id.
For that I have tried this.
#Override
public ArrayList<Word> getAllSynonymsByWord(int id) {
ArrayList<Word> synonyms = new ArrayList<>();
Cursor c = database.rawQuery("select id, word, translation from " + WordsTable.TABLE_NAME + " inner join " + WordSynonymTable.TABLE_NAME + " on " + WordSynonymTable.COLUMN_WORD_ID + " = " + id, null);
c.moveToFirst();
while (!c.isAfterLast()) {
Word s = new Word();
s.setId(c.getInt(0));
s.setName(c.getString(1));
s.setTranslation(c.getString(2));
synonyms.add(s);
c.moveToNext();
}
c.close();
return synonyms;
}
Parameter ID is id of the word I need (id = 1 in picture)
I want to return words with id = 2 and id = 3 for example
but this is not working properly.
What should I change?
If you need another part of code comment and I will add.

You need to join the words table two times:
SELECT W2.ID,
W2.Name,
W2.Translation
FROM Words
JOIN WordSynonym ON Words.ID = WordSynonym.Synonym_ID1
JOIN Words AS W2 ON WordSynonym.Synonym_ID2 = W2.ID
WHERE Words.ID = ?;

Related

How to load data associated with a specific item from SQLite Android Database?

On the click of X semester I want my app to load the classes associated with that specific semester, which I'm trying to do with the following piece of code:
public void openSemestersActivity() {
final Intent semester = new Intent(this, SemesterActivity.class);
semesterListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// This works if nothing is deleted. If something is deleted we would have to add another +1 to the position
semester.putExtra("semester", db.getSemesterNameString(position + 1));
Log.d("Semester Name", db.getSemesterNameString(position + 1));
startActivity(semester);
}
});
}
Now, I want to load the classes associated with that specific semester on the SemesterActivity, which I'm trying to do with the following code:
// Retrieving the Extra and determining the semester we want to load
Intent myIntent = getIntent();
String semester = myIntent.getStringExtra("semester");
// Creating the Database and loading the ListView
db = new DataBaseHelperC(this);
myCourses.addAll(db.getAllCoursesForThisSemester(semester));
customCourseAdapter = new CourseAdapter(getApplicationContext(), R.layout.course_row, myCourses);
courseListView.setAdapter(customCourseAdapter);
customCourseAdapter.notifyDataSetChanged();
This is the method, located on my DatabaseHelper class, that's supposed to get all the courses for that specific semester:
public List<Course> getAllCoursesForThisSemester(String semester) {
List<Course> courses = new ArrayList<>();
// Select all query
String selectQuery = "SELECT * FROM " + Course.TABLE_NAME + " ORDER BY " + Course.COLUMN_ID + " ASC";
SQLiteDatabase db = this.getWritableDatabase();
#SuppressLint("Recycle") Cursor cursor = db.rawQuery(selectQuery, null);
// Looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Course course = new Course();
course.setNameOfCourse(cursor.getString(cursor.getColumnIndex(Course.COLUMN_COURSE)));
course.setCodeOfCourse(cursor.getString(cursor.getColumnIndex(Course.COLUMN_COURSECODE)));
course.setCreditsOfCourse(cursor.getString(cursor.getColumnIndex(Course.COLUMN_COURSECREDITS)));
course.setNameOfBackground(cursor.getString(cursor.getColumnIndex(Course.COLUMN_BACKGROUND)));
course.setId(cursor.getInt(cursor.getColumnIndex(Course.COLUMN_ID)));
courses.add(course);
}
while (cursor.moveToNext());
}
// Close db connection
db.close();
return courses;
}
I'm passing a String semester as parameter, but can't figure out how to actually use this parameter to only get the courses for that specific semester. This is my first time working with a Database and it is worth noting that I'm having a hard time with it and haven't gotten the hang of it just yet so any help would be really appreciated since I've been stuck here for around 2 weeks now.
Right now, by using the code that I currently have, if I add a course in X semester and then open Y semester, the courses added on X semester are loaded on the Y semester too. This is what I'm trying to fix with that method that receives a String semester as parameter.
The sql statement:
SELECT * FROM " + Course.TABLE_NAME + " ORDER BY " + Course.COLUMN_ID + " ASC"
needs a WHERE clause.
If the column containing the semester has a name like semester, you can do it like this:
String selectQuery = "SELECT * FROM " + Course.TABLE_NAME +
" WHERE semester = ?" + // replace with the actual column name
" ORDER BY " + Course.COLUMN_ID + " ASC";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, new String[] {semester});

Android SQLite rawQuery - How to select multiple rows of a table

I'm trying to use rawQuery to return a cursor with a few different rows of data to be passed into it. When there is only 1 argument it works. When there is more than 1 argument it displays the empty ListView state. I believe the issue lies here:
// Query for items from the database and get a cursor back. Edited code for clarity:
recipeCursor = db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id = ?",
selectedRecipesSQL);
When the code works the selectedRecipesSQL would look something like:
String[] selectedRecipesSQL;
selectedRecipesSQL = new String[]{"2"};
And when it doesn't work it would be something like
String[] selectedRecipesSQL;
selectedRecipesSQL = new String[]{"2 OR 5"};
So, to be clear, I can display a single row of the table in my ListView, but if I try to display more than one row of the table then it won't display anything.
One ugly solution which has crossed my mind (but I haven't pursued) is that I need to edit the rawQuery selection statement to read something like:
recipeCursor = db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id = ? OR _id = ? OR _id = ?",
selectedRecipesSQL);
I'd probably use a for loop to generate the correct amount of WHERE "_id = ?" and then use a string array:
selectedRecipesSQL = new String[]{"2", "5"};
One way of doing it is by passing the possible values of _id as 1 string which is a comma separated list like this:
selectedRecipesSQL = new String[]{"1,2,3"};
and in your query use the operator LIKE:
recipeCursor = db.rawQuery(
"SELECT course, name, _id FROM recipes WHERE ',' || ? || ',' LIKE '%,' || _id || ',%'",
selectedRecipesSQL
);
This works also for just 1 value.
static String multiply__concat_string(String text,String joiner_,int multiple_)
{
String output="";
for(int i=0;i<multiple_;i++)
{
output+=(text+joiner_);
}
if(output.length()>0)
{
output=output.substring(0,output.length()-1);
}
return output;
}
Use it like this :
selectedRecipesSQL = new String[]{"2", "5"};
db.rawQuery("SELECT course, name, _id " +
" FROM recipes WHERE _id IN("+multiply_concat_string("?",",",selectedRecipesSQL.length)+")",
selectedRecipesSQL);

Never entering in cursor.moveToNext() in Android SQLite

I'm trying Official Documentation for Android this article. Creating Database, Table and inserting data is working fine. But I'm unable to get data from database. Here is the piece of code to retrieve data from table.
public Person searchDataInDB(String personCellString) {
SQLiteDatabase db = getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
PersonTable.COLUMN_NAME_ID,
PersonTable.COLUMN_NAME_NAME,
PersonTable.COLUMN_NAME_CELL_NO,
PersonTable.COLUMN_NAME_ADDRESS
};
// Filter results WHERE "cell#" = 'Person Cell #'
String selection = SQLiteDBHelper.PersonTable.COLUMN_NAME_CELL_NO + " = ?";
String[] selectionArgs = {"'" + personCellString + "'"};
// How you want the results sorted in the resulting Cursor
// String sortOrder = SQLiteDBHelper.PersonTable.COLUMN_NAME_ID + " DESC";
Cursor cursor = db.query(
SQLiteDBHelper.PersonTable.TABLE_NAME, // The table to query
null, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
null // The sort order
);
String [] names = cursor.getColumnNames();
Log.e("SQLiteDB", "cursorCount = " + cursor.getCount() + ", cursorColumnCount = " + cursor.getColumnCount() + ", Column = " + names[0]);
Person person = null;
while (cursor.moveToNext()) {
int id = (int) cursor.getLong(
cursor.getColumnIndexOrThrow(PersonTable.COLUMN_NAME_ID));
Log.e("SQLiteDB", "moveToNext id = " + id);
String name = cursor.getString(
cursor.getColumnIndexOrThrow(SQLiteDBHelper.PersonTable.COLUMN_NAME_NAME));
Log.e("SQLiteDB", "moveToNext name = " + name);
String cellNo = cursor.getString(
cursor.getColumnIndexOrThrow(SQLiteDBHelper.PersonTable.COLUMN_NAME_CELL_NO));
Log.e("SQLiteDB", "moveToNext cell = " + cellNo);
String address = cursor.getString(
cursor.getColumnIndexOrThrow(SQLiteDBHelper.PersonTable.COLUMN_NAME_ADDRESS));
Log.e("SQLiteDB", "moveToNext address = " + address);
person = new Person(id, name, cellNo, address);
}
cursor.close();
return person;
}
It seems like my app does not enter in while loop i.e. while(cursor.moveToNext() So this method always returns initial value of person which is null. As a result, the first condition is always true from below code
Person person = dbHelper.searchDataInDB(personCellString);
if (person == null) {
Toast.makeText(mContext, "no such record exists in database!", Toast.LENGTH_LONG).show();
} else {
String personDetails = "Name = " + person.getName()
+ "Cell Number = " + person.getCellNumber()
+ "Address = " + person.getAddress();
personDetailsTV.setText(personDetails);
}
I'm using DB Browser for SQLite so I can see the records are successfully adding in the database.
What should I do with the above code to make it work?
What you are doing with this:
String[] selectionArgs = {"'" + personCellString + "'"};
is searching for the string value of personCellString enclosed inside single quotes and not for the actual value of the string personCellString.
Remove the single quotes:
String[] selectionArgs = {personCellString};
You don't have to worry about the string representation of personCellString in the final sql statement that will be constructed and executed which will contain them without explicitly setting them.

Storing data from an entire row, Android SQLite

So I have a method that allows me to get the id of a certain item by using a name i already have in an SQL Database. How would I go about getting the entire row of information and storing each item in its own variable.
Method that only works with ID
public Cursor getID(String name){
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String query = " SELECT " + COL1 + " FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = sqLiteDatabase.rawQuery(query, null);
return data;
}
And the method that gets the query and stores the result
Cursor data = mydb2.getID(name);
int itemId= -1;
while(data.moveToNext()){
itemId = data.getInt(0);
}
Using this method below how would i store all of the data in its own variable using this (or any other way to get data of entire row).
public Cursor rowData(String name){
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String query = " SELECT * FROM " + TABLE_NAME + " WHERE " + COL2 + " = '" + name + "'";
Cursor data = sqLiteDatabase.rawQuery(query, null);
return data;
}
I know this might be a dumb question, and I have tried looking at other questions, I have gotten this far I just don't know what to do next (I'm very new to Sq Lite databases and Android development)
You'd use something like :-
Cursor csr = instance_of_yourdbhelper.rowData();
while(csr.moveToNext()) {
long thisItemId = csr.getLong(csr.getColumnIndex(yourdbhelper.COL_1));
String thisName = csr.getString(csr.getColumnIndex(yourdbhelper.COL_2));
// etc for other columns
}
Notes
yourdbhelper is the class for your DatabaseHelper which is the class that extends SQLiteOpenHelper (the assumption is that the above methods are from such a class, as this is a common usage of SQLite)
instance_of_yourdbhelper is the instance of the DatabaseHelper class i.e. you may have yourdbhelper dbhlpr = new yourdbhelper(parameters);, in which case dbhlpr is the instance.
This just overwrites the same variables (thisItemId and thisName) for each row in the cursor, although there is perhaps the likliehood that the rowData method only returns one row.
You will likely encounter fewer errors using the getColumnIndex method as it returns the offset according to the column name. Miscalculated offsets is a frequent cause of problems.
You may wish to handle a no rows returned situation in which case you can use cursor.getCount(), which will return the number of rows in the cursor.

Obtaining a count of data from one SQL table with a relationship to another and using this in java

I have 2 database tables for my program: GameInfo and Characters.
How this works is that a Game has 4 maps with different names and each character added to the game must be assigned any of the 4 maps. Now I have the sql statement which returns a result set named "Expr1001, of the number of characters on each map. I then need to add this information to a jTable and link up the corresponding amount of each characterson a map, with the mapname.
My ResultSet with the query which returns the amount of characters on each map:
ResultSet qs = dbm.queryDatabase("SELECT Expr1001 FROM (SELECT GameInfo.mapname, SUM(IIF(Map = GameInfo.mapname,1,0)) FROM (SELECT * FROM [Character] INNER JOIN Player ON Character.PlayerID=Player.[ID]) AS A RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname GROUP BY GameInfo.mapname) AS [%$###_Alias]");
The whole method which gets the Game Info from the database from the GameInfo table, which comprises of a GameID and MapName only.
public Game[] getGameInfo(){
Game[] arr = null; //Creates an array of Games
try { //getting list from database
ResultSet rs = dbm.queryDatabase("Select Count(GameID) as NumGames from GameInfo" );
//While there are still more rows to read from the database.
rs.next();
int count = rs.getInt("NumGames");
arr = new Game[count];
String sql = "Select * from GameInfo";
// System.out.println(sql);
rs = dbm.queryDatabase(sql);
//Take the info from the current row
//Add the info to the array
ResultSet qs = dbm.queryDatabase("SELECT Expr1001 FROM (SELECT GameInfo.mapname, SUM(IIF(Map = GameInfo.mapname,1,0)) FROM (SELECT * FROM [Character] INNER JOIN Player ON Character.PlayerID=Player.[ID]) AS A RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname GROUP BY GameInfo.mapname) AS [%$###_Alias]");
for(int i = 0; rs.next(); i++){
arr[i] = new Game(
rs.getInt("GameInfo.GameID"),
rs.getString("GameInfo.mapname"),
qs.getInt(i));
}//Creates a Game from the currently selected info
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Failed to get Games");
e.printStackTrace();
}
return arr;
}
}
The data is then added to the jTable which is on a Panel in the GameInfoPanel class:
public void refreshTable() {
//remove old stuff
refreshing = true;
Game[] arr = gim.getGameInfo();
DefaultTableModel model = (DefaultTableModel) GameInfoTable.getModel();
while (model.getRowCount() > 0) {
model.removeRow(0);
}
for (int i = 0; i < arr.length; i++) {
model.addRow(new Object[]{
arr[i].getNumberOfCharacters(),
arr[i].getID(),
arr[i].getMapName()});
}
refreshing = false;
//load new data from database using manager
}
I keep getting the error which points to the ResultSet qs line: "user lacks privilege or object not found: A.CHARACTER.MAP" when I try and run the program even though when I copy this statement into Microsoft Access and run it, it's fine.
Help please!
Thanks.
(I am still at school so not really a genius on this at all so please have mercy if I've done some stupid things)
Don't run a select count(*) first to get the number of games for allocating an array. Build you result in a List, which will auto-expand as needed. You can always convert the list to an array later, if needed.
Don't run two queries when one can do the job, especially when you already join to the table in question.
Your SQL is unreadable, so here it is in a more readable format:
String sql = "SELECT Expr1001" +
" FROM (SELECT GameInfo.mapname" +
", SUM(IIF(Map = GameInfo.mapname,1,0))" +
" FROM (SELECT *" +
" FROM [Character]" +
" INNER JOIN Player ON Character.PlayerID=Player.[ID]" +
") AS A" +
" RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname" +
" GROUP BY GameInfo.mapname" +
") AS [%$###_Alias]";
The outer query does nothing. Get rid of it.
Don't SELECT *. Select the columns you want, i.e. Character.map.
Since you want GameID, add it to the GROUP BY.
Specify an alias for the SUM value.
public Game[] getGameInfo(){
String sql = " SELECT GameInfo.GameID" +
", GameInfo.mapname" +
", SUM(IIF(C.map = GameInfo.mapname,1,0)) AS CharacterCount" +
" FROM ( SELECT Character.map" +
" FROM [Character]" +
" JOIN Player ON Player.[ID] = Character.PlayerID" +
") C" +
" RIGHT JOIN GameInfo ON GameInfo.mapname = C.map" +
" GROUP BY GameInfo.GameID" +
", GameInfo.mapname";
try (ResultSet rs = dbm.queryDatabase(sql)) {
List<Game> games = new ArrayList<>();
while (rs.next())
games.add(new Game(rs.getInt("GameID"),
rs.getString("mapname"),
rs.getInt("CharacterCount")));
return games.toArray(new Game[games.size()]);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Failed to get Games");
e.printStackTrace();
return null;
}
}

Categories

Resources