SQLITE query monthly GROUP BY with SUM - android

I have been stuck with this problem for a while (Android SQLITE). I have 2 columns - Date and Amount. Date is stored in YYYYMMDD format.
DATE AMOUNT
20120521-------50
20120506-------40
20120311-------30
20120202-------20
20120125-------10
What I need is a SQL query (Android SQLITE), which will output two columns - Month and cumulative total till that month..If a month does not have any transaction, it still should evaluate the cummulative total.
So the output I need here (notice there are no transactions for April)
Month Cumulative-Total
MAY-------150
APR-------60
MAR-------60
FEB-------30
JAN-------10

It should work:
SELECT strftime('%m', date), SUM(Amount)
FROM myTable
GROUP BY strftime('%m', date)
Sorry i forgot this part of your question "..If a month does not have any transaction, it still should evaluate the cummulative total."
Solution: The simple solution is to have a DUMMY entry in the table for all months.

Difficult since the easy way to do this is to write a stored procedure to do it but which isnt supported in sqlite. However take a look at this - maybe this way might be useful
Android - easy/efficient way to maintain a "cumulative sum" for a SQLite column
Also you can try doing the cumulative addition on the android end

you can not just comulate like this. You can do this 2 ways:
Group by month and then sum it up on the Android end and add the Months that missing.
Try make that with a store procedure. (this I am not entierly sure possable on sql lite for your case.) Read this
So I would go with the first option.

Related

Natural sorting of alphanumeric values in sqlite using android

I have a list of names of starts with characters and end with numbers like: -
ka1, ka10, ka 2, ka, sa2, sa1, sa10, p1a10, 1kb, p1a2, p1a11, p1a.
I want to sort it in natural order, that is: -
1kb, ka, ka1, ka 2, ka10, p1a, p1a2, p1a10, p1a11, sa1, sa2, sa10.
The main problem I am seeing here is no delimiter between text and numeric part, there also a chance of without numeric part also.
I am using sqlite in android, I can do sorting using java after fetching points by cacheing cursor data, but I am using(recommended to use) cursor adapter.
Please suggest a query for sorting or is there any way to apply sorting in cursor?
I tried below query for Natural sorting:
SELECT
item_no
FROM
items
ORDER BY
LENGTH(item_no), item_no;
It worked for me in Sqlite db too. Please see this link, for more details.
I can propose using regex replacement adding zeros, creating temporary table of original and corresponding values, then follow this link for sorting it: http://www.saltycrane.com/blog/2007/12/how-to-sort-table-by-columns-in-python/
tip for regex add as many zeros after last letter, but limit the number of total digits for predicted maximum number of digits. If You need help with regex as well, provide exact info of valid and invalid values, so can halp with that too.
PS if want to be sure that zeros goes before last digits search for char from the end
Updated
You can use different ways - Some of are mentioned below:
BIN Way
SELECT
tbl_column,
BIN(tbl_column) AS binray_not_needed_column
FROM db_table
ORDER BY binray_not_needed_column ASC , tbl_column ASC
Cast Way
SELECT
tbl_column,
CAST(tbl_column as SIGNED) AS casted_column
FROM db_table
ORDER BY casted_column ASC , tbl_column ASC
or try the solution:
There are a whole lot of solutions out there if you hit up Google, and
you can, of course, just use the natsort() function in PHP, but it's
simple enough to accomplish natural sorting in MySQL: sort by length
first, then the column value.
Query: SELECT alphanumeric, integer FROM sorting_test ORDER BY LENGTH(alphanumeric), alphanumeric from here

To fetch records from sqlite table between a range of dates

In my application i am trying to fetch records from a sqlite table with respect to a range of dates selected from the date picker. The records in the table are as follows :
The query formed is as given below :
select * from Order_Master where Order_Date >= '12-04-2015' and Order_Date <= '11-03-2016' And WSS_Code = '1014332'
This query does not return any value which is not the desired result as the dates are in the selected range.
What could possibly be wrong here ? Am i missing something?
Kindly guide me through this. Thanking you in Advance !
Your date format cannot be used for comparisons, because strings are compared lexicographically, i.e., with the first characters compared first.
In this query, you are searching for dates with a month that is at least 12 and, at the same, no larger than 11.
SQLite has no separate data type for dates.
To store dates in a database, you have to choose one of the existing data types (number or text).
When using SQLite's built-in date functions, you must use one of the formats supported by them.
Try this , hope it helps
Change your datatype to text
SELECT * FROM Order_Master WHERE Order_Date BETWEEN '12-04-2015' AND '11-03-2016' AND WSS_Code = '1014332';
As well as your query will also work.

