SQLite One-to-Many Relationship Set/Get Foreign Key - java

I am building an android app project with SQLite DB.
I got stuck on One-To-Many RelationShip.
This is One
private static final String createTableOrders =
"CREATE TABLE " + TABLE_ORDER + "("
+ KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
...
+ KEY_COLUMN_FORMATS + " INTEGER REFERENCES " + TABLE_FORMATS + "(" + KEY_ID + ")"
+ ");";
This is Many
private static final String createTableFormats =
"CREATE TABLE " + TABLE_FORMATS + "("
+ KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
...
+ ");";
My problems is with set/get methods.
Lets say that I would need to get list of ids of all Formats that are in one Order.
I guess same thing goes for set method.
I tried to find this kind of question on SO but most of the question were just for SQL part.
P.S. Spent 3 hours trying to make it by myself but the only thing I got to was using GSON to code list of ids into String but it was just a dead-end.
EDIT: I need to get that information inside the code.
P.S.S I have been doing this for 18 hours so sorry if this is uber-stupid question.

A one-to-many relationship requires the foreign key column in the "many" table:
CREATE TABLE Orders (
ID PRIMARY KEY
);
CREATE TABLE Formats (
ID PRIMARY KEY,
OrderID REFERENCES Orders(ID)
);
To get all formats belonging to an order, you just look up rows with the ID of that order:
SELECT * FROM Formats WHERE OrderID = ?
In Jave:
Cursor cursor = db.query(TABLE_FORMATS,
new String[] { whatever columns you need },
"OrderID = " + orderID,
null, null, null, null, null);
while (cursor.moveToNext()) {
// read one order from the cursor
}
cursor.close();

Related

How to include two foreign keys in a table in jdbc?

I'm using JDBC in eclipse IDE , i want to put two foreign keys in my table 3 , one is referencing to the primary key in table 1 and one is referencing to the primary key in table 2. When i only put one foreign key constrains for any referencing table1 or table 2 , it works fine but when i include two it gives me sql exception as stated below:
java.sql.SQLSyntaxErrorException: You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'foreign key(T2) references
Table2(T2) )' at line 1
String createString =
// TABLE 1
"CREATE TABLE " + this.tableName + " ( " +
"T1 varchar(50) NOT NULL PRIMARY KEY )";
// TABLE 2
"CREATE TABLE " + this.tableName + " ( " +`enter code here`
"T2 varchar(50) NOT NULL PRIMARY KEY )";
// TABLE 3
"CREATE TABLE " + this.tableName + " ( " +
"T1 varchar(50) " +
"T2 varchar(50) " +
"foreign key(T1) references Table1 (T1)" +
"foreign key(T2) references Table2(T2) )";
First, this is actually a MySQL question, unrelated to Java/JDBC. Secondly, and more importantly, you don't appear to be using the correct syntax, which would be...
CREATE TABLE TableName (
T1 varchar(50),
T2 varchar(50),
foreign key(T1) references Table1(T1),
foreign key(T2) references Table2(T2)
);
Formatted for your code, it would look like this:
String createString = "CREATE TABLE " + this.tableName + " ( " +
" T1 varchar(50)," +
" T2 varchar(50)," +
" foreign key(T1) references Table1(T1)," +
" foreign key(T2) references Table2(T2));";
You were missing commas after each item in the items list for your CREATE TABLE statement.

Sqlite Query with Subquery returns empty

