DBFlow - inner join with another select statement - android

I'm trying to convert the following SQL statement into DBFlow method calls:
SELECT t.SSID, t.BSSID, t.Latitude, t.Longitude, t.Timestamp
FROM wlan_events t
INNER JOIN (SELECT BSSID, MAX(Timestamp) AS MaxTimestamp FROM wlan_events GROUP BY BSSID) groupedt
ON t.BSSID = groupedt.BSSID AND t.Timestamp = groupedt.MaxTimestamp
What I got so far:
SQLite.select(WifiEvent_Table.SSID, WifiEvent_Table.BSSID, WifiEvent_Table.latitude,
WifiEvent_Table.longitude)
.from(WifiEvent.class)
.as("t")
.innerJoin(WifiEvent.class) // ????
;
How do i create that inner join's select statement using dbflow?

This is what I found:
SELECT EMP_ID, NAME, DEPT FROM COMPANY LEFT OUTER JOIN DEPARTMENT
ON COMPANY.ID = DEPARTMENT.EMP_ID
in DBFlow:
SQLite.select(Company_Table.EMP_ID, Company_Table.DEPT)
.from(Company.class)
.leftOuterJoin(Department.class)
.on(Company_Table.ID.withTable().eq(Department_Table.EMP_ID.withTable()))
.queryList();
Hope this helps: (Link updated)
https://agrosner.gitbooks.io/dbflow/content/

Related

Get vararg parameter size in Room Query

