Related
I have a problem when I want to record into Room database my JSON.
My data class is:
data class CurrentWeatherEntry(
#SerializedName("temperature")//
val temperature: Int,
#SerializedName("weather_code")
val weatherCode: Int,
#SerializedName("weather_icons")
val weatherIcons: List<String>,
)
{
#PrimaryKey(autoGenerate = false)
var id : Int = CURRENT_WEATHER_ID
}
I get error: Cannot figure out how to save this field into database. You can consider adding a type
converter for it.
private final java.util.List<java.lang.String> weatherIcons = null;
How to create converter?
object Converter {
private val gson = Gson()
private val listTypeConverter = object : TypeToken<List<String>>() {}.type
#TypeConverter
#JvmStatic
fun fromListToIcon(list: List<String>): String = gson.toJson(list, listTypeConverter)
#TypeConverter
#JvmStatic
fun fromIconToList(icon: String): List<String> = gson.fromJson(icon, listTypeConverter)
}
Then add #TypeConverters(Converter::class) at the top of your DataBase:
#TypeConverters(Converter::class)
abstract class YourDB : RoomDatabase()
I've been stuck on this problem for a while now, and I can't seem to figure out what's wrong. I'm trying to create a database table, insert values into the table, and check to see if the email already exists. At first, it was at least telling me that the values were being inserted, now, the app only stops.
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "People.db";
public static final String TABLE_NAME = "user";
public static final String COL1 = "email";
public static final String COL2 = "password";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + "(" +
COL1 + "TEXT PRIMARYKEY," +
COL2 + "TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
/*Inserting into database*/
public boolean add(String email, String password) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
to database
contentValues.put(COL1, email);
contentValues.put(COL2, password);
long ins = db.insert(TABLE_NAME, null, contentValues);
if (ins == -1) return false;
else return true;
}
/*checking if email exist*/
public Boolean chkemail(String email) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * from TABLE_NAME where email = ?",
new String[]{email});
if (cursor.getCount() > 0) return false;
else return true;
}
}
This is the SignUp activity that inserts and checks the information.
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.powell.randomeats.MainActivity;
import com.powell.randomeats.R;
public class SignUp extends AppCompatActivity {
DatabaseHelper db;
EditText email, pass, pass1;
Button sign;
boolean optionsSwitch;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
db = new DatabaseHelper(this);
email = (EditText) findViewById(R.id.Email);
pass = (EditText) findViewById(R.id.Password);
pass1 = (EditText) findViewById(R.id.Confirm);
sign = (Button) findViewById(R.id.Signup);
sign.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String s1 = email.getText().toString();
String s2 = pass.getText().toString();
String s3 = pass1.getText().toString();
if (s1.equals("") || s2.equals("") || s3.equals("")) {
Toast.makeText(getApplicationContext(), "Fields are empty",
Toast.LENGTH_SHORT).show();
} else {
if (s2.equals(s3)) {
Boolean chkemail = db.chkemail(s1);
if (chkemail == true) {
Boolean insert = db.add(s1, s2);
if (insert == true) {
Toast.makeText(getApplicationContext(),
"Registered Succesfully",
Toast.LENGTH_SHORT).show();
Log();
if (optionsSwitch == true) {
openLog();
}
}
} else {
Toast.makeText(getApplicationContext(), "Email
Already exists,", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "Passwords do
not match", Toast.LENGTH_SHORT).show();
}
}
}
});
}
public void Log() {
optionsSwitch = true;
}
public void openLog() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
}
Your issue(s)
I believe that the table is being created. However, not with the expected column names.
That is due to spaces being admitted the create statement resolves to :-
CREATE TABLE user (emailTEXT PRIMARYKEY, passwordTEXT);
As such the table will have columns emailTEXT rather than email and passwordText rather than password.
This will cause issues when attempt to use columns email and password as those columns do not exist.
Additional PRIMARYKEY is not a valid keyword so changing the create statement to
CREATE TABLE user (email TEXT PRIMARYKEY, password TEXT);
Will create the table with the correct columns BUT the email column would not reject duplicate values.
So you'd need to add a space between PRIMARY and KEY thus the create should be :-
CREATE TABLE user (email TEXT PRIMARY KEY, password TEXT);
Suggested Fix
Your code could be changed to :-
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + "(" +
COL1 + " TEXT PRIMARY KEY," +
COL2 + " TEXT)");
}
Note that onCreate will not be invoked unless the database is deleted or it is forced to be invoked, so you could do one of the following :-
Delete the App's data (deletes the database).
uninstall the App (deletes the database).
Increase the database version (4th parameter of the call to the super e.g. use super(context, DATABASE_NAME, null, 2); (1 changed to 2)) (causes the onUpgrade method to be invoked and thus the table is dropped and then onCreate is invoked.).
Change this line:
Cursor cursor = db.rawQuery("SELECT * from TABLE_NAME where email = ?", new String[]{email});
to
Cursor cursor = db.rawQuery("SELECT * from " + TABLE_NAME + " where email = ?", new String[]{email});
so that the name of the table in the sql statement is users and not TABLE_NAME.
Here are all the Queries I should be able to retrive and display corresponding data. I need help with the sytax and code. All this should be displayed to another xml when user enters query button.
/*1a. Retrieve full details of all suppliers; that is, make a list of all attributes used to describe each supplier for every supplier in s.
SELECT * FROM s;
1b. Retrieve full details of all parts.
SELECT * FROM p;
1c. Retrieve full details of all suppliers-of-parts. (Hint This query should test the vertical and horizontal scrolling capabilities of your app!)
SELECT * FROM sp;
2. Retrieve sno and sname for all suppliers based in "London".
SELECT sno,s.sname FROM s WHERE ( city = 'London' );
3. Is part "P07" still manufactured in "London"?
SELECT pno,city FROM p WHERE pno = 'P07';
4. What is the pno and pname of all parts that cost more than $1.00?
SELECT pno,pname FROM p
WHERE ( cost > 1.00 );
5. Retrieve full details for parts supplied by supplier "S01".
SELECT p.pno,p.pname,p.cost,p.city FROM p,sp
WHERE ( (p.pno = sp.pno) AND (sp.sno = 'S01') );
6. Retrieve a list of each distinct part city. Does this eliminate duplicate cities from the list?
SELECT DISTINCT city FROM p;
7. Retrieve the pno, pname, and city of parts manufactured in "Dallas", "Paris", or "London".
SELECT pno,pname,city FROM p WHERE ( city IN ('Dallas','Paris','London') );
8. Retrieve the pno and pname of each part and sno and sname of all suppliers who supply qty ≥ 100 (100 or more) of any one part.
SELECT DISTINCT p.pno,p.pname,s.sno,s.sname FROM s,p,sp
WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND (sp.qty >= 100) );
9. Retrieve sname of all suppliers who supply less than 400 of pno = "P02", but only if the part and the supplier have identical city attributes.
SELECT s.sname FROM s,p,sp
WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND
(sp.pno = 'P02') AND (sp.qty < 400) AND (p.city = s.city)
);
10. What is the pno of parts with pname = "Nut" or pname = "Screw"?
SELECT pno FROM p WHERE ( pname IN ('Nut','Screw') ); */
Here is my code so far
Main activity.java
package com.rough.problem.problem9;
import android.content.Context;
import android.database.sqlite.SQLiteStatement;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import java.util.List;
public class MainActivity extends AppCompatActivity {
EditText Select;
DatabaseHelper myDB;
Button create, query, quit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myDB = new DatabaseHelper(this);
// Select = (EditText) findViewById(R.id.SelectStatement);
create = (Button) findViewById(R.id.Create);
query = (Button) findViewById(R.id.Query);
quit = (Button) findViewById(R.id.Quit);
// Select.getBackground().setColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_ATOP);
create.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tableS tables1 = new tableS("S01", "Smith", "London");
tableS tables2 = new tableS("S02", "Jones", "Paris");
tableS tables3 = new tableS("S03", "Blake", "Paris");
tableS tables4 = new tableS("S04", "Clark", "London");
tableS tables5 = new tableS("S05", "Adams", "Athens");
tableS tables6 = new tableS("S06", "Gracia", "Austin");
tableS tables7 = new tableS("S07", "Thomas", "Paris");
tableS tables8 = new tableS("S08", "Jonas", "New York");
tableS tables9 = new tableS("S09", "Zeeman", "Dallas");
tableP tablep1 = new tableP("P01","Nut", "0.13", "London");
tableP tablep2 = new tableP("P02","Bolt", "0.25", "Paris");
tableP tablep3 = new tableP("P03","Screw", "0.09", "Rome");
tableP tablep4 = new tableP("P04","Screw", "0.10", "London");
tableP tablep5 = new tableP("P05","Cam", "5.26", "Paris");
tableP tablep6 = new tableP("P06","Cog", "3.75", "London");
tableP tablep7 = new tableP("P07","Washer", "0.11", "El Paso");
tableP tablep8 = new tableP("P08","Nut", "0.13", "Austin");
tableP tablep9 = new tableP("P09","Nail", "0.01", "Rome");
tableP tablep10 = new tableP("P10","Gear", "9.99", "Houston");
tableP tablep11 = new tableP("P11","Tack", "0.01", "Dallas");
tableP tablep12 = new tableP("P12","Wheel", "2.30", "Paris");
tableSP tablesp1 = new tableSP("S01", "P01","300");
tableSP tablesp2 = new tableSP("S01", "P02","200");
tableSP tablesp3 = new tableSP("S01", "P03","400");
tableSP tablesp4 = new tableSP("S01", "P04","200");
tableSP tablesp5 = new tableSP("S01", "P05","100");
tableSP tablesp6 = new tableSP("S01", "P06","100");
tableSP tablesp7 = new tableSP("S01", "P12","50");
tableSP tablesp8 = new tableSP("S02", "P01","300");
tableSP tablesp9 = new tableSP("S02", "P02","400");
tableSP tablesp10 = new tableSP("S03", "P02","200");
tableSP tablesp11 = new tableSP("S04", "P02","200");
tableSP tablesp12 = new tableSP("S04", "P04","300");
tableSP tablesp13 = new tableSP("S04", "P05","400");
tableSP tablesp14 = new tableSP("S05", "P01","50");
tableSP tablesp15 = new tableSP("S05", "P09","150");
tableSP tablesp16 = new tableSP("S05", "P011","320");
tableSP tablesp17 = new tableSP("S06", "P02","150");
tableSP tablesp18 = new tableSP("S06", "P12","825");
tableSP tablesp19 = new tableSP("S08", "P08","180");
tableSP tablesp20 = new tableSP("S08", "P11","250");
tableSP tablesp21 = new tableSP("S09", "P01","100");
tableSP tablesp22 = new tableSP("S09", "P03","200");
tableSP tablesp23 = new tableSP("S09", "P04","100");
tableSP tablesp24 = new tableSP("S09", "P07","300");
tableSP tablesp25 = new tableSP("S09", "P10","100");
tableSP tablesp26 = new tableSP("S09", "P12","200");
// add them
myDB.insertdata(tables1);
myDB.insertdata(tables2);
myDB.insertdata(tables3);
myDB.insertdata(tables4);
myDB.insertdata(tables5);
myDB.insertdata(tables6);
myDB.insertdata(tables7);
myDB.insertdata(tables8);
myDB.insertdata(tables9);
myDB.insertdatap(tablep1);
myDB.insertdatap(tablep2);
myDB.insertdatap(tablep3);
myDB.insertdatap(tablep4);
myDB.insertdatap(tablep5);
myDB.insertdatap(tablep6);
myDB.insertdatap(tablep7);
myDB.insertdatap(tablep8);
myDB.insertdatap(tablep9);
myDB.insertdatap(tablep10);
myDB.insertdatap(tablep11);
myDB.insertdatap(tablep12);
myDB.insertdatasp(tablesp1);
myDB.insertdatasp(tablesp2);
myDB.insertdatasp(tablesp3);
myDB.insertdatasp(tablesp4);
myDB.insertdatasp(tablesp5);
myDB.insertdatasp(tablesp6);
myDB.insertdatasp(tablesp7);
myDB.insertdatasp(tablesp8);
myDB.insertdatasp(tablesp9);
myDB.insertdatasp(tablesp10);
myDB.insertdatasp(tablesp11);
myDB.insertdatasp(tablesp12);
myDB.insertdatasp(tablesp13);
myDB.insertdatasp(tablesp14);
myDB.insertdatasp(tablesp15);
myDB.insertdatasp(tablesp16);
myDB.insertdatasp(tablesp17);
myDB.insertdatasp(tablesp18);
myDB.insertdatasp(tablesp19);
myDB.insertdatasp(tablesp20);
myDB.insertdatasp(tablesp21);
myDB.insertdatasp(tablesp22);
myDB.insertdatasp(tablesp23);
myDB.insertdatasp(tablesp24);
myDB.insertdatasp(tablesp25);
myDB.insertdatasp(tablesp26);
}
});
List<tableS> tables = myDB.alltableS();
if (tables != null) {
String[] itemsNames = new String[tables.size()];
for (int i = 0; i < tables.size(); i++) {
itemsNames[i] = tables.get(i).toString();
}
// display like string instances
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, itemsNames));
}
}
//-----------------------------------------------------------
public void ClickQueryButton(View view)
//-----------------------------------------------------------
{
String select = ((EditText) findViewById(R.id.SelectStatement)).getText().toString();
DatabaseHelper mydb = openOrCreateDatabase("SPdb1.db", Context.MODE_PRIVATE, null);
try
{
SQLiteStatement statement = myDB.compileStatement(query);
Intent intent = new Intent(this,ExecuteQueryActivity.class);
intent.putExtra(QUERYX, query);
startActivity(intent);
} catch (SQLiteException exception)
{
Toast.makeText(this, "SQL query contains syntax error", Toast.LENGTH_LONG).show();
}
}
public boolean onCreateOptionMenu (Menu menu){
getMenuInflater().inflate(R.menu.menu_main,menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item){
int id = item.getItemId();
return true;
}
}
DatabaseHelper.java
package com.rough.problem.problem9;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "SPdb1.db";
public static final String TABLE_NAME = "s";
public static final String COL_1 = "sno";
public static final String COL_2 = "sname";
public static final String COL_3 = "city";
public static final String TABLENAME = "p";
public static final String COL1 = "pno";
public static final String COL2 = "pname";
public static final String COL3 = "cost";
public static final String COL4 = "city";
public static final String TABLENAMES = "sp";
public static final String COLS1 = "sno";
public static final String COLS2 = "pno";
public static final String COLS3 = "qty";
private static final String[] COLUMNS = {COL_1, COL_2, COL_3};
private static final String[] COLUMN = {COL1,COL2,COL3,COL4};
private static final String[] COLUMNSS = {COLS1,COL2,COLS3};
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
String query = "Create Table IF NOT EXISTS " + TABLE_NAME + "(" +
COL_1 + " TEXT PRIMARY KEY COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COL_2 + " TEXT NOT NULL COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COL_3 + " TEXT NOT NULL COLLATE NOCASE" + //<<<<<<<<<< ADDED SPACE
");";
db.execSQL(query);
String querys = "Create Table IF NOT EXISTS " + TABLENAME + "(" +
COL1 + " TEXT NOT NULL COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COL2 + " TEXT NOT NULL COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COL3 + " REAL NOT NULL," + //<<<<<<<<<< ADDED SPACE
COL4 + " TEXT NOT NULL COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
"PRIMARY KEY (pno)" + //<<<<<<<<<< ADDED SPACE
");";
db.execSQL(querys);
String queryss = "Create Table IF NOT EXISTS " + TABLENAMES + "(" +
COLS1 + " TEXT NOT NULL REFERENCES s(sno) COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COLS2 + " TEXT NOT NULL COLLATE NOCASE," + //<<<<<<<<<< ADDED SPACE
COLS3 + " INTEGER NOT NULL," + //<<<<<<<<<< ADDED SPACE
"FOREIGN KEY (pno) REFERENCES p(pno)" + //<<<<<<<<<< ADDED SPACE
");";
db.execSQL(queryss);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// you can implement here migration process
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + TABLENAME);
db.execSQL("DROP TABLE IF EXISTS " + TABLENAMES);
onCreate(db);
}
public void insertdata (tableS tables){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(COL_1, tables.getSno());
values.put(COL_2, tables.getSname());
values.put(COL_3,tables.getCity());
// insert
db.insert(TABLE_NAME, null, values);
db.close();
}
public void insertdatap ( tableP tablep){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values1 = new ContentValues();
values1.put(COL1, tablep.getPno());
values1.put(COL2, tablep.getPname());
values1.put(COL3, tablep.getCost());
values1.put(COL4, tablep.getCity());
// insert
db.insert(TABLENAME,null,values1);
db.close();
}
public void insertdatasp ( tableSP tablesp){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values2 = new ContentValues();
values2.put(COLS1,tablesp.getSno());
values2.put(COLS2,tablesp.getPno());
values2.put(COLS3,tablesp.getQty());
// insert
db.insert(TABLENAMES,null,values2);
db.close();
}
public List<tableS> alltableS() {
List<tableS> tables = new LinkedList<tableS>();
String query = "SELECT * FROM " + TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
tableS Tables = null;
if (cursor.moveToFirst()) {
do {
Tables = new tableS();
Tables.setSno(cursor.getString(0));
Tables.setSname(cursor.getString(1));
Tables.setCity((cursor.getString(2)));
tables.add(Tables);
} while (cursor.moveToNext());
}
return tables;
}
}
And finally tableS.java I am not attaching tableP.java and tableSP.java as they are very similar to tableS.java
package com.rough.problem.problem9;
public class tableS {
private String sno;
private String sname;
private String city;
public tableS() {
}
public tableS(String sno , String sname, String city) {
this.sno = sno;
this.sname = sname;
this.city = city;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
#Override
public String toString() {
return sno + " \t\t " + sname + " \t\t " + city ;
}
}
The way that I would determine the syntax is via a combination of :-
reading the documentation e.g SQL As Understood By SQLite SELECT
Perhaps testing the queries outside of the App using one of the available SQLite Management tools e.g. DB Browser for SQLite, Navicat etc..
You would initially build and populate a test Database
You could then run the queries.
Ideally you would the convert these queries to utilise the convenience methods (query for selections if appropriate (sometimes the convenience methods may not be able to cope in which case you may rarely have to utilise the rawQuery method)).
I would suggest that trying to display the result from 10 queries with various lists would be a UI nightmare. So perhaps you should consider displaying the various information in different activities or in different fragments of an activity.
Assuming Navicat as the SQLite Management tool then you could :-
Start the Navicat program (after installing).
Click on File/New Connection.
Provide a suitable Connection Name e.g. SPdb1
Click the New SQLite 3 radio button.
Click on the ... at the right of the Database File input, select an appropriate location for the Database and enter the SPdb1.db as the database name.
Click Save and the OK.
Double click the connection and the double click main.
You could build the tables by click on New Table or you could write queries to create them (I tend to prefer the latter).
You could then populate them using appropriate data either using the options with the tables or via queries.
An alternative would be to copy the database from the App using Android Studio's Device Explorer to a suitable location and then create a connection using an existing database.
You can now copy the proposed queries (either as a single query or multiple queries (Navicat allows/captures results from multiple queries)) and try running them to check the syntax and functionality. e.g. Using the database form your previous question (an then adding the p and sp tables) the results are that all 10 queries run without any syntax errors as per :-
SELECT * FROM s
> OK
> Time: 0s
SELECT * FROM p
> OK
> Time: 0s
SELECT * FROM sp
> OK
> Time: 0s
SELECT sno,s.sname FROM s WHERE ( city = 'London' )
> OK
> Time: 0s
SELECT pno,city FROM p WHERE pno = 'P07'
> OK
> Time: 0s
SELECT pno,pname FROM p
WHERE ( cost > 1.00 )
> OK
> Time: 0s
SELECT p.pno,p.pname,p.cost,p.city FROM p,sp
WHERE ( (p.pno = sp.pno) AND (sp.sno = 'S01') )
> OK
> Time: 0s
SELECT DISTINCT city FROM p
> OK
> Time: 0s
SELECT pno,pname,city FROM p WHERE ( city IN ('Dallas','Paris','London') )
> OK
> Time: 0s
SELECT DISTINCT p.pno,p.pname,s.sno,s.sname FROM s,p,sp
WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND (sp.qty >= 100) )
> OK
> Time: 0s
SELECT s.sname FROM s,p,sp
WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND
(sp.pno = 'P02') AND (sp.qty < 400) AND (p.city = s.city)
)
> OK
> Time: 0s
SELECT pno FROM p WHERE ( pname IN ('Nut','Screw') )
> OK
> Time: 0s
However only the first and fourth query results in any data being extracted as per :-
Converting queries
Once you are assured that the queries work as expected then you can convert these into methods, perhaps within you DatabaseHelper class.
Taking the most complicated query :-
SELECT s.sname FROM s,p,sp
WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND
(sp.pno = 'P02') AND (sp.qty < 400) AND (p.city = s.city)
);
Look at the SQLiteDatabase query method (the simplest of the 4) SQLiteDatabase - query
This takes 7 parameters as per :-
The tablename.
The columns to be returned in the cursor as a String array (null for all i.e, equivalenet to *).
The selection (WHERE clause less WHERE) (null for no where clause).
The selection arguments to replace the placeholders in the selection (i.e. each ? is replaced by an argument) (null for no arguments).
The GROUP BY column(s) as a string (null for no GROUP BY clause).
The HAVING clause, as a string, less the HAVING keyword (null for no HAVING clause).
The ORDER BY clause as a string, less the ORDER BY keywords.
The tablename is used to specify JOINED tables.
So :-
- 1 will be FROM s,p,sp less theFROM keyword, so s,p,sp
e.g. :-
String table = "s,p,sp";
2 will be a sinlge element string array with the element as the string s.sname
e.g. :-
String[] columns = new String[]{"s.sname"};
3 will be WHERE ( (s.sno = sp.sno) AND (p.pno = sp.pno) AND
(sp.pno = 'P02') AND (sp.qty < 400) AND (p.city = s.city)
) less the WHERE clause and with the parameters as ? marks
e.g. :-
String whereclause = "( (s.sno = sp.sno) AND (p.pno = sp.pno) AND (sp.pno = '?') AND (sp.qty < ?) AND (p.city = s.city));
4 The arguments will be p02 and 400 respectively (however you may want to pass these so the values can be changed so here the assumption is that values will be passed via the call to the method as variables partno (string) and quantity (integer))
so :- String[] whereargs = new String[]{partno,String.valueOf(quantity};
5 will be null as there is no GROUP BY clause.
6 will be null as there is no HAVING clause.
7 will be null as there is no ORDER BY clause.
As such the resultant method could be :-
public Cursor getLowUsageSupplierNamesForAPart(String partno, int Quantity) {
String table = "s,p,sp";
String[] columns = new String[]{"s.sname"};
String whereclause = "( (s.sno = sp.sno) AND (p.pno = sp.pno) AND (sp.pno = '?') AND (sp.qty < ?) AND (p.city = s.city));
String[] whereargs = new String[]{partno,String.valueOf(quantity};
SQLiteDatbase db = this.getWriteableDatabase();
return db.query(
table,
columns.
whereclause,
whereargs,
null,null,null
);
}
You could then call this from an activity/fragment that instantiates or has an instantiated DatabaseHelper ( e.g. MyDB in your MainActivity) using :-
mCursor = MyDB.getLowUsageSupplierNamesForAPart("p02",400);
You could then display the list of supplier names in a ListView (noting that you should close mCursor when done with the activity e.g. by overidding the onDestroy method to include mCursor.close().
Note this example assumes that mCursor has been defined as a class variable and thus has ample scope.)
I have created an app with an SQLite database and a ListView that I want to populate using the database. To do this I have written an adapter class called HomeListAdapter. This class takes 4 string arrays as input and that is where my problem is. At first, I just used random string arrays to populate the ListView by typing them myself, for example:
String[] homelist_name_short = {
"Flower", "Bush", "Tree"};
String[] homelist_name_long = {
"Red rose", "Berry bush", "Oak"};
String[] homelist_date = {
"20-9-2017", "11-10-2017", "12-10-2017"};
String[] homelist_price = {
"€1.50", "€2.48", "€0.68"};
Now I want this to be put into the listview automatically and to do that I have written the code that can be seen below..
I have created a class called Home:
public class Home {
private String mShortHomeName;
private String mLongHomeName;
private String mHomeDate;
private String mHomePrice;
public Home(String ShortName, String LongName, String Date, String Price) {
this.mShortHomeName = ShortName;
this.mLongHomeName = LongName;
this.mHomeDate = Date;
this.mHomePrice = Price;
}
public String getShortName() {
return this.mShortHomeName;
}
public String getLongName() {
return this.mLongHomeName;
}
public String getDate() {
return this.mHomeDate;
}
public String getPrice() {
return this.mHomePrice;
}
}
Added the following to my DatabaseHelper:
public Cursor getAllHomesAsCursor() {
SQLiteDatabase db = this.getWritableDatabase();
String[] columns = {"rowid as _id","*"};
return db.query(TABLE_NAME,columns,null,null,null,null,null);
}
The following to the activity that contains my listview:
DatabaseHelper db = new DatabaseHelper(getActivity());
Cursor csr = db.getAllHomesAsCursor();
HLAdapter adapter = new HLAdapter(getActivity(), csr);
listView.setAdapter(adapter);
The HLAdapter looks as follows:
public class HLAdapter extends CursorAdapter {
public HLAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
#Override
public View newView(Context context, Cursor csr, ViewGroup parent) {
return LayoutInflater.from(context).inflate(
R.layout.homelist_listview_layout,
parent,
false
);
}
#Override
public void bindView(View view, Context context, Cursor csr) {
TextView sname = (TextView) view.findViewById(R.id.homelist_name_short);
TextView lname = (TextView) view.findViewById(R.id.homelist_name_long);
TextView date = (TextView) view.findViewById(R.id.homelist_date);
TextView price = (TextView) view.findViewById(R.id.homelist_price);
sname.setText(csr.getString(csr.getColumnIndex("name_short")));
lname.setText(csr.getString(csr.getColumnIndex("name_long")));
date.setText(csr.getString(csr.getColumnIndex("date")));
price.setText(csr.getString(csr.getColumnIndex("price")));
}
}
My DatabaseHelper class looks as follows:
public class DatabaseHelper extends SQLiteOpenHelper{
public static final String DATABASE_NAME = "Main.db";
public static final String TABLE_NAME = "current_table";
public static final String COL_1 = "name_short";
public static final String COL_2 = "name_long";
public static final String COL_3 = "date";
public static final String COL_4 = "price";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_NAME + " (name_short TEXT,name_long TEXT, due_date TEXT, price TEXT) ");
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
public Cursor getAllHomesAsCursor() {
SQLiteDatabase db = this.getWritableDatabase();
String[] columns = {"rowid as _id","*"};
return db.query(TABLE_NAME,columns,null,null,null,null,null);
}
public boolean insertData(String name_short, String name_long, String due_date, String price) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(COL_1,name_short);
contentValues.put(COL_2,name_long);
contentValues.put(COL_3,due_date);
contentValues.put(COL_4,price);
long result = db.insert(TABLE_NAME,null,contentValues);
if(result == -1)
return false;
else
return true;
}
public void deleteAllData() {
SQLiteDatabase db = this.getWritableDatabase();
db.execSQL("DELETE FROM " + TABLE_NAME);
}
public Cursor getAllData() {
SQLiteDatabase db = this.getWritableDatabase();
Cursor res = db.rawQuery("SELECT * FROM " + TABLE_NAME ,null);
return res;
}
public Cursor getSpecifiedColumnData(String column) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor res = db.rawQuery("SELECT column FROM " + TABLE_NAME,null);
return res;
}
}
I would think that my code should be working fine, but when I run the app. It closes immediately. Can you tell me what the problem is?
I believe the issue is that you need 4 String arrays to be passed to the adapter, so doing it like above you'd need to have a unique equivalent of getAllData for each type.
However considering that a house has a short name, long name, date and price a better approach could to consider all of these properties as an object and thus create a class. You could then create a List not of String objects but as a List of House objects, you'd be able to get them all in one go etc.
So (P.S. for the sake of my sanity I've incorporated the SO4522191 into the following so I can keep some sort of track of the code) :-
1) Create your Home Object to hold all values/properties of a house:-
1-a) Create a file the same as your home name, it's going to be a java class file.
In this case I've called it SO45422191Home, the code could be along the lines of :-
public class SO45422191Home {
private String mShortHomeName;
private String mLongHomeName;
private String mHomeDate;
private String mHomePrice;
public SO45422191Home(String ShortName, String LongName, String Date, String Price) {
this.mShortHomeName = ShortName;
this.mLongHomeName = LongName;
this.mHomeDate = Date;
this.mHomePrice = Price;
}
public String getShortName() {
return this.mShortHomeName;
}
public String getLongName() {
return this.mLongHomeName;
}
public String getDate() {
return this.mHomeDate;
}
public String getPrice() {
return this.mHomePrice;
}
}
Explanation
Using the above we can create a SO45422191Home object, in code elsewhere e.g. in your activity, by using something
like SO45422191Home Myhome = new SO45422191Home("Flower","Red
Rose","20-9-2017","1.50");.
With the MyHome object you can extract the properties e.g.
MyHome.getPrice() would return a String with a value of 1.50.
Similar for the other properties.
You can create an array of objects e.g. SO45422191Home[] homes = new
SO45422191Home[3]; will create an array of 3 (empty) SO45422191Home
objects. We could set the first element of the array using homes[0] =
new SO45422191Home("Bush","Cherry","11-10-2017","2.48");
2) Create a means of getting an array of SO45422191Home objects from the database.
here's some code for this:-
public List<SO45422191Home> getAllHomes() {
List<SO45422191Home> rv = new ArrayList<>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor csr = db.query(HOMETABLE,null,null,null,null,null,null);
while (csr.moveToNext()) {
SO45422191Home h = new SO45422191Home(
csr.getString(csr.getColumnIndex(SHORTHOMENAME)),
csr.getString(csr.getColumnIndex(LONGHOMENAME)),
csr.getString(csr.getColumnIndex(HOMEDATE)),
csr.getString(csr.getColumnIndex(HOMEPRICE))
);
rv.add(h);
}
csr.close();
return rv;
}
Explanation You used List and added elements to the list, List is similar but for SO45422191Home objects rather
than String objects.
The Database is opened, if not already open, using SQLiteDatabase db
= this.getWritableDatabase();.
All rows are extracted into a cursor.
The cursor is traversed each row at a time.
For each row a SO45422191Home object is created by getting the respective data from the cursor
(Note that csr.getColumnIndex(columnname) is used
rather than hard coding the column's index/offset, doing so can reduce
the chance for errors and also reduce overheads should changes be
applied.).
The the new object is added to the list.
Obviously column names would have to be adjusted, you may also want to add db.close() before the return.
3) Amend your adapter to take and use the the single list of objects rather than the 4 List.
here's an example adapter for use by a List (Note that R.layout.homeentry is the layout used for each entry in the ListView), the layout is below in the section re Cursor Adapter:-
public class AdapterHomeList2 extends ArrayAdapter {
List<SO45422191Home> homes;
LayoutInflater lInflater;
public AdapterHomeList2(Context context, List<SO45422191Home> homes) {
super(context,R.layout.homeentry, homes);
lInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.homes = homes;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = lInflater.inflate(R.layout.homeentry, parent, false);
}
TextView sname = (TextView) view.findViewById(R.id.shortname);
TextView lname = (TextView) view.findViewById(R.id.longname);
TextView date = (TextView) view.findViewById(R.id.date);
TextView price = (TextView) view.findViewById(R.id.price);
sname.setText(homes.get(position).getShortName());
lname.setText(homes.get(position).getLongName());
date.setText(homes.get(position).getDate());
price.setText(homes.get(position).getPrice());
return view;
}
}
This is the code for an ArrayList :-
public class AdapterHomeList3 extends ArrayAdapter {
ArrayList<SO45422191Home> homes;
LayoutInflater lInflater;
public AdapterHomeList3(Context context, ArrayList<SO45422191Home> homes) {
super(context,R.layout.homeentry, homes);
lInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.homes = homes;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = lInflater.inflate(R.layout.homeentry, parent, false);
}
TextView sname = (TextView) view.findViewById(R.id.shortname);
TextView lname = (TextView) view.findViewById(R.id.longname);
TextView date = (TextView) view.findViewById(R.id.date);
TextView price = (TextView) view.findViewById(R.id.price);
sname.setText(homes.get(position).getShortName());
lname.setText(homes.get(position).getLongName());
date.setText(homes.get(position).getDate());
price.setText(homes.get(position).getPrice());
return view;
}
}
Using a CursorAdapter
1) Add a new method to extract a cursor with all rows (NOTE! for cursor adapter a row named _id is required)
public Cursor getAllHomesAsCursor() {
SQLiteDatabase db = this.getWritableDatabase();
String[] columns = {"rowid as _id","*"};
return db.query(HOMETABLE,columns,null,null,null,null,null);
}
Note! instead of all columns i.e. coding null as the second parameter
to 'query' (which doesn't get the hidden rowid column (assuming
WITHOUT ROWID hasn't been used)), will will get the rowid (a unqiue
row identifier) and name this AS _id to suite the Cursor Adapter
hence "rowid as _id", the following * as the second element of
the columns array means all rows (specifying null as 2nd parameter
result in SELECT * .....).
Otherwise it's pretty simple. NOTE you must not close the database,
otherwise you can't access the cursor.
2) You will need a layout for each item in the list, as you would for a custom array adapter and it can be the same one i.e. there are no diferences according to which adapter is used. e.g. I created :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/shortname"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/longname"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/date"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/price"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
3) Create The Cursor Adpater as a class file, very similar to an Array Adapter.
public class AdapterHomeList extends CursorAdapter {
public AdapterHomeList(Context context, Cursor cursor) {
super(context, cursor,0);
}
#Override
public View newView(Context context, Cursor csr, ViewGroup parent) {
return LayoutInflater.from(context).inflate(
R.layout.homeentry, //<< layout for each list item
parent,
false
);
}
#Override
public void bindView(View view, Context context, Cursor csr) {
TextView sname = (TextView) view.findViewById(R.id.shortname);
TextView lname = (TextView) view.findViewById(R.id.longname);
TextView date = (TextView) view.findViewById(R.id.date);
TextView price = (TextView) view.findViewById(R.id.price);
sname.setText(csr.getString(csr.getColumnIndex(SO45422191.SHORTHOMENAME)));
lname.setText(csr.getString(csr.getColumnIndex(SO45422191.LONGHOMENAME)));
date.setText(csr.getString(csr.getColumnIndex(SO45422191.HOMEDATE)));
price.setText(csr.getString(csr.getColumnIndex(SO45422191.HOMEPRICE)));
}
}
Note! R.layout.homeentry being the layout for the list entries
and id's are from this.
4) From the respective activity, get the cursor, get an instance of the adapter and set the ListView to use the adapter.
e.g.:-
Cursor csr = dbhlp.getAllHomesAsCursor();
AdapterHomeList ahl = new AdapterHomeList(this,csr);
ListView hl = (ListView) this.findViewById(R.id.homelist);
hl.setAdapter(ahl);
result :-
Using cursor.getColumnIndex()
getColumnIndex
int getColumnIndex (String columnName)
Returns the zero-based index for the given column name, or -1 if the
column doesn't exist. If you expect the column to exist use
getColumnIndexOrThrow(String) instead, which will make the error more
clear.
SQLiteCursor
Using getColumnIndex as opposed to specifying the index removes the need to manually determine column offsets.
For example purposes, there is a table, named items with 3 columns, named as name, date and price :-
Using a query that uses the equivalent of SELECT * FROM items, the query will return a cursor with 3 columns, name, date and price
column name would have an offset of 0.
column date would have an offset of 1.
column price would have an offset of 2.
To extract the date from the cursor you could code cursor.getString(1);
However, if you were to have a query based upon SELECT date, price, name FROM items then the offsets would be:-
column name would have an offset of 2.
column date would have an offset of 0.
column price would have an offset of 1.
In this case you'd have to code cursor.getString(0); to extract the date.
It could be easy to inadvertently code the wrong offset, especially when using larger tables or when joining tables or when introducing generated columns.
Using cursor.getString(cursor.getColumnIndex("date")); could be used in both situations as it would return 1 in the first case and 0 in the second case.
Above, as an example, sname.setText(csr.getString(csr.getColumnIndex(SO45422191.SHORTHOMENAME))); has been coded.
Home.SHORTHOMENAME is a class varaible defined in the Database Helper (i.e. SO45422191 is the DatabaseHelper Class and SHORTHOMENAME is the class variable) that equates to the column name of the respective column as can be seen from the Database Helper code extract:-
public class SO45422191 extends SQLiteOpenHelper {
public static final String DBNAME = "SO45422191";
public static final String HOMETABLE = "homes";
public static final String SHORTHOMENAME = "shorthomename";
public static final String LONGHOMENAME = "longhomename";
public static final String HOMEDATE = "homedate";
public static final String HOMEPRICE = "homeprice";
// constructor
public SO45422191(Context context) {
super(context, DBNAME , null , 1);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table " + HOMETABLE +
"(" +
SHORTHOMENAME + " TEXT, " +
LONGHOMENAME + " TEXT, " +
HOMEDATE + " TEXT, " +
HOMEPRICE + ")");
How can I get a selected item in a row from tableview in javaFX with Sqlite Database.
I am now using this to get the Index of the row:
(...)
#FXML
private ObservableList<UserData> data;
#FXML
private TableView table;
#FXML
private void pressTableAction() {
System.out.println("Selected index: " +table.getSelectionModel().getSelectedIndex());
}
(...)
public void initialize (URL url, ResourceBundle rb) {
try {
con = DataBaseConnection.getConnected();
stat = con.createStatement();
data = FXCollections.observableArrayList();
ResultSet rs = con.createStatement().executeQuery("SELECT * FROM person");
while (rs.next()) {
data.add(new UserData(rs.getInt("p_id"), rs.getString("Name")));
}
column1.setCellValueFactory(new PropertyValueFactory("p_id"));
column2.setCellValueFactory(new PropertyValueFactory("Name"));
table.setItems(null);
table.setItems(data);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error on Building Data");
}
Public static class UserData {
private IntegerProperty p_id;
private StringProperty Name;
private UserData(Integer p_id, String Name) {
this.p_id = new SimpleIntegerProperty (p_id);
this.Name = new SimpleStringProperty(Name);
}
public IntegerProperty p_idProperty() {
return p_id;
}
public StringProperty NameProperty() {
return Name;
}
}
My db looks like this:
CREATE TABLE person (p_id INTEGER PRIMARY KEY AUTOINCREMENT, Name VARCHAR(30) NOT NULL);
How can I get the p_id or the Name of the row I clicked?
#FXML
private void pressTableAction() {
System.out.println("Selected index: " + table.getSelectionModel().getSelectedIndex());
System.out.println("Selected p_id: " + ????)
}
First, do not use raw types for your table and table columns. Your IDE should be generating lots of warnings for this. So you should do
#FXML
TableView<UserData> table ;
instead of the declaration you have. Similarly the columns should be declared with the appropriate types.
If your model class UserData follows the standard JavaFX properties pattern, it will have a getP_id() method, and you can do
UserData selected = table.getSelectionModel().getSelectedItem();
System.out.println("Selected p_id: "+selected.getP_id());