How to "Create Trigger" using Room Persistence library
CREATE TRIGGER IF NOT EXISTS delete_till_10 INSERT ON user WHEN (select count(*) from user)>9
BEGIN
DELETE FROM user WHERE id IN (SELECT id FROM user ORDER BY id limit (select count(*) -9 from user));
END
Call getOpenHelper() on your RoomDatabase. This gives you a SupportSQLiteOpenHelper, which has an API reminiscent of SQLiteOpenHelper. On there, call getWritableDatabase() to get a SupportSQLiteDatabase, and on there use execSQL() to execute your SQL statements. A RoomDatabase.Callback is one place to execute this sort of SQL, as AdamMc331 illustrates in this Kotlin snippet.
IOW, Room does not really help with this scenario, but you can always work with the lower-level database API for cases like this one.
Related
I migrate my database from DBFlow to Room finally.
However, some queries I made for my old database don't really match what I know about Room. So in my Entity I have / had these calls:
"CREATE INDEX IF NOT EXISTS `idDeletedStartEndLocalIndex` ON `QUANTITY`(START_LOCAL, END_LOCAL DESC)"
I implemented that in Room as
Index("START_LOCAL", "END_LOCAL")
but how can I add the Descending at the index? Should I just write "END_LOCAL DESC"? Would that work as expected?
Same for this one
"CREATE UNIQUE INDEX IF NOT EXISTS `serverQtyId` ON QUANTITY(SERVER_QUANTITY_ID) WHERE SERVER_QUANTITY_ID > 0"
How can I add the WHERE SERVER_QUANTITY_ID > 0 clause to the Index annotation of room? Is that even possible?
Okay, looks like there are not many ways around this. So I did the queries manually.
For those who have the same problem, my code looks like this:
runBlocking(Dispatchers.IO){
with (getInstance().openHelper.writableDatabase) {
execSQL("CREATE INDEX IF NOT EXISTS `someIndexName` ON `QUANTITY`(...)")
...
}
}
So what I do is basically get the Database Instance and their openHelper. From there you can get the writable Database. It then supports executing SQL queries directly.
All this is run in the IO coroutine scope but that's just for convenience.
I implemented an app using an SQLite database and the data are stored in background without any user interactions. The only point where the use is needed is when data are deleted with an gesture and that is my question.
Is it possible to make an SQL injection through a gesture and if so, how can I prevent it?
If the user is not inputting text then SQL Injection is highly unlikely.
However, if you use the convenience methods fully and or rawQuery execSQL with the 2nd parameter, passing any values via the 2nd parameter then the values will be bound which protects against SQL injection.
This assumes that you are using the standard SQLiteDatabase as per the SDK.
Examples of inserting rows
This example uses execSQL (both forms) and the insert convenience method to demonstrate the principles of using bound arguments and in the first example of not using a bound argument.
theSQLitedatabase.execSQL("INSERT INTO mytable VALUES('" + userdata + "')"); //<<<<<< potential for injection
theSQLitedatabase.execSQL("INSERT INTO mytable VALUES(?)",new String[]{userdata}); //<<<<< protects as value is bound by SQLite itself
/* Uses the convenience method that builds the SQL (as per 2nd example) and protects */
ContentValues cv = new Contentvalues();
cv.put(the_column_name_as_a_string,userdata);
theSQLitedatabase.insert("mytable",null,cv);
I am using this query
"select * from SomeTable group by SomeColumn"
It is returns list with accenting order, but i need to same order like in database.
For example the order in database is:
p
a
s
But result is:
a
i
p
Sample
The result need to be like distinct by CityEN but with all columns and order like 1.Paris 2.Amsterdam 3.Istanbul
In Sqlite, each row of a table has a unique rowid, which you can use for sorting.
select * from SomeTable group by SomeColumn order by rowid;
In your statement, add this line to sort the results:
order by min(rowid)
Your query does not enforce any order with ORDER BY clause so no assumption about row order should be made. If you want specific order add i.e. ORDER BY SomeColumn. See docs about all available order options: https://www.sqlite.org/lang_select.html#orderby
By the rules of SQL, you can't count on getting records back in any specific order without specifying an ORDER BY clause in your SQL query.
In practice servers sometimes return values in the order in which they're inserted, in the order of the first index created, or in the order of the primary key--but you can't count on this behavior, and in fact I've seen the behavior change between database maintenance windows or after the database version is upgraded. You definitely wouldn't want to count on a DB engine to give you back records in any particular order if you write a SELECT statement without an ORDER BY clause.
The only real way to get your records back in the order you inserted them is to create a timestamp column and then sort on it during the SELECT. If you don't want to worry about populating that column on INSERT, have that column auto-populate itself with a timestamp (depending on your DB engine).
Is there any way I can create and drop tables similar to a 'RawQuery'?
I tried with a #RawQuery annotation (which it would be the perfect solution for me) but when I am compiling I get an error saying methods annotated with RawQuery can't return void.
I read only SELECT, UPDATE and DELETE statements are allowed when using #Query.
I would like to achieve the "creation or deletion of tables" by passing a tablename as a parameter, something like the following:
#Query("DROP TABLE :name")
void deleteTable (String name);
Any ideas on how to achieve this?
Thanks!
Official doc states that,
RawQuery serves as an escape hatch where you can build your own SQL query at runtime but still use Room to convert it into
objects.
RawQuery methods must return a non-void type. If you want to execute a raw query that does not return any value, use
RoomDatabase#query methods.
or use it like,
#RawQuery
int deleteTable (SupportSQLiteQuery query); //We can return int status like it used to return with database.delete()
//Usage
dao.deleteTable(
new SimpleSQLiteQuery("DROP TABLE tablename")
)
The ting is, wit Room, you don't have to "drop" tables, the tables re created based on your entity classes (annotated with #Entity).
As far as I know, you usually need to drop tables in case the columns change or there are some updates on the "structure", with Room there's no point in doing this unless you change the structure of your entity that can't be automatically handled by the migration. In this case, Room gives you the chance to do the migration by yourself. Check the documentation here: https://developer.android.com/training/data-storage/room/migrating-db-versions
But like the documentation states, be really careful with this.
I wanna insert some row to a table in Android, I'm using this:
INSERT INTO MyTable (Column_1, Column_1) VALUES ('X',100);
The query runs and no exception is thrown, but when I retrieve all rows from MyTable, no row
is returned.
I do not want to use the insert method, because the queries are read from a file and I want to insert them to the database.
What's wrong with my code?
Update : The rawQuery() method doesn't run the query, but execSQL() does.
The title of your question suggests you're using rawQuery(). It just compiles the SQL but does not run it. Calling one of the moveTo...() methods on the returned Cursor would also execute the SQL.
For an insert query, use execSQL() instead of rawQuery(), even if the documentation incorrectly states it should not be used with INSERT.
How is your Table organized?
You seem to use twice the same column Column_1 is this a typo?
Alternative, you could use insert-command of SQListeDatabase insteat:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert%28java.lang.String,%20java.lang.String,%20android.content.ContentValues%29