In my app, i'm using subquerys of sqlite, the subquery returns 3 values, its ok, but in the main query, returns empty and i need help in this.
*some parts of variables is in portuguese because i'm brazilian.
public List<Table_Anuncio_Empregador> getAllUser_Empregador() {
SQLiteDatabase db = this.getReadableDatabase();
List<Table_Anuncio_Empregador> anuncios = new ArrayList<Table_Anuncio_Empregador>();
SharedPreferences preferences = context.getSharedPreferences("user_preferences", MODE_PRIVATE);
int user_id = preferences.getInt("user_id_conectado",0);
String selectQuery = "SELECT "+KEY_ID+", "+KEY_IMAGEM_ANUNCIO+", "+KEY_TITULO+", "+KEY_DESCRICAO+", "+KEY_CIDADE
+ " FROM " + TABLE_ANUNCIO_EMPREGADOR
+ " WHERE "+ KEY_ID +" IN (SELECT "+KEY_ANUNCIO_EMPREGADOR_ID+" FROM "+ TABLE_ANUNCIO
+" WHERE "+ KEY_ANUNCIO_PERFIL+" = 'empregador' AND "+ KEY_USER_ID+" = "+user_id+")";
Log.e(LOG, selectQuery);
Cursor c = db.rawQuery(selectQuery, null);
if (c.moveToFirst()) {
do {
Table_Anuncio_Empregador anuncio = new Table_Anuncio_Empregador();
anuncio.setAnuncio_empregador_id(c.getInt(c.getColumnIndex(KEY_ID)));
anuncio.setImagem_do_anuncio(c.getBlob(c.getColumnIndex(KEY_IMAGEM_ANUNCIO)));
anuncio.setTitulo(c.getString(c.getColumnIndex(KEY_TITULO)));
anuncio.setDescricao(c.getString(c.getColumnIndex(KEY_DESCRICAO)));
anuncio.setCidade(c.getString(c.getColumnIndex(KEY_CIDADE)));
anuncios.add(anuncio);
} while (c.moveToNext());
}
return anuncios;
}
The LOG shows the query as :-
E/Banco_Helper: SELECT ID, Imagem_anuncio, Titulo, Descricao, Cidade FROM Anuncio_empregador WHERE ID IN (SELECT Anuncio_empregado_info_ID FROM Anuncio WHERE Anuncio_perfil = 'empregador' AND User_ID = 2)
The tables are created using :-
private static final String CREATE_TABLE_ANUNCIO =
"CREATE TABLE IF NOT EXISTS " + TABLE_ANUNCIO + "(" + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
KEY_USER_ID + " INTEGER NOT NULL," +
KEY_ANUNCIO_PERFIL + " TEXT NOT NULL," +
KEY_ANUNCIO_EMPREGADOR_ID + " INTEGER," +
KEY_ANUNCIO_PRESTADOR_ID + " INTEGER," +
KEY_CREATED_AT + " DATETIME NOT NULL" + ")";
and :-
private static final String CREATE_TABLE_ANUNCIO_EMPREGADOR =
"CREATE TABLE IF NOT EXISTS " + TABLE_ANUNCIO_EMPREGADOR + "(" + KEY_ID + " INTEGER PRIMARY KEY," +
KEY_TITULO + " TEXT NOT NULL," +
KEY_DESCRICAO + " TEXT NOT NULL," +
KEY_BAIRRO + " TEXT NOT NULL," +
KEY_CIDADE + " TEXT NOT NULL," +
KEY_ESTADO + " TEXT NOT NULL," +
KEY_LOCAL_SERVICO + " TEXT NOT NULL," +
KEY_EXIGENCIAS + " TEXT," +
KEY_IMAGEM_ANUNCIO + " BLOB NOT NULL" + ")";
Equating to :-
CREATE TABLE IF NOT EXISTS Anuncio(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
USER_ID INTEGER NOT NULL,
Anuncio_perfil TEXT NOT NULL,
Anuncio_empregado_info_ID INTEGER,
ANUNCIO_PRESTADOR_ID INTEGER,
CREATED_AT DATETIME NOT NULL
);
And :-
CREATE TABLE IF NOT EXISTS Anuncio_empregador (
ID INTEGER PRIMARY KEY,
Titulo TEXT NOT NULL,
Descricao TEXT NOT NULL,
Bairro TEXT NOT NULL,
Cidade TEXT NOT NULL,
Estado TEXT NOT NULL,
Local_Servico TEXT NOT NULL,
Exigencias TEXT,
Imagem_anuncio BLOB NOT NULL
);
I believe that your issue is with the actual data rather then the query.
That is, the following was used to create and populate the two tables and to also run the query (plus some intermediate queries). The result was that the three expected rows were included and that the three rows that should have been excluded were. That is the query in question ran with the expected results.
The following SQL was used :-
DROP TABLE IF EXISTS Anuncio;
CREATE TABLE IF NOT EXISTS Anuncio(
ID INTEGER PRIMARY KEY AUTOINCREMENT,
USER_ID INTEGER NOT NULL,
Anuncio_perfil TEXT NOT NULL,
Anuncio_empregado_info_ID INTEGER,
ANUNCIO_PRESTADOR_ID INTEGER,
CREATED_AT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
DROP TABLE IF EXISTS Anuncio_empregador;
CREATE TABLE IF NOT EXISTS Anuncio_empregador (
ID INTEGER PRIMARY KEY,
Titulo TEXT NOT NULL,
Descricao TEXT NOT NULL,
Bairro TEXT NOT NULL,
Cidade TEXT NOT NULL,
Estado TEXT NOT NULL,
Local_Servico TEXT NOT NULL,
Exigencias TEXT,
Imagem_anuncio BLOB NOT NULL DEFAULT X'00010203040506070809'
)
;
INSERT INTO Anuncio_empregador
(Titulo,Descricao,Bairro,Cidade,Estado,Local_Servico,Exigencias)
VALUES
('Mr','Albert','Bloggs','something','something else','xxx','xxxx'),
('Mr','Bert','Bloggs','something','something else','xxx','xxxx'),
('Mr','Charlie','Bloggs','something','something else','xxx','xxxx'),
('Mr','Dave','Bloggs','something','something else','xxx','xxxx'),
('Mr','Eddie','Bloggs','something','something else','xxx','xxxx'),
('Mr','Fred','Bloggs','something','something else','xxx','xxxx'),
('Mr','George','Bloggs','something','something else','xxx','xxxx')
;
SELECT * FROM Anuncio_empregador;
INSERT INTO Anuncio
(USER_ID, Anuncio_perfil,Anuncio_empregado_info_ID,ANUNCIO_PRESTADOR_ID)
VALUES
(1,'empregador',1,100),
(2,'empregador',2,100),
(3,'empregador',3,100),
(4,'not an empregador',1,100),
(5,'not an empregador',2,100),
(6,'not an empregador',3,100)
;
SELECT * FROM Anuncio;
SELECT * FROM Anuncio WHERE Anuncio_perfil = 'empregador';
SELECT ID,Imagem_anuncio,Titulo,Descricao,Cidade
FROM Anuncio_empregador
WHERE ID IN
(
SELECT Anuncio_empregado_info_ID
FROM ANUNCIO
WHERE ANUNCIO_PERFIL = 'empregador' AND USER_ID = user_id
)
;
Note that some liberties were taken, like
using the CURRENT_TIMESTAMP and
using X'00010203040506070809'
saving having to repeat these values which would have no impact upon workings of the SQL.
The resultant Anuncio_empregador table being :-
The resultant Anuncio table being :-
i.e. last 3 rows have been set to be excluded according to the clause WHERE ANUNCIO_PERFIL = 'empregador'
The result of the query in Question
SELECT ID,Imagem_anuncio,Titulo,Descricao,Cidade
FROM Anuncio_empregador
WHERE ID IN
(
SELECT Anuncio_empregado_info_ID
FROM ANUNCIO
WHERE ANUNCIO_PERFIL = 'empregador' AND USER_ID = user_id
)
;
being :-
Note changing AND USER_ID = user_id to AND USER_ID = 2 shows just the 1 row for Bert, as expected.

Inserting Content Values in multiple tables in Sqlite Android Application

I am brand new to multiple tables in an SQLite database and am trying to find out what the best practices are for inserting values into multiple tables. My main question is do I need to Create another ContentValues object for inserting the values into a second table? I am really stumped on how to perform the insert(). Here is what I am trying so far.
Here are the two tables and schema
/* Creating a common attributes table here. */
private static final String CREATE_COMMON_ATTRIBUTES_TABLE = "create table "
+ COMMON_ATTRIBUTES_TABLE + "(" + DBColCons.UID_COMMON_ATTRIBUTES + " integer" +
" primary key autoincrement, " + DBColCons.GPS_POINT+ " integer not null, "
+ DBColCons.EXISTING_GRADE_GPS_POINT+ " integer not null, "
+ DBColCons.COVER+ " real not null, "+ DBColCons.NOTES+ " text, "
+ DBColCons.DATE+ " text)";
/* Creating a weld table here */
private static final String CREATE_WELD_TABLE = " create table " +WELD_TABLE+ "("
+ DBColCons.UID_WELD + " integer primary key, " + DBColCons.WELD_TYPE +
" text, " + DBColCons.WELD_ID + " text, " + DBColCons.DOWNSTREAM_JOINT +
" text, " + DBColCons.UPSTREAM_JOINT + " text, " + DBColCons.HEAT_AHEAD +
" text, " + DBColCons.LENGTH_AHEAD + " real, " + DBColCons.WALL_CHANGE +
" text, " + DBColCons.WELD_WALL_THICKNESS + " text, "
+ DBColCons.WELDER_INITIALS + " text, foreign key("+DBColCons.WELD_ID+") references" +
"("+DBColCons.GPS_POINT+"))";
Here is the method I am wanting to use for the insert() with some class getters() for the Weld class, which I am passing in as a parameter.
public boolean insertWeld(Weld weld) {
/* Get a writable copy of the database */
SQLiteDatabase db = this.getWritableDatabase();
/* Content values to insert with Weld class setters */
ContentValues contentValuesWeld = new ContentValues();
try {
contentValuesWeld.put(DBColCons.GPS_POINT, weld.getGpsPoint());
contentValuesWeld.put(DBColCons.WELD_TYPE, weld.getWeldType());
contentValuesWeld.put(DBColCons.WELD_ID, weld.getWeldId());
contentValuesWeld.put(DBColCons.DOWNSTREAM_JOINT, weld.getDownstreamJoint());
contentValuesWeld.put(DBColCons.UPSTREAM_JOINT, weld.getUpstreamJoint());
contentValuesWeld.put(DBColCons.HEAT_AHEAD, weld.getHeatAhead());
contentValuesWeld.put(DBColCons.LENGTH_AHEAD, weld.getLengthAhead());
contentValuesWeld.put(DBColCons.EXISTING_GRADE_GPS_POINT, weld.getExistingGradePoint());
contentValuesWeld.put(DBColCons.COVER, weld.getCover());
contentValuesWeld.put(DBColCons.WALL_CHANGE, weld.getWallChange());
contentValuesWeld.put(DBColCons.WELD_WALL_THICKNESS, weld.getWeldWallThickness());
contentValuesWeld.put(DBColCons.WELDER_INITIALS, weld.getWelderInitials());
contentValuesWeld.put(DBColCons.NOTES, weld.getNotes());
/* adding the date in here to the row. */
contentValuesWeld.put(DBColCons.DATE, String.valueOf(mStrDate));
/* Inserting into the weld table */
db.insertWithOnConflict(WELD_TABLE, DBColCons.WELDER_INITIALS, contentValuesWeld,
SQLiteDatabase.CONFLICT_NONE);
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
The values for DBColCons.GPS_POINT,DBColCons.EXISTING_GRADE_GPS_POINT,DBColCons.GPS_COVER and DBColCons.NOTES are what I want to insert into the Common_Attributes_Table. This is where I am really confused. Do I need to create a separate ContentValues object for those specific values and insert them into the desired table with a separate db.insert() method along with the one I am already using with the insert on the WELD_TABLE?
Help I am lost in this train wreck. Ha.
Thank you all.
You need to call insert() (or insertWithConflict()) for each table you are inserting values into. Unless the values are the same, this implies you will need another ContentValues per table.
If you intend for these inserts to be committed as a single atomic operation, consider using a transaction.
SQLiteDatabase db = ...;
db.beginTransaction();
try {
// do your inserts/etc. here
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Slow retrieval of data in SQLITE takes a long using ContentProvider

I have an application in Android (running 4.0.3) that stores a lot of data in Table A. Table A resides in SQLite Database. I am using a ContentProvider as an abstraction layer above the database.
Lots of data here means almost 80,000 records per month. Table A is structured like this:
String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_A + " ( " +
COLUMN_ID + " INTEGER PRIMARY KEY NOT NULL" + "," +
COLUMN_GROUPNO + " INTEGER NOT NULL DEFAULT(0)" + "," +
COLUMN_TIMESTAMP + " DATETIME UNIQUE NOT NULL" + "," +
COLUMN_TAG + " TEXT" + "," +
COLUMN_VALUE + " REAL NOT NULL" + "," +
COLUMN_DEVICEID + " TEXT NOT NULL" + "," +
COLUMN_NEW + " NUMERIC NOT NULL DEFAULT(1)" + " )";
Here is the index statement:
String SQL_CREATE_INDEX_TIMESTAMP = "CREATE INDEX IF NOT EXISTS " + TABLE_A +
"_" + COLUMN_TIMESTAMP + " ON " + TABLE_A + " (" +
COLUMN_TIMESTAMP + ") ";
I have defined the columns as well as the table name as String Constants.
I am already experiencing significant slow down when retrieving this data from Table A. The problem is that when I retrieve data from this table, I first put it in an ArrayList and then I display it. Obviously, this is possibly the wrong way of doing things. I am trying to find a better way to approach this problem using a ContentProvider. But this is not the problem that bothers me.
The problem is for some reason, it takes a lot longer to retrieve data from other tables which have only upto 12 records maximum. I see this delay increase as the number of records in Table A increase. This does not make any sense. I can understand the delay if I retrieve data from Table A, but why the delay in retrieving data from other tables.
To clarify, I do not experience this delay if Table A is empty or has less than 3000 records.
What could be the problem?
EDIT: 09/14/2012 9:53 AM
To clarify, I am using a ContentProvider to manage the database. To query the data, I am using the context.getContentResolver().query method.
My query code in the ContentProvider:
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
final SQLiteDatabase db = dbHelper.getReadableDatabase();
String tableName = getTableName(uri);
queryBuilder.setTables(tableName);
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
So this is embarrassing:
Apparently, there was one line of code somewhere during the Application Load that was retrieving data from Table A. That was what was slowing down the application as a whole.
In any case, I still have to figure out how to optimize loading data from Table A using a ContentProvider.

Android SQLite3 problem enforcing primary key

I have a listview with a custom adapter that uses an sql cursor. When I add items to my listview, the item will be added to my sqlite3 database and the listview will refresh.
My one problem is that I am able to add duplicate items, and I do not want my application to allow duplicates to be added.
I have added a primary key to my database (on itemNumber), however the database does not seem to be enforcing this. Here is how I create my database:
private static final String DB_CREATE_MASTER = "CREATE TABLE "
+ "MyTable"
+ " (_id INTEGER, itemNumber TEXT,"
+ "itemPlace TEXT," + "itemTimeTEXT,"
+ "itemCode INTEGER,"
+ "dbdatestamp TEXT" + "PRIMARY KEY(itemNumber)" +");";
Does anyone know why I am able to add more than 1 duplicate itemNumber to my listview?
Thanks!
EDIT:
private static final String DB_CREATE_MASTER = "CREATE TABLE "
+ "MyTable"
+ " (_id INTEGER PRIMARY KEY, itemNumber TEXT,"
+ "itemPlace TEXT," + "itemTimeTEXT,"
+ "itemCode INTEGER,"
+ "dbdatestamp TEXT" + "UNIQUE(itemNumber)" +");";
EDIT:
This is how I add the itemNumber to the database:
values.put("itemNumber", myClass.itemNumber);
values.put("itemName", myClass.itemName);
values.put("itemTime", myClass.itemTime);
values.put("dbdatestamp", "03/01/1960 08:55");
this.db.insert(MY_TABLE, null, values);
Your primary key consists of 2 fields: _id and itemNumber. That means that a duplicate itemNumber is not enough to enforce the constraint. A duplicate would be an item with the same _id AND itemNumber. You could change the CREATE statement like this
PRIMARY KEY(_id), UNIQUE(itemNumber)
The UNIQUE constraint wouldn't allow duplicate item numbers.

Categories

Resources