Say I have a DB with two main entities (Song and Tag) and a many-to-many relationship between them. Using Room, I want to query the Songs that have a series of Tags (all of them) by their names.
So, given this example data in the cross ref table (SongTagCrossRef):
Song
Tag
song1
tag1
song1
tag2
song1
tag3
song2
tag2
song3
tag2
song3
tag3
I want the query to return only song1 if I enter tag1 and tag2, as it's the only song related to both.
I've come up with this #Query in the corresponding Dao:
#Query("""
SELECT s.* FROM Song s
JOIN SongTagCrossRef st ON s.song_id = st.song_id
JOIN Tag t ON st.tag_id = t.tag_id
WHERE t.name IN (:tagNames)
GROUP BY s.song_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM Tag WHERE name IN (:tagNames))
""")
fun getSongsWithAllOfTheTagsByName(vararg tagNames: String): List<SongEntity>
Since I can't access tagNames.size in the #Query, I've had to use a subquery to artificially get it. This subquery shouldn't be too heavy, but it would always be better to somehow access tagNames.size.
After reading the answers to a slightly related question, I've been toying with creating a #RawQuery and calling it from a function that takes only tagNames, something along these lines:
#RawQuery
fun getSongsWithAllOfTheTagsByName(query: SupportSQLiteQuery): List<SongEntity>
fun getSongsWithAllOfTheTagsByName(vararg tagNames: String): List<SongEntity> {
val query = SimpleSQLiteQuery("""
SELECT s.* FROM Song s
JOIN SongTagCrossRef st ON s.song_id = st.song_id
JOIN Tag t ON st.tag_id = t.tag_id
WHERE t.name IN (?)
GROUP BY s.song_id
HAVING COUNT(*) = ?
""", arrayOf(tagNames, tagNames.size))
return getSongsWithAllOfTheTagsByName(query)
}
(only converting tagNames to something it can actually swallow)
But I've discarded this approach because I don't want to expose a function that takes a query.
Is there a simpler, more elegant way to write this query?
I finally did it, so I want to share what I found out. It's actually not quite straightforward, but it does the trick.
Going through the SQLite documentation, I came upon the JSON1 extension and more specifically the json_array() and json_array_length() functions.
However, to use this extension, as CommonsWare points out in this answer and Hooman summarises here, Requery's standalone library must be used, through RequerySQLiteOpenHelperFactory.
In conclusion:
build.gradle file
dependencies {
...
implementation 'com.github.requery:sqlite-android:3.36.0'
...
}
Room database class
Room.databaseBuilder(...)
...
.openHelperFactory(RequerySQLiteOpenHelperFactory())
...
.build()
Dao interface
#Query("""
SELECT s.* FROM Song s
JOIN SongTagCrossRef st ON s.song_id = st.song_id
JOIN Tag t ON st.tag_id = t.tag_id
WHERE t.name IN (:tagNames)
GROUP BY s.song_id
HAVING COUNT(*) = JSON_ARRAY_LENGTH(JSON_ARRAY(:tagNames))
""")
fun getSongsWithAllOfTheTagsByName(vararg tagNames: String): List<SongEntity>

Android exception in sql query that runs fines in DB Browser

When running the following query on Android
select *
from EICRChecklistItems
where (Sect, S_Sect, SS_Sect) in (
select Sect, S_Sect, SS_Sect
from EICRCheckList
where Version=2018
order by id
)
order by id
I get the exception:
android.database.sqlite.SQLiteException: near ",": syntax error (code
1)
Columns Sect, S_Sect and SS_Sect are all defined as integer.
But when running on DB Browser against a copy of the same database it executes correctly
Any pointers as to what may be causing this would be greatly appreciated.
private var EICR_CHECK_ITEMS_TABLE = "EICRChecklistItems"
private var EICR_CHECKLIST_TABLE = "EICRCheckList"
val cursor1: Cursor = writableDatabase.rawQuery(
"select * from $EICR_CHECK_ITEMS_TABLE where (Sect, S_Sect, SS_Sect) in (select Sect, S_Sect, SS_Sect from $EICR_CHECKLIST_TABLE where Version='2018' order by id) order by id", null)
Since your SQLite's version is prior to 3.15.0 and you can't use ROW VALUES, you can write your query with EXISTS instead of the operator IN:
SELECT ei.*
FROM EICRChecklistItems ei
WHERE EXISTS (
SELECT 1 FROM EICRCheckList el
WHERE el.Version = 2018
AND el.Sect = ei.Sect AND el.S_Sect = ei.S_Sect AND el.SS_Sect = ei.SS_Sect
)
ORDER BY ei.id
Note that the ORDER BY clause that you had inside the subquery in your code is actually useless.

Return type of GROUP BY statement in Room Database

I would like to make the following query to my database:
SELECT type, COUNT(*) FROM offerings GROUP BY type
This query works well with an Sqlite browser. Now I want to use this query in my Dao:
#Query("SELECT type, COUNT(*) FROM offerings GROUP BY type")
LiveData<Map<String, Integer>> getOfferingsGroupedByType();
But I am getting the error: ... not sure how to convert a cursor to this method's return type
How can I query a table with 2 columns? --> that is, [type, count(type)] ?
Step #1: Give a name to the count: SELECT type, COUNT(*) AS count FROM offerings GROUP BY type
Step #2: Create a Java class with suitable fields:
public class Thingy {
public String type;
public int count;
}
Step #3: Have your return type from the DAO method use that class:
#Query("SELECT type, COUNT(*) FROM offerings GROUP BY type")
LiveData<List<Thingy>> getOfferingsGroupedByType();
I don't recall Room supporting returning a Map, so you will need to handle that aspect yourself, either in the observer or via a MediatorLiveData that wraps the LiveData you get from the DAO and does the conversion.

Multiple LIKE statement using AND in Sqlite.

I want to select recipe_id for recipes that have my both ingredient but I cant use AND like this(I mean it returns null for all columns) :
SELECT
vsearch.ingredient_id,
vsearch.ingredtypes_id,
vsearch.name,
vsearch.recipe_id,
vsearch.qingred
FROM
vsearch
WHERE
vsearch.name = 'olive' AND vsearch.name = 'apple'
vsearch is a View which is:
SELECT
ingredient.ingredient_id,
ingredient.ingredtypes_id,
ingredient.name,
quantity.recipe_id,
quantity.ingredient_id AS qingred
FROM
ingredient ,
quantity
WHERE
strong textingredient.ingredient_id = quantity.ingredient_id
And heres my database tables:
To find (for example) find the recipe id's that contain both cucumber and tomato;
SELECT recipe_id
FROM vsearch
WHERE name = 'cucumber' OR name = 'tomato'
GROUP BY recipe_id
HAVING COUNT(*) = 2
...where 2 is the name of ingredients that have to match (in this case both)
An SQLfiddle to test with.
select *
from vsearch
where recipe_id
in
( select recipe_id from vsearch where name = 'apple'
intersect
select recipe_id from vsearch where name = 'olive'
)

Use class to represent foreign key / join table in Android SQLite?

I need to use classes to represent entities in database, here are some information:
=== TABLEs ===
SHOP
shop_id(primary)
name
owner
FAVOURITES LIST
fav_id(primary)
list_name
(JOIN)FAV_SHOPS
fav_id(primary)
shop_id(primary)
If I use a class Shop to represent shop entity, and FavShops to represent fav_shops, FavShops is written as below:
class FavShop {
int fav_id;
String list_name;
NSSet<Shop> shops;
}
Then how do I retrieve fav_shops from database in SQLite(Android)? I'll be appreciated if any one can provide some SQL statement, I also need to save the list to database, say, I added another shop to FavShop "My Favourites", how do I save it back to database?
Thanks!
You can use JOIN to get your FavShops table..
SELECT * FROM fav_shops INNER JOIN favourites_list ON fav_shops.fav_id = favourite_list.fav_id WHERE favourite_list.fav_id = <YOUR_LIST_ID>
You can put whatever clause you need in your WHERE (shop_id = ?, list_name = ?, etc..)
And to insert a new row in the fav_shops table
INSERT INTO fav_sops (fav_id, shop_id) values ('My Favourites', <A_SHOP_ID>);

Categories

Resources