SQLite - How to use ROW_NUMBER() OVER - android

I wanted to get information about streaks of certain challenges from my database. I experimented with all of my queries in sqliteonline.com and therefore I found a query which meets my requirements to get these information:
select challengeid, min(date) as min_date, max(date) as max_date, count(*) as length from (select t.*, row_number() over (partition by challengeid order by date) as seqnum from ACTIVE_CHALLENGES_TABLE t) t group by challengeid, date(date, '-' || seqnum || ' day') HAVING challengeid = 4 AND value != 0
Everything works fine on sqliteonline.com, but when it comes to Android Studio I get following error:
android.database.sqlite.SQLiteException: near "(": syntax error (code 1): , while compiling: select challengeid, min(date) as min_date, max(date) as max_date, count() as length from (select t., row_number() over (partition by challengeid order by date) as seqnum from ACTIVE_CHALLENGES_TABLE t) t group by challengeid, date(date, '-' || seqnum || ' day') HAVING challengeid = 4 AND value != 0
I already tried finding out what causes the error. Throughout testing I found out that it could be the use of this snippet: SELECT row_number() OVER (challengeid) seqnum from ACTIVE_CHALLENGES_TABLE
I don't know what I should do. Can you please help me?

If your version of SQLite does not support window functions you can use a correlated subquery to get the column seqnum:
select challengeid, min(date) as min_date, max(date) as max_date, count(*) as length
from (
select t.*,
(
select count(*) + 1 from ACTIVE_CHALLENGES_TABLE
where challengeid = t.challengeid
and (date < t.date or (date = t.date and rowid < t.rowid))
) as seqnum
from ACTIVE_CHALLENGES_TABLE t
where t.challengeid = 4 and t.value != 0
)
group by challengeid, date(date, '-' || seqnum || ' day')
Note that I removed the HAVING clause, which does not make sense since it does not filter out any aggregated columns and I replaced it with a WHERE clause inside the subquery, since you want results only under the condition:
challengeid = 4 and value != 0

Related

SQLITE: How to get One row from table + get rest of rows in different order

I have a table with below rows.
rowid type value
1 A 13
2 A 14
3 B 12
4 B 15
5 C 17
6 C 16
I want to get the bigest value of type A first, it's rowid=2, then others in order by value DESC, the rowids are 56413
How to implement it sqlite? Thanks a lot!
If you wanted to do this only in the order by:
order by (case when type = 'A' and
value = (select max(t2.value) from t t2 where t2.type = 'A')
then 1 else 2
end),
value desc;
Or:
select t.*
from t cross join
(select max(value) as maxvalue from t where type = 'A'
) ta
order by (case when t.type = 'A' and t.value = ta.maxvalue then 1 else 2 end),
value desc;
Simply use the UNION clause to join 2 queries in one.
SELECT Type, Value FROM YourTableName WHERE rowID = 2
UNION
SELECT Type, Value FROM YourTableName WHERE rowID != 2 ORDER BY value DESC

SQLite SUM() between several rows

I need some help with the SUM feature in android app. I have a table that looks something like the following :
I have need to SUM Quantities between last two records Notes and last one record with Note. I need to sum Quantity of rows 31,32 and 33. It would return 90. I've tried
SELECT Sum(QUANTITY) FROM fuel_table WHERE NOTE!='' ORDER BY ID DESC
but it returns SUM of all quantities with note.
I am inclined to phrase the question as: sum the quantity from all rows that have one note "ahead" of them. This suggests:
select sum(quantity)
from (select ft.*,
(select count(*)
from fuel_table ft2
where ft2.note = 'Yes' and ft2.id >= ft.id
) as numNotesAhead
from fuel_table ft
) ft
where numNotesAhead = 1;
WITH max_id_with_note AS
(
SELECT MAX(ID) AS max_id
FROM YourTable
WHERE IFNULL(note, '') <> ''
)
, previous_max_id_with_note AS
(
SELECT max(ID) as max_id
FROM YourTable
WHERE IFNULL(note, '') <> ''
AND ID < (SELECT max_id FROM max_id_with_note)
)
SELECT SUM(Quantity)
FROM YourTable
WHERE (SELECT max_id FROM previous_max_id_with_note)
< ID and ID <=
(SELECT max_id FROM max_id_with_note)
Example at SQL Fiddle.
First select few ROW and from this selection query SUM(). In your case it looks like this:
Select SUM(t1.QUANTITY) FROM (SELECT QUANTITY from fuel_table WHERE NOTE!='' ORDER BY ID limit 2) as t1
Change your query as
SELECT Sum(QUANTITY) FROM fuel_table ORDER BY ID DESC LIMIT 3
I created table like you have and test. Andomar had good idea but made few mistakes!
WITH max_id_with_note AS
(
SELECT MAX(ID) AS max_id
FROM fuel_table
WHERE Note <> ''
)
, previous_max_id_with_note AS
(
SELECT max(ID) as max_id
FROM fuel_table
WHERE Note <> ''
AND ID < (SELECT max_id FROM max_id_with_note)
)
SELECT SUM(Quantity)
FROM fuel_table
WHERE (SELECT max_id FROM previous_max_id_with_note)
< id and id <= (SELECT max_id FROM max_id_with_note)
Use sub query to get your QUANTITY in deceasing order by ID and LIMIT 3 as you want last 3 row and put SUM() to the result quantity...
SELECT SUM(QUANTITY) FROM (SELECT QUANTITY FROM fuel_table ORDER BY ID DESC LIMIT 3);

