I have a problem in my code that occurs error in lunching in database_helper.dart
database_helper.dart is one file in Sqlite storing data learning project and i faced this issue ,
i tried many solutions like uninstall app and install it again
can any one help me ?
======
class DataBaseHelper {
static Database _db ;
final String userT = 'userT' ;
final String columnId = 'id' ;
final String columnUserName = 'username' ;
final String columnPassword = 'password' ;
final String columnAge = 'age' ;
final String columnCity = 'city' ;
=========
Future<Database> get dbase async {
if(_db != null) {
return _db ;
}
_db = await intDB();
return _db ;
}
=================
intDB() async {
Directory docDirectory = await getApplicationDocumentsDirectory() ;
String path = join(docDirectory.path , 'myDB.db') ;
var myOwnDB = await openDatabase(path , version: 1 , onCreate: _onCreate);
return myOwnDB ;
}
=========================
void _onCreate(Database db , int newVersion) async {
var sql = 'CREATE TABLE $userT ($columnId INTEGER PRIMARY KEY UNIQUE ,'
' $columnUserName TEXT , $columnPassword TEXT , $columnCity TEXT , $columnAge INTEGER ' ;
await db.execute(sql) ;
}
error log:
E/SQLiteLog(14607): (1) near "INTEGER": syntax error
I/flutter (14607): error DatabaseException(near "INTEGER": syntax error (code 1): , while compiling: CREATE TABLE userT (id INTEGER PRIMARY KEY UNIQUE , username TEXT , password TEXT , city TEXT , age INTEGER) during oenter code herepen, closing...
E/flutter (14607): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: DatabaseException(near "INTEGER": syntax error (code 1): , while compiling: CREATE TABLE userT (id INTEGER PRIMARY KEY UNIQUE , username TEXT , password TEXT , city TEXT , age INTEGER)
Syntax error. you forgot to put ) at the end of line
$columnAge INTEGER )
You can check your sqllite code in https://sqliteonline.com/
CREATE TABLE userT (columnId INTEGER PRIMARY KEY UNIQUE ,
columnUserName TEXT , columnPassword TEXT , columnCity TEXT , columnAge INTEGER)
after put ) . it works fine.
Edit : Second question of Insert Into statement you mentioned in comments
The syntax error of Insert Into statement is column "userCity" does not exist.
In the question you provided, when Create table you use the name columnCity = 'city'. so you sholud change the name to "city".
Try removing UNIQUE
They have not included that word in any of the samples, so maybe it has not been implemented.
Related
package com.example.database;
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 {
//making db and setting tables 1-6 names
private static final int DATABASE_VERSION = 4;
private static final String DATABASE_NAME = "contacts.db";
private static final String TABLE1_NAME = "contacts";
private static final String TABLE2_NAME = "Uinfo";
private static final String TABLE3_NAME = "exercises";
private static final String TABLE4_NAME = "calories";
private static final String TABLE5_NAME = "calendar";
// private static final String TABLE6_NAME = "settings";
//these are for table 1
private static final String COLUMN_ID = "id";
private static final String COLUMN_EMAIL = "email";
private static final String COLUMN_PASS = "pass";
private static final String COLUMN_UNAME = "uname";
private static final String COLUMN_NAME = "name";
//for table 2
private static final String COLUMN_ID2 = "id2";
private static final String COLUMN_AGE = "age";
private static final String COLUMN_WEIGHT = "weight";
private static final String COLUMN_HEIGHT = "height";
private static final String COLUMN_SEX = "sex";
private static final String COLUMN_FK_CONTACTS_ID = "id";
// private static final String COLUMN_FK_SETTINGS_ID = "id_6";
private static final String COLUMN_FK_CALENDAR_ID = "id5";
//creating tables
private static final String TABLE_CREATE = "create table " + TABLE1_NAME +
" (id integer primary key AUTOINCREMENT not null ," +
" name text not null , " +
" email text not null ," +
" pass text not null, " +
" uname text not null);";
private static final String TABLE2_CREATE = "create table " + TABLE2_NAME +
"(id2 integer primary key AUTOINCREMENT not null ," +
" age text not null , " +
" weight text not null ," +
" height text not null, " +
" sex text not null, " +
" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE1_NAME+"("+COLUMN_ID+")," +
" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE5_NAME+"("+COLUMN_ID5+"));";
//" FOREIGN KEY ("+ COLUMN_ID2 +") REFERENCES "+TABLE6_NAME+"("+COLUMN_ID6+"));";
basically the foreign keys don't show up in the db when viewing it.
I've tried adding in
"id integer not null"
before the first foreign key line and that made the database stop writing data to that table. I've updated the database version to see if that would make a difference too, but to no avail.
Am I calling it wrong? I could just be missing the correct way to write in the column the foreign key goes into. Though I'm not sure how it would be inserted the correct way.
I believe your issue is a misunderstanding of what the FOREIGN KEY .... clause does.
It does not create a column for storing the foreign key. Rather it adds a constraint (a rule) that says that the column(s) in the table being created MUST contain an existing value in the table(columns) specified after REFERENCES.
The statements are correct and actually do create the Foreign Key constraints; as will be shown.
Consider the following (taken by running the code using Android Studio that you have supplied (plus code to make it usable) and thus creating the database and the tables needed)
using DEBUG to stop when creating the Uinfo table (as well as the other tables) and copying the value from the TABLE2_CREATE variable the value obtained is :-
create table Uinfo(id2 integer primary key AUTOINCREMENT not null , age text not null , weight text not null , height text not null, sex text not null, FOREIGN KEY (id2) REFERENCES contacts(id), FOREIGN KEY (id2) REFERENCES calendar(id5));
Dropping this value into an SQLite tool (navicat) and then running the following SQL:-
create table contacts (id integer primary key AUTOINCREMENT not null , name text not null , email text not null , pass text not null, uname text not null);
CREATE TABLE calendar(id5 INTEGER PRIMARY KEY,other TEXT);
create table Uinfo(id2 integer primary key AUTOINCREMENT not null , age text not null , weight text not null , height text not null, sex text not null,
FOREIGN KEY (id2) REFERENCES contacts(id),
FOREIGN KEY (id2) REFERENCES calendar(id5));
SELECT * FROM Uinfo;
INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female');
Results in :-
Clearly the INSERT did not insert the data. A look at the log shows:-
create table Uinfo(id2 integer primary key AUTOINCREMENT not null , age text not null , weight text not null , height text not null, sex text not null,
FOREIGN KEY (id2) REFERENCES contacts(id),
FOREIGN KEY (id2) REFERENCES calendar(id5))
> OK
> Time: 0.074s
SELECT * FROM Uinfo
> OK
> Time: 0s
INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female')
> FOREIGN KEY constraint failed
> Time: 0s
So the foreign key constraint has been added.
Doing the equivalent in the testing Android App was undertaken using the code:-
public class MainActivity extends AppCompatActivity {
DatabaseHelper DBHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DBHelper = new DatabaseHelper(this);
SQLiteDatabase db = DBHelper.getWritableDatabase();
db.execSQL("INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female')");
Log.d("DBINFO","After the first insert");
db.execSQL("PRAGMA foreign_keys = true");
db.execSQL("INSERT INTO Uinfo VALUES(null,10,5.6,70,'Female')");
Log.d("DBINFO","After the second insert");
}
}
results in :-
2021-04-24 15:34:27.954 5644-5644/a.a.so67224090javafknotshowing D/DBINFO: After the first insert
2021-04-24 15:34:27.955 5644-5644/a.a.so67224090javafknotshowing D/AndroidRuntime: Shutting down VM
2021-04-24 15:34:27.957 5644-5644/a.a.so67224090javafknotshowing E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.a.so67224090javafknotshowing, PID: 5644
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so67224090javafknotshowing/a.a.so67224090javafknotshowing.MainActivity}: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:748)
at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:754)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:64)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1770)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1698)
at a.a.so67224090javafknotshowing.MainActivity.onCreate(MainActivity.java:20)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
The App has crashed with an exception, the exception message being FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
BUT the log also contains D/DBINFO: After the first insert.
i.e. the first INSERT did not cause the exception, it was the second after THE IMPORTANT db.execSQL("PRAGMA foreign_keys = true");
Without this line (or an equivalent) then the default on Android (as it is with the default SQLite) is that Foreign Key processing is turned off. The above turns Foreign Key processing on.
So if you issue is more that the foreign keys do nothing then this could be the cause.
I need to update one field only in my table :
static Future<void> updateType(Statement statement, String type) async {
await db.update('StatementTABLE',
{'type' : '?'},
where: "id = ?",
whereArgs: [type,statement.id]);
}
But I have this error message :
"DatabaseException(Too many bind arguments. 3 arguments were provided
but the statement needs 2 arguments.) sql 'UPDATE StatementTABLE SET
type = ? WHERE id = ?' args [?, Sortie,
56fcb6b0-a283-11eb-a4d4-1ffc954983be]}"
I do not understand as I have well 2 arguments and not 3 ..
whereArgs is only to replace values in whee clause. type should be in the map :
await db.update('StatementTABLE',
{'type' : type},
where: "id = ?",
whereArgs: [statement.id]);
I am trying to have SQLite create automatic timestamps with CURRENT_TIMESTAMP.
I took the liberty of using Google's code:
// roomVersion = '2.2.2'
#Entity
public class Playlist {
#PrimaryKey(autoGenerate = true)
long playlistId;
String name;
#Nullable
String description;
#ColumnInfo(defaultValue = "normal")
String category;
#ColumnInfo(defaultValue = "CURRENT_TIMESTAMP")
String createdTime;
#ColumnInfo(defaultValue = "CURRENT_TIMESTAMP")
String lastModifiedTime;
}
#Dao
interface PlaylistDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(playlist: Playlist): Long
}
This translates into an SQLite-Statement:
CREATE TABLE `Playlist` (
`playlistId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` TEXT,
`description` TEXT,
`category` TEXT DEFAULT 'normal',
`createdTime` TEXT DEFAULT CURRENT_TIMESTAMP,
`lastModifiedTime` TEXT DEFAULT CURRENT_TIMESTAMP
)
I did make one insert:
mDb.playListDao().insert(Playlist().apply { name = "Test 1" })
But the timestamps are always Null.
With the DB Browser for SQLite I added another entry, here I get timestamps.
How do I insert without a Null-Timestamp in room?
(Info: createdTime is also always the same as lastModifiedTime. I think this has to be done with triggers in SQLite, but that is a different problem not to be discussed here).
You don't need to use another class, you can use #Query as an alternative to the convenience #Insert.
as per :-
There are 4 type of statements supported in Query methods: SELECT, INSERT, UPDATE, and DELETE.
Query
e.g.
#Query("INSERT INTO test_table001 (name) VALUES(:name) ")
void insert(String name);
You are also not limited to CURRENT_TIMESTAMP as the only means of getting the current timestamp you can use embedded datetime functions (as is shown below), which can store the value more efficiently and also be more flexible e.g. you could adjust the current time using modifiers such as '+7 days'.
If you consider the following :-
#Entity(tableName = "test_table001")
public class TestTable001 {
#PrimaryKey
Long id;
#ColumnInfo(defaultValue = "CURRENT_TIMESTAMP")
String dt1;
#ColumnInfo(defaultValue = "(datetime('now'))")
String dt2;
#ColumnInfo(defaultValue = "(strftime('%s','now'))")
String dt3;
String name;
}
Note that the inefficient autogenerate = true has not been used BUT as will be shown you can still have an SQLite assigned id (note that you must use the type Long/Integer as opposed to long or int)
Also note the alternative ways of getting the current date time (the latter being more efficient as the value will ultimately be stored as an Integer (max 8 bytes) rather than a more byte hungry String).
With a Dao as :-
#Dao
public interface TestTable001Dao {
#Insert()
long insert(TestTable001 testTable001);
#Query("INSERT INTO test_table001 (name) VALUES(:name) ")
long insert(String name);
#Query("SELECT * FROM test_table001")
List<TestTable001> getAllTestTable001();
}
And the following to test/demonstrate :-
public class MainActivity extends AppCompatActivity {
AppDatabase mRoomDB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRoomDB = Room.databaseBuilder(this,AppDatabase.class,"testdb")
.allowMainThreadQueries()
.build();
TestTable001 tt01 = new TestTable001();
tt01.setName("tt01");
mRoomDB.useTestTable001().insert(tt01);
mRoomDB.useTestTable001().insert("tt02");
logAllTestTable001();
}
private void logAllTestTable001() {
for (TestTable001 tt: mRoomDB.useTestTable001().getAllTestTable001()) {
Log.d(
"TTINFO",
"ID = " + tt.getId() +
" Name = " + tt.getName() +
" Date1 = " + tt.getDt1() +
" Date2 = " + tt.getDt2() +
" Date3 = " + tt.getDt3());
}
}
}
The result is :-
2019-12-14 03:18:32.569 D/TTINFO: ID = 1 Name = tt01 Date1 = null Date2 = null Date3 = null
2019-12-14 03:18:32.569 D/TTINFO: ID = 2 Name = tt02 Date1 = 2019-12-13 16:18:32 Date2 = 2019-12-13 16:18:32 Date3 = 1576253912
Found it. Did not read the manual.
You have to create a 2nd class without the auto-set fields to insert.
public class NameAndDescription {
String name;
String description
}
I think, this is not a good idea.
If you have an autoincrement field in the DB it will get an automatically updated value when you pass 0.
Likewise the default value of the timestamp should be used when passing null or "".
I found the best solution was creating an abstract Dao that implemented the insert and update methods. I didn't get the default value to work (perhaps I was doing something wrong). Take a look at my answer here: How to implement created_at and updated_at column using Room Persistence ORM tools in android
I am currently learning JavaFX and Sqlite.
I have an Sqlite Database which I built with MySQL manager, there are already foreign key rules etc.
For example user and adress:
CREATE TABLE "Benutzer" ("Benutzername" TEXT PRIMARY KEY NOT NULL , "Vorname" VARCHAR, "Nachname" VARCHAR, "Email" TEXT UNIQUE , "Passwort" TEXT, "AdresseID" INTEGER, FOREIGN KEY(AdresseID) REFERENCES Adresse(AdresseID))
CREATE TABLE "Adresse" ("AdresseID" INTEGER PRIMARY KEY NOT NULL , "Land" VARCHAR, "Stadt" VARCHAR, "Straße" TEXT, "Hausnr." INTEGER)
I connected the database to my JavaFX application, now I am trying to create the register function, so a new user is on an fxml template where he can fill in "Benutzername", "Vorname" etc. and his adress "Land", "Stadt" etc.
Here is the form:
Adding these values to the database works, but I do not have an idea how to tell javaFX that this current user which is inserted has to take the current adress which is inserted (its AdressID) as foreign key.
User is inserted without foreign key:
I was reseaching and found things like
mysql_insert_id returns the last auto-increment value generated by the database connection currently in use.
But I dont know how to access it.
Thats my model which I use to fill in the data into my database:
public class RegisterModel {
Connection conection;
// Konstruktor
public RegisterModel() {
conection = SqliteConnection.Connector();
// Wenn die Verbindung nicht erfolgreich ist, dann App schließen
if (conection == null) {
System.out.println("connection not successful");
System.exit(1);
}
}
public boolean isDbConnected() {
try {
return !conection.isClosed();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public boolean RegisterUser(String user_benutzername, String user_vorname, String user_nachname, String user_email,
String user_passwort, String adress_land, String adress_stadt, String adress_strasse,
String adress_hausnummer) throws SQLException {
PreparedStatement preparedStatement = null;
PreparedStatement preparedStatement_for_adress = null;
// or ignore besprechen
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort) values(?,?,?,?,?)";
String query_adress = "insert into Adresse (Land, Stadt, Straße, 'Hausnr.') values(?,?,?,?)";
try {
preparedStatement = conection.prepareStatement(query);
preparedStatement.setString(1, user_benutzername);
preparedStatement.setString(2, user_vorname);
preparedStatement.setString(3, user_nachname);
preparedStatement.setString(4, user_email);
preparedStatement.setString(5, user_passwort);
System.out.println("Benutzer wurde eingefuegt");
preparedStatement_for_adress = conection.prepareStatement(query_adress);
preparedStatement_for_adress.setString(1, adress_land);
preparedStatement_for_adress.setString(2, adress_stadt);
preparedStatement_for_adress.setString(3, adress_strasse);
preparedStatement_for_adress.setString(4, adress_hausnummer);
System.out.println("Adresse wurde eingefügt");
preparedStatement.executeUpdate();
preparedStatement_for_adress.executeUpdate();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
preparedStatement.close();
preparedStatement_for_adress.close();
}
}
}
I think there must be a 3rd query which takes the AdressID of the current adress and assigns it to the current user as his adress? So thats the interessting part:
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort) values(?,?,?,?,?)";
String query_adress = "insert into Adresse (Land, Stadt, Straße, 'Hausnr.') values(?,?,?,?)";
You should insert the Address first with a PreparedStatement.
Retrieve the ID (last inserted ID) of the Address, see Java PreparedStatement retrieving last inserted ID
Now insert the User with the AddressId stated in step 2. So you have to include the AddressId column in the user INSERT INTO statement.
Your user insert query should become:
String query = "insert or ignore into Benutzer (Benutzername, Vorname, Nachname, Email, Passwort, AddressId) values(?,?,?,?,?,[put last_inserted_id here)";
I call
public bool CheckIfFinished ( Guid pid, int sid )
{
// pid: guid corresponding to partner
// sid: survey id
bool finished = false;
using (SqlCommand cmd = new SqlCommand("CheckIfFinished", this._Conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#pid", pid);
cmd.Parameters.AddWithValue("#sid", sid);
this._Conn.Open();
using ( SqlDataReader dataReader = cmd.ExecuteReader() )
{
while (dataReader.Read())
{
finished = dataReader.GetByte(0) == 1 ? true : false;
}
}
this._Conn.Close();
}
return finished;
}
which calls the sproc
GO
-- Create sproc for returning whether a partner has marked their survey as finished
CREATE PROCEDURE CheckIfFinished
#pid UNIQUEIDENTIFIER,
#sid INT
AS
BEGIN
SELECT 1 FROM FinishedMappings WHERE partner_id=#pid AND survey_id=#sid
END
which uses the table FinishedMappings which does exist because it was defined with
CREATE TABLE FinishedMappings (
partner_id UNIQUEIDENTIFIER,
survey_id INT,
PRIMARY KEY (partner_id,survey_id),
FOREIGN KEY (partner_id) REFERENCES Partners(id),
FOREIGN KEY (survey_id) REFERENCES Surveys(id)
);
right above the sproc. Why am I getting the error?
If the table was created using a different user to the one that you are executing the sp with then a fully qualified name could be needed. I would check this first as dimasun suggested in his first reply.
Also check to see if you can execute the sp directly in SQL management studio. If this doesn't work then you can focus on the code in the sp