I have a sqlite table, which has the following columns:
id | description | startYear | startWeek | endYear | endWeek
startYear, startWeek, endYear and endWeek are all integer
So given current week and year (for example week 4, year 2017), how do I search for rows that have startYear, startWeek and endYear, endWeek that include the given week and year?
I'm currently trying to doing this manually by UNION-ing several select query, but I think it's inefficient, and not too mention too much codes (relatively, if there's some sort of built-in query to do this).
My query currently look something like this:
Select id, description
from myTable
where (:currentYear = startYear AND
(:currentWeek >= startWeek OR
:currentWeek <= endWeek ))
UNION
Select id, description
from myTable
where (:currentYear > startYear AND
:currentWeek <= endWeek )
UNION
Select id, description
from myTable
where (:currentYear < endYear AND
:currentWeek <= 53 )
UNION
Select id, description
from myTable
where (:currentYear < endYear AND
:currentWeek <= 53 )
UNION
Select id, description
from myTable
where (:currentYear < endYear AND
:currentWeek <= 53 )
UNION
Select id, description
from myTable
where (:currentYear = endYear AND
:currentWeek <= endWeek);
When you have a query of the form:
SELECT ... WHERE A
UNION
SELECT ... WHERE B
you can trivially transform it into a single query of the form:
SELECT ... WHERE A OR B
The WHERE condition might then be further simplified by using the rules of the Boolean algebra.
But your current query is wrong, so it's better to construct a new one from scratch.
What you want is the equivalent of this:
SELECT ... WHERE currentTime BETWEEN startTime AND endTime;
Now, instead of splitting the time comparisons into the two fields, it would be easier to construct a single time value. Just multiplying the year by 100 and summing it with the week gives a value like 201704, which compares correctly with any other such values:
SELECT ...
WHERE :currentYear * 100 + :currentWeek
BETWEEN startYear * 100 + startWeek
AND endYear * 100 + endWeek;
Related
So I have a table with 4 columns and would like to sum the values of the amount column where isExpense is true and where isExpense is false. I would like to subtract those 2 values and return that sum.
I don't have much experience with SQL other than single line queries so I'm struggling to format this.
#Query("""
SELECT SUM (amount) AS INCOME FROM `transaction` WHERE isExpense = 0,
SELECT SUM (amount) AS EXPENSE FROM `transaction` WHERE isExpense = 1,
SUM (INCOME - EXPENSE) AS BALANCE
""")
fun getTotalBalance(): Flow<Double>?
I could get around this by creating more columns in my table if all else fails.
Use case expressions to do conditional aggregation:
SELECT SUM(case when isExpense = 0 then amount else 0 end) AS INCOME,
SUM(case when isExpense = 1 then amount else 0 end) AS EXPENSE,
SUM(case when isExpense = 0 then amount
when isExpense = 1 then -amount
end) as BALANCE
FROM `transaction`
WHERE isExpense IN (0, 1) -- Not needed, but might speed things up if there
-- are other values than 0 and 1
The following SQLite query works fine on android 4.4 and below, but it causes an exception: "android.database.sqlite.SQLiteException: ambiguous column name: number (code 1):......" on android 5.0 and later. I checked the SQLite release documents, but did not see any changes that can effect my work. Is there any thing that I missing?
select * from
(
select
'0' as queryid,
CNCT._id,
coalesce(case when length(C.abId)=0 then null else C.abId end,
(
select
addrBkId from numbers as nm,
contacts as cot
where nm.number=coalesce(C.number,S.Number) and nm.contactID = cot._id
order by cot.lastMod desc limit 1)) as addrBkId,
coalesce(
case when length(C.abId)=0 then null else C.abId end,
(
select
addrBkId from numbers as nm,
contacts as cot
where nm.number=coalesce(C.number,S.Number) and nm.contactID = cot._id
order by cot.lastMod desc
limit 1
)
) as uqAddrBkId,
CNCT.displayName,
CNCT.firstName,
CNCT.lastName,
CNCT.favorite,
coalesce(C.location,
(
select
location from calls as css
where css.number = S.Number
)) as location,
0 as numberType,
coalesce(C.number,S.Number) number,
N.txt,A.type,
coalesce(A.callID,A.smsId) actId,
max(A.startEpoch) as maa,
max(A.startTime),
strftime('%w',datetime(A.startEpoch,'unixepoch','localtime'))+0 dayOfWeek,
strftime('%W',datetime(A.startEpoch,'unixepoch','localtime'))+0 weekOfYear,C.duration,
case
when C.callResult='vmail' then 'vmail'||C._id
when C.callType='callin' and C.callResult='missed' then 'missed'
else C.callType end as newCallType,
C.callResult,
C.extension,
C.msgId,
C.audioUrl,
C.name,
C.state,
C.syncParams,
S.smsId,
S.dir,
S.state,
N.noteId,
N.color from activity as A
left outer join calls C on A.callId=C.callId
left outer join sms S on A.smsId=S.smsId
left outer join contacts CNCT on coalesce(case when length(C.abId)=0 then null else C.abId end,
(
select addrBkId from numbers as nm,
contacts as cot
where nm.number=coalesce(C.number,S.Number) and nm.contactID = cot._id
order by cot.updated desc
limit 1)
)=CNCT.addrBkId
left outer join
(
select * from notes as nt
order by nt.lastMod asc
) as N on CNCT.addrBkId=N.addrBkId
where (C.state<>5 or C.state is NULL) and (C.callResult<>'abandoned' or C.callResult is NULL)
group by newCallType,number,weekOfYear,dayOfWeek
order by max(A.startEpoch) asc
)
group by _id
order by maa desc
limit 3
... where nm.number=coalesce(C.number,S.Number) ...
... where nm.number=coalesce(C.number,S.Number) ...
... where css.number = S.Number) ...
... coalesce(C.number,S.Number) ...
... where nm.number=coalesce(C.number,S.Number) ...
... group by newCallType,number,...
^^^^^^
All occurences of number are qualified with a table alias, except the last one. That one indeed is ambiguous.
How do I make a comparison between dates using SQlite, I tried this more failed. help: D
My Query:
SELECT
latitude,
longitude,
grupo_crime_id_grupo_crime,
descricao,
id_crime,
cities_id_cities,
time,
estado
FROM crime WHERE
cities_id_cities='0' AND
time >= datetime('2013-03-28T09:30:37-03:00')
time <= datetime('2013-0328T09:30:37-03:00') AND
grupo_crime_id_grupo_crime='1'
use like this:
select * from MyTable
where mydate >= Datetime('2000-01-01 00:00:00')
and mydate <= Datetime('2050-01-01 23:00:59')
In a database I have saved the date in form of 3 columns: Year, Month, Day_of_Month
( I know it might not be a best way to save the date but I make certain other queries for which this format felt suitable.)
Now I wish to get all the rows where the date is in between two specified dates. I went through previous stackoverflow questions, but most of them have saved the date as a single entity.
This is how I tried:
I have a MySqLiteHelper class with all the column names declared. I also create the table there. COLUMN_DATE_YEAR, COLUMN_DATE_MONTH and COLUMN_DATE_DAY are the string storing the column names.
int fyear, fmonth, fday; // I populate those initial date values
int tyear, tmonth, tday; // I populate those target date values
String selection = MySQLiteHelper.COLUMN_DATE_YEAR + " >= '"+fyear+"' AND "+ MySQLiteHelper.COLUMN_DATE_DAY + " >= '"+fday+"' AND "
+ MySQLiteHelper.COLUMN_DATE_MONTH + " >= '"+fmonth+"' AND " + MySQLiteHelper.COLUMN_DATE_YEAR + " <= '"+tyear+"' AND "
+ MySQLiteHelper.COLUMN_DATE_DAY + " <= '"+ tday+"' AND "+ MySQLiteHelper.COLUMN_DATE_MONTH + " <= '"+tmonth+"'";
String []column = {MySQLiteHelper.COLUMN_MOOD_LEVEL};
Cursor cursor = database.query(MySQLiteHelper.TABLE_NAMES, column, selection, null, null, null, null);
Now the problem with this approach is that it will give no results for the query between 25 Feb 2013 and 17 March 2013 as the date 25th > 17th, even though the month 2 < 3. This might require some kind of nested where clause. However I am unable to form a nested 'Where' using '.query' method.
Please suggest a way to query for the entries stored in between these two dates. Thanks in advance.
There's no reason why you shouldn't be able to run a somewhat more complex WHERE clause, as follows (for date >= 2013-02-17):
( YEAR > 2013 OR ( YEAR = 2013 AND ( MONTH > 2 OR ( MONTH = 2 AND DAY >= 17 ) ) ) )
This will work, but it's for from optimal. You'd be better off correcting your database design.
Correction: You must fix your database design. Either store the date as DATE type or as ISO string: yyyy-mm-dd.
Bonus: Say you have the following right now:
CREATE TABLE theTable(
....
THEYEAR TEXT,
THEMONTH TEXT,
THEDAY TEXT );
To convert the date to a usable format, you can simply run the following:
ALTER TABLE theTable
ADD COLUMN THEDATE TEXT;
UPDATE theTable
SET THEDATE = THEYEAR || substr( '0' || '-' || THEMONTH, -2, 2 ) || '-' || substr( '0' || THEDAY, -2, 2 );
Once you've done that, you can then query using the BETWEEN clause.
Using your current schema, try reordering your WHERE clause. You need to compare the largest columns first, i.e. year, month, day. With your current year, day, month you cannot accurately compare dates that cross over into new months.
For example: day >= 25 and day <= 17 creates an invalid range. It doesn't account for the correct range: >25, wrap to 1, then <17...
Without changing the table structure the below query will work for you, try it
select * from TableName WHERE (10000*ColumnYear+100*ColumnMonth+ColumnDay >= 20131009) and (10000*ColumnYear+100*ColumnMonth+ColumnDay <= 20131121);
I need that every time I make a change to a certain record from a table in SQLite, in the column lastChangedDate to set the time from France. Here is the structure of my table :
CREATE TABLE name(
id VARCHAR(36) PRIMARY KEY
, pos_report_id VARCHAR(36)
, path_name VARCHAR(64)
, photo_name VARCHAR(64)
, from_scratch INTEGER DEFAULT 0
, lastChangedDate DATETIME DEFAULT (DATETIME('now', 'utc', '1 hours'))
)
I see that DATETIME('now') returns 2 hours before my real time and DATETIME('now', 'utc', '1 hours') returns with 3 hours before my time. Why is happening this? I need the application to work in more countries, so I cannot use localtime.
Any idea how to solve this?
I have the same problem (using sqlite on Raspbarry Pi). 'utc' obviously only calcultes the difference according to location and timezone. I got it running like this:
select datetime(datetime('now', 'localtime'), 'utc');
Also check out the other variation of my VIEW [NOW] for sensor logging purpose.
CREATE VIEW [NOW] AS
SELECT datetime('now', 'localtime') as LOCAL,
datetime(datetime('now', 'localtime'),'utc') as UTC,
substr(datetime('now', 'localtime'),1,17)||'00' as TimeSlot_1min,
substr(datetime('now', 'localtime'),1,15)||'0:00' as TimeSlot_10min,
substr(datetime('now', 'localtime'),1,14)||'00:00' as TimeSlot_1h;
try datetime('now','localtime') instead of DATETIME('now', 'utc', '1 hours')
Ok dont use default time for lastChangedDate
CREATE TABLE name(
id VARCHAR(36) PRIMARY KEY
, pos_report_id VARCHAR(36)
, path_name VARCHAR(64)
, photo_name VARCHAR(64)
, from_scratch INTEGER DEFAULT 0
, lastChangedDate DATETIME)
)
then when you want to add record to table, you can calculate the time in France and add this value to your database
//Calendar cal = Calendar.getInstance();
//Log.v("hata",String.valueOf(cal.get(Calendar.HOUR)));
Calendar c = Calendar.getInstance();
// It is local time
Log.v("time",String.valueOf(c.getTime()));
TimeZone z = c.getTimeZone();
int offset = z.getRawOffset();
if(z.inDaylightTime(new Date())){
offset = offset + z.getDSTSavings();
}
// france is GMT2
int offsetHrs = offset / 1000 / 60 / 60;
int offsetMins = offset / 1000 / 60 % 60;
// Offsets
Log.v("time",String.valueOf(offsetHrs));
Log.v("time",String.valueOf(offsetMins));
c.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
c.add(Calendar.MINUTE, (-offsetMins));
// FRANCE time
Log.v("time",String.valueOf(c.getTime()));