Android Contacts.CONTENT_STREQUENT_URI throws SQLiteException on Android 4.1.2 and 4.4.2

I need some assistance with this.
I am trying to query the strequent table (ContactsContract.CONTENT_STREQUENT_URI) on Android to get starred and most frequently contacted contacts.
Cursor cursor = context.getContentResolver().query(Contacts.CONTENT_STREQUENT_URI,
new String[]{Contacts._ID, Contacts.LOOKUP_KEY, Contacts.STARRED, Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY
: Contacts.DISPLAY_NAME}, null,
null, null
);
On most devices and Android versions it works fine. But on Android 4.1.2 versions I'm getting this SQLiteException
{AsyncTask #2} android.database.sqlite.SQLiteException: near "(": syntax error (code 1): ,
while compiling: SELECT * FROM (SELECT _id, lookup, starred, display_name, 9223372036854775807
AS times_used, 9223372036854775807 AS last_time_used FROM view_contacts WHERE
(view_contacts.[single_is_restricted] = 0(1)) AND (starred=1) GROUP BY _id ORDER
BY display_name COLLATE LOCALIZED ASC) UNION ALL SELECT * FROM (SELECT _id,
lookup, starred, display_name, SUM(data_usage_stat.times_used) AS times_used,
MAX(data_usage_stat.last_time_used) AS last_time_used FROM view_data_usage_stat AS
data_usage_stat INNER JOIN view_contacts ON ((data_usage_stat.times_used > 0) AND
(contact_id=view_contacts._id)) WHERE (view_contacts.[single_is_restricted] = 0
AND ((starred =0 OR starred IS NULL) AND account_type NOT IN
('com.android.contacts.sim'))) GROUP BY _id HAVING contact_id IN default_directory
ORDER BY (CASE WHEN (strftime('%s', 'now') - last_time_used/1000) < 259200 THEN 0
WHEN (strftime('%s', 'now') - last_time_used/1000) < 2592000 THEN 1 ELSE 2 END),
times_used DESC LIMIT 10) at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:184) at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140) at
android.content.ContentProviderProxy.query(ContentProviderNative.java:366) at
android.content.ContentResolver.query(ContentResolver.java:371) at
android.content.ContentResolver.query(ContentResolver.java:314) at
(...)
I'm pretty sure that this other SQLiteException that I'm getting on Android 4.4.2 versions is related:
android.database.sqlite.SQLiteException: near ")": syntax error (code 1): , while
compiling: SELECT * FROM (SELECT _id, lookup, starred, display_name,
9223372036854775807 AS times_used, 9223372036854775807 AS last_time_used FROM
view_contacts WHERE (view_contacts.[single_is_restricted] = 0 AND ) AND
(starred=1) GROUP BY _id ORDER BY display_name COLLATE LOCALIZED ASC) UNION ALL
SELECT * FROM (SELECT _id, lookup, starred, display_name,
SUM(data_usage_stat.times_used) AS times_used, MAX(data_usage_stat.last_time_used)
AS last_time_used FROM view_data_usage_stat AS data_usage_stat INNER JOIN
view_contacts ON ((data_usage_stat.times_used > 0) AND
(contact_id=view_contacts._id)) WHERE (view_contacts.[single_is_restricted] =
0((starred =0 OR starred IS NULL) AND account_type NOT IN
('com.android.contacts.sim'))) GROUP BY _id HAVING contact_id IN default_directory
ORDER BY (CASE WHEN (strftime('%s', 'now') - last_time_used/1000) < 259200 THEN 0
WHEN (strftime('%s', 'now') - last_time_used/1000) < 604800 THEN 1 WHEN
(strftime('%s', 'now') - last_time_used/1000) < 1209600 THEN 2 WHEN
(strftime('%s', 'now') - last_time_used/1000) < 2592000 THEN 3 ELSE 4 END),
times_used DESC LIMIT 10) WHERE (strftime('%s', 'now') - last_time_used/1000)
<2592000 at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:181) at
android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137) at
android.content.ContentProviderProxy.query(ContentProviderNative.java:413) at
android.content.ContentResolver.query(ContentResolver.java:464) at
android.content.ContentResolver.query(ContentResolver.java:407) at
(...)
My understanding is that Android Content Resolver is building the SQL query incorrectly. Am I missing something? Has anyone encountered this or can suggest a workaround? Is there another/simpler query that can be used? I would like to maintain this feature for these Android versions :(

Row data as column in time keeper

I have data from table CheckInOut
select UserEnrollNumber,TimeDate,TimeStr from DATACHAMCONG.dbo.CheckInOut
UserEnrollNumber TimeDate TimeStr
50559 2015-01-03 00:00:00.000 2015-01-03 07:21:32.000
50559 2015-01-03 00:00:00.000 2015-01-03 16:28:36.000
I want to display as:
UserEnrollNumber TimeDate IN1 OUT1 IN2 OUT2 IN3 OUT3
50559 2014-01-03 2015-01-03 07:21:32.000 2014-01-03 17:11:22.000 NULL NULL NULL NULL
what kind support for me?
SAMPLE TABLE
CREATE TABLE #TEMP(UserEnrollNumber INT,TimeDate DATETIME,TimeStr DATETIME)
INSERT INTO #TEMP
SELECT 50559, '2015-01-03 00:00:00.000', '2015-01-03 07:21:32.000'
UNION ALL
SELECT 50559, '2015-01-03 00:00:00.000', '2015-01-03 16:28:36.000'
UNION ALL
SELECT 50559, '2015-01-04 00:00:00.000', '2015-01-04 07:15:32.000'
UNION ALL
SELECT 50559, '2015-01-04 00:00:00.000', '2015-01-04 08:13:36.000'
UNION ALL
SELECT 50559, '2015-01-04 00:00:00.000', '2015-01-04 09:28:36.000'
UNION ALL
SELECT 50559, '2015-01-04 00:00:00.000', '2015-01-04 16:15:32.000'
UNION ALL
SELECT 70987, '2015-01-03 00:00:00.000', '2015-01-03 04:08:32.000'
UNION ALL
SELECT 70987, '2015-01-03 00:00:00.000', '2015-01-03 14:01:36.000'
UNION ALL
SELECT 70987, '2015-01-05 00:00:00.000', '2015-01-05 06:18:32.000'
UNION ALL
SELECT 70987, '2015-01-05 00:00:00.000', '2015-01-05 15:21:36.000'
QUERY
I have written the logic inside the query.
SELECT UserEnrollNumber,CAST(TimeDate AS DATE)TimeDate,
TimeStr,[STATUS]+CAST(RNO AS VARCHAR(30))[STATUS],
-- Logic to order columns in pivot like IN1,OUT1,IN2,OUT2....
DENSE_RANK() OVER (ORDER BY RNO,[STATUS]) ORG
INTO #NEWTABLE
FROM
(
SELECT *,
-- 1st record will be IN next OUT next IN next OUT.....
CASE WHEN ROW_NUMBER() OVER(PARTITION BY UserEnrollNumber ORDER BY UserEnrollNumber,TimeDate,TimeStr)%2 = 0
THEN 'OUT' ELSE 'IN' END [STATUS],
-- Check the count of In-out in a date
(ROW_NUMBER() OVER(PARTITION BY UserEnrollNumber,CAST(TimeDate AS DATE) ORDER BY UserEnrollNumber,CAST(TimeDate AS DATE),TimeStr)+1)/2 RNO
FROM #TEMP
)TAB
ORDER BY UserEnrollNumber,CAST(TimeDate AS DATE),TimeStr
Get the columns for dynamic pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + [STATUS] + ']','[' + [STATUS] + ']')
FROM (SELECT DISTINCT ORG,[STATUS] FROM #NEWTABLE) PV
ORDER BY ORG
Now pivot the query
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT * FROM
(
SELECT UserEnrollNumber,TimeDate, TimeStr,[STATUS]
FROM #NEWTABLE
) x
PIVOT
(
MIN(TimeStr)
FOR [STATUS] IN (' + #cols + ')
) p
ORDER BY UserEnrollNumber,TimeDate'
EXEC SP_EXECUTESQL #query
Click here to see the working result
I'm excute this query and recieve this error :
(16561 row(s) affected)
Msg 325, Level 15, State 1, Line 6
Incorrect syntax near 'PIVOT'. You may need to set the compatibility level of the current database to a higher value to enable this feature. See help for the SET COMPATIBILITY_LEVEL option of ALTER DATABASE.

android sqlite select avg multiple columns

I have a problem with a query of sqlite. I want to do is the average of two columns and place the result in a new column. example:
id | max_ma | max_ta | avg_max (new column)
1 | 100 | 102 | 101 ==> (100+102)/2
2 | 100 | null | 100 ==> (100+0)/1 INGNORE NULL
wrong code:
public Cursor list() {
String lista_ge = "SELECT *, AVG(tr_max_m + tr_max_t) AS media_max FROM bdt_registro ORDER BY tr_fecha DESC, _id DESC";
return db.rawQuery(lista_ge, null);
}
or
public Cursor list() {
String lista_ge = "SELECT *, ((tr_max_m + tr_max_t)/COUNT(*)) AS media_max FROM bdt_registro ORDER BY tr_fecha DESC, _id DESC";
return db.rawQuery(lista_ge, null);
}
Thanks for your interest
Use the COALESCE function:
SELECT *,
(COALESCE(tr_max_m, tr_max_t, 0) + COALESCE(tr_max_t, tr_max_m, 0)) / 2 AS media_max
FROM
bdt_registro ORDER BY tr_fecha DESC, _id DESC
If both are non_NULL you get: (tr_max_t + tr_max_m) / 2
If tr_max_m is NULL you get: (tr_max_t + tr_max_t) / 2 = tr_max_t
If tr_max_t is NULL you get: (tr_max_m + tr_max_m) / 2 = tr_max_m
If both are NULL you get: (0 + 0) / 2 = 0
Probably the best approach will be to use a lot of cases:
SELECT max_ma, max_ta,
CASE WHEN max_ma IS NULL THEN
CASE WHEN max_ta IS NULL THEN 0
ELSE max_ta END
ELSE
CASE WHEN max_ta IS NULL THEN max_ma
ELSE (max_ma + max_ta) / 2 END
END avg_max
FROM user_address
Fiddle here.
By the way, I noticed you were trying to use AVG. If you're wondering how you could have used that function then this will give you an idea. It won't be faster than the previous approach because it adds more calculation, though:
SELECT id,
max(CASE WHEN kind = 1 THEN aMax END) max_ma,
max(CASE WHEN kind = 2 THEN aMax END) max_ta,
avg(aMax) aMax
FROM (
SELECT id, max_ma aMax, 1 kind FROM user_address
UNION ALL
SELECT id, max_ta, 2 FROM user_address
) s
GROUP BY id
Another solution based on function IFNULL and...
... "un-aggregated" aggregated function COUNT:
SELECT *,
(IFNULL(max_ma, 0)+IFNULL(max_ta, 0))/(COUNT(max_ma)+COUNT(max_ta)) AS avg_max
FROM bdt_registro
GROUP BY id;
... CASE:
SELECT *,
(IFNULL(max_ma, 0)+IFNULL(max_ta, 0)) / (CASE WHEN max_ma IS NULL THEN 0 ELSE 1 END + CASE WHEN max_ta IS NULL THEN 0 ELSE 1 END) AS avg_max
FROM bdt_registro;
ยป SQL Fiddle

Categories

Resources