Trouble sorting query by date range followed by other criteria. Union? Concatenate? Looking for ideas

In my Android SQLite database, I have a column that is a datetime in the format YYYY-MM-DD HH:MM. I want a query (or a cursor, actually) that will give me all of the rows in, let's say May 2015. The sorting is where I'm getting stuck. I want my results broken down first by week, then for each week a sort based on other columns.
Right now I'm just sorting by the datetime column, followed by the other columns. Eg: ORDER BY t.TASKS_DATETIME ASC, s.STATUSES_RANK ASC, t.TASKS_CATEGORY. But basically every row has a unique value for datetime (even though I don't care about hours and minutes in this case) so no other sorting happens and the end result is not very user friendly. The sort order is really important for the user to look at and understand this data.
I thought about doing a separate select statement for each of the weeks, then doing a UNION ALL to get the month data. But you can't use the ORDER BY clause with a UNION, because it sorts the whole union, not just the individual select statements inside. Not to mention, it's pretty ugly.
I thought maybe I could do it on the Android/Java side and concatenate multiple Cursor objects. But I can't find any way to do that. Does anyone here know a way? I've been away from Java for a few years and was never that intimate with the language to start.
I thought maybe I could use the SQLite date functions [https://www.sqlite.org/lang_datefunc.html ] in some way. Maybe add a new column in my select that has the week of year. Then I could sort by that new column, followed by the other sort criteria that I want. Or maybe there is a way to put a range (or simplified datetime) into the ORDER BY clause. But this is pushing the boundaries of my SQLite skills. Does this seem possible? FYI, on the Android/Java side, I convert this datetime String to a GregorianCalendar.
I'm hoping someone smarter than me on here can point me in a good direction! None of these options seems great and I can't think of any others.
If I can't figure out anything else, I'll go with the UNION option. And add a "week_of_year" column to each select statement inside to identify that week, as suggested by other union/sorting questions here. Then sort by that "week_of_year" column, followed by my other sort criteria. I've started working on this. But I took a break to ask for better ideas here, cause my gut says there has to be a better way. But maybe not :)
As additional background, that I don't think is relevant, but just in case...
This scary query is being used in a StickyHeaderList [https://github.com/emilsjolander/StickyListHeaders ], where the weeks are the headers. If I don't sort first by datetime, the headers/weeks end up out of order. Sometimes they even duplicate.
I will probably at some point write my own alternative or alter this StickyHeaderList code, perhaps something that takes a cursor for each week/header rather than just one for the whole month. I can deal with dates easier in Java then SQL. But I don't have the resources for that today. The biggest headache, I imagine, will be having the multiple-select CAB menu allow me to select across different lists. If you happen to know an easy work around for that, maybe I will just do that and accept the major rework over figuring out this query.
UPDATE: It works!
Many thanks to #CL for giving me the answer. For posterity and clarity, here are some notes.
The correct answer is:
SELECT ...
FROM ...
ORDER BY strftime('%Y%W', t.TASKS_DATETIME),
s.STATUSES_RANK,
t.TASKS_CATEGORY
As noted, weeks are finicky things. I need to also account for users who have weeks that start on different days of the week. Note, the SQLite default is to start the ween on Monday (not Sunday). Also, the keyword is day not days for accounting for that offset. Also, the offset should be made to the right of the datetime.
This left me with:
"ORDER BY strftime('%Y %W', t." + TASKS_SCHED_DATETIME + weekOffset + ")," +
"s." + STATUSES_RANK + " ASC, " +
"t." + TASKS_CATEGORY + " DESC "
Which in the end becomes: ORDER BY strftime('%Y %W', t.task_sched_datetime, '+5 day' ), s.status_rank ASC, t.tasks_category DESC
weekOffset is defined in a little helper function:
private String calculateWeekOfset() {
int wkStart = App.getWeekStart();
int offset = 9 - wkStart; // Calendar.MONDAY == 2
return ", '+" + Integer.toString(offset)+ " day' ";
}
I think that's all. Thanks again!
To extract fields from a timestamp, use the strftime function.
In this case, you need the week of the year, and the year itself to make dates in different years unique:
SELECT ...
FROM ...
ORDER BY strftime('%Y%W', t.TASKS_DATETIME),
s.STATUSES_RANK,
t.TASKS_CATEGORY
If you do not want to start a week on a Monday, add or subtract the appropriate number of days:
... strftime('%Y%W', t.TASKS_DATETIME, '+1 days'), ...

SQLite use year with date functions in where clause and group by

I am keeping date time values(Unix timestamps) in a "NUMERIC" format in SQLite table, the value is calculated through Java Date function:
new Date().getTime();
The values look like proper date/time when I load these in an Android program, but when I try to experiment with queries through SQLite data browser 2 beta the results are awkward. Numeric values are given below:
1391313058888
1391313104336
1391313175752
When I try to apply date function the SQLite data browser shows following for all three rows:
-1413-03-01 13:07:12
My query is
SELECT date(trxDateTime, 'unixepoch') from trx_log
I was trying to figure out how to get correct date values in the first place, once I got those then I believe I could figure a way to use it in where clause or group by.
Basically I am trying to show totals sales by year. Any help will be appreciated.
Your times are in milliseconds. Just convert them to seconds, and you'll be fine:
SELECT date(trxDateTime / 1000, 'unixepoch') from trx_log

How do you count the number of consecutive dates in a table?

In my Android App I need to keep track of the longest streak, and current streak, of consecutive dates that are saved in a database table. I don't even know where to start to get this to work. The best I can come up with is to query every row in the table and iterate through all of them programmatically to find where there's a gap. Not very efficient. Anyone have any better ideas?
Here is an SQL only solution that I thought was really cool. Assuming the dates in your table are unique (not that it would be too hard to just group on them) you can use the method adapted from here http://www.sqlteam.com/article/detecting-runs-or-streaks-in-your-data. I ran through the example and there are some syntax errors, so hopefully I didn't repeat them in my answer below. I probably used some reserved keywords, so you may need to adapt that.
First create a table of Dates that is significantly large to cover your needs. I'm not sure what the best method for SQLite is, but in SQL Server you can insert integers into a Datetime field and it will do an implicit conversion of integers to dates. There are many methods to insert integers into tables...
Anyway, once the Dates table is created, do a left join from your Dates table to your Streak table using your min and max dates from your streak table as your range limiter. You will then have the following code.
Let’s call it SQL 0
SELECT Dates.Date,
CASE
WHEN StreakTable.DATE IS NULL THEN 0
ELSE 1
END AS Result
FROM Dates
LEFT JOIN StreakTable
ON Dates.DATE = StreakTable.DATE
WHERE Dates.DATE BETWEEN (SELECT MIN(DATE) AS MinDate
FROM StreakTable) AND (SELECT MAX(DATE) AS MaxDate
FROM StreakTable)
Let’s call the following SQL 1
SELECT Date,
Result,
(SELECT COUNT(*)
FROM (SQL 0) S
WHERE S.Result <> SV.Result
AND S.GameDate <= SV.GameDate) AS RunGroup
FROM (SQL 0) SV
Let’s call the following SQL 2
SELECT Result,
MIN(Date) AS StartDate,
MAX(Date) AS EndDate,
COUNT(*) AS Days
FROM (SQL 1) A
GROUP BY Result,
RunGroup
ORDER BY MIN(Date)
At this point you can do some pretty cool stuff like answer:
What was the longest streak?
SELECT TOP 1 *
FROM (SQL 2) A
WHERE Result = 1
ORDER BY Games DESC
What is the current streak as of the most recent date?
SELECT *
FROM (SQL2) A
WHERE EndDate = (SELECT Max(Date)
FROM Streak)
How many streaks of 3 or more did we have?
SELECT Result,
COUNT(*) as NumberOfStreaks
FROM (SQL 2) A
GROUP BY Result
WHERE Days >= 3
Basically you have a month and days in a month
so you just compare the days count to the needed number.
If there's a gap you can easily find it out by substracting the count from days in a month. E.g. you have count(days_visited) where month=1
and it returns you 20 days but January has 31 so there's a gap in 11 days and here're the date functions of sqlite
http://www.sqlite.org/lang_datefunc.html
You can use following functions
like SELECT date('now','start of year','+9 months','weekday 2');
EDIT
sorry everyone solution is ugly. it is I know.
create table visits(day_visited timestamp,visited int);
You create a record everyday in this table indicating
whether a user was online or offline with
'now',1 or 0 (online/offline). Then you run through there records.
Your records for month will be an int array with 1s and 0s.
called vistedrecordsformonth
pseudo code:
int online=0;
int offline=0;
for(int i=0;i<vistedrecordsformonth.size();i++){
boolean flag=false;
if(vistedrecordsformonth[i]==1){ //visited
if(!flag&&i!=0) //check for flag and not 0 index to insert a record
{
streaksMap.put(online,offline); //or insert a record into another streakmap or table
online=0;
offline=0;
}
flag=true;
online++;
}
else{
flag=false;
offline++;
}
} //end of for
The map or table will contain a pair of online=offline days for a month.
with usual order by you can see what was the biggest streak in online or offline days.
It is ugly I know I'm sure there should be something more elegant but as
quick and dirty it should work.
hope it helps abit.

Categories

Resources