How to format Query using ROOM - android

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

Related

Search period, given current week and year

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;

Fetch data from 3 Tables

I have 3 Tables
1 Customers
-c_id
-c_name
2 Debit_Master
-transaction_id
-c_id
-amount
3 Credit_Master
-transaction_id
-c_id
-amount
Now i want data like this : Customer Name and Total amount(credit amount - debit amount) of each customer .
I want query to fetch data in my listview with two columns 1- Customer Name , 2- Total amount
Try this SQL statement:
SELECT
Customers.c_name as CustomerName,
SUM((CASE
WHEN Credit_Master.amount IS NULL THEN 0
ELSE Credit_Master.amount END -
CASE
WHEN Debit_Master.amount IS NULL THEN 0
ELSE Debit_Master.amount END)) as TotalAmount
FROM Customers
LEFT JOIN Debit_Master on Customers.c_id = Debit_Master.c_id
LEFT JOIN Credit_Master on Customers.c_id = Credit_Master.c_id
GROUP BY Customers.c_id
Try something like this
SELECT Customers.c_name as name , (Credit_Master.amount - Debit_Master.amount) as total FROM Customers JOIN Debit_Master on Customers.c_id=Debit_Master.c_id JOIN Credit_Master on Customers.c_id=Credit_Master.c_id

Group by in sub query

Here's the table in question,
What I am trying to do is to get the count of entries segregated by type for each person(claimed_by). For example, for example,
John : Total entries :4 , Type 1 entries: 1, Type 2 entries : 3.
Jane : Total entries :4 , Type 1 entries: 4, Type 2 entries : 0.
Here's what I have at the moment,
SELECT count(id) as total_entry,claimed_by,
(select count(id) from tblIssues where type=1) as type1_entry,
(select count(id) from tblIssues where type=2) as type2_entry
FROM tblIssues
GROUP BY claimed_by
order by count(id) desc
This return correct value for total_entry but incorrect for type1 and type2. I think this is because I am not doing a group_by in the sub query but I am not sure how to correctly do that.
You can put a condition in the sum(). It adds up how many times it is true (1).
SELECT claimed_by,
count(id) as total_entry,
sum(type = 1) as type1_entry,
sum(type = 2) as type2_entry,
sum(type = 3) as type3_entry
FROM tblIssues
GROUP BY claimed_by
order by count(id) desc

AND and OR function in one query, not working? sqlite

i run a query with a WHERE
"COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0 AND COMPUTERCLASSROOM_DONE = 1"
though it return all the row that met a requirement..this is the table rows data
According to column presentation, here are the values of the rows
ROW 1 = 0 0 0
ROW 2 = 1 0 0
ROW 3 = 1 2 1
ROW 4 = 1 3 0
ROW 5 = 1 4 1
ROW 6 = 0 5 1
ROW 7 = 0 0 1
they all return..why is that? if i changed the OR with an AND, it would follow the query, returning ROW 7... its just weird..i need that OR and AND in one query, because my target is to return a row with at least 0 in either SLot1 or Slot2, and DONE = 1
it should be
WHERE (COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0) AND
COMPUTERCLASSROOM_DONE = 1
As #Jack already pointed out, the problem is because you are not using the parentheses. And hence your query is evaluated logically different from what you are expecting.
Try #JW.'s snippet and it would work perfectly.
WHERE (COMPUTERCLASSROOM_SLOT1 = 0 OR COMPUTERCLASSROOM_SLOT2 = 0) AND (COMPUTERCLASSROOM_DONE = 1)
Underlying cause
AND is evaluated as a multiplication; OR is evaluated as an addition. So according to arithmetic precedence rule (PEMDAS), AND is evaluated before evaluating OR.
Example: 1 OR 0 is 1 + 0 = 1; 1 AND 0 is 1 * 0 = 0;
So
X or X or X and X is grouped automatically as X or X or (X and X).
Use of parenthesis avoids the confusion, as well as makes code more readable.

Calculation of refuelings (full and partly)

In one of my apps I need to calculate fuel consumption that takes into account complete refuelings and partly refuelings. My Android App is based on SQLite syntax and features.
I try to solve that puzzle in SQL and don't want to walk thru all rows to do this stuff programmatically.
Rows with FULL='N' should be left out in the result list but their values should be added to the next FULL='Y' row. At least that is my idea.
This is the DML (only required columns shown):
CREATE TABLE FUELINGS (
ID INTEGER PRIMARY KEY,
MILEAGE INTEGER,
VOLUME DECIMAL(8, 2),
FULL CHAR(1));
Here's some input to this table:
INSERT INTO FUELINGS VALUES(1,22995,29.48,'Y');
INSERT INTO FUELINGS VALUES(2,23385,31.27,'Y');
INSERT INTO FUELINGS VALUES(3,23869,16.71,'N');
INSERT INTO FUELINGS VALUES(4,24065,33.18,'Y');
INSERT INTO FUELINGS VALUES(5,24485,30.59,'Y');
INSERT INTO FUELINGS VALUES(6,24956,33.78,'Y');
Ok, here comes the problem. This is the query I use:
SELECT T2.MILEAGE,
T2.VOLUME,
T2.FULL,
T2.PREVMILEAGE,
T2.PREVVOLUME,
T2.PREVFULL,
100 * T2.VOLUME / ( T2.MILEAGE - T2.PREVMILEAGE )
FROM (SELECT T.MILEAGE,
T.VOLUME,
T.FULL,
T.PREVMILEAGE,
(SELECT VOLUME
FROM FUELINGS
WHERE MILEAGE = T.PREVMILEAGE
AND MILEAGE IS NOT NULL
AND MILEAGE > 0
AND VOLUME IS NOT NULL
AND VOLUME > 0) AS PREVVOLUME,
(SELECT FULL
FROM FUELINGS
WHERE MILEAGE = T.PREVMILEAGE
AND MILEAGE IS NOT NULL
AND MILEAGE > 0
AND VOLUME IS NOT NULL
AND VOLUME > 0) AS PREVFULL
FROM (SELECT F.MILEAGE,
F.VOLUME,
F.FULL,
(SELECT Max(MILEAGE)
FROM FUELINGS PREV
WHERE PREV.MILEAGE < F.MILEAGE
AND MILEAGE IS NOT NULL
AND MILEAGE > 0
AND VOLUME IS NOT NULL
AND VOLUME > 0) AS PREVMILEAGE
FROM FUELINGS F
WHERE MILEAGE IS NOT NULL
AND MILEAGE > 0
AND VOLUME IS NOT NULL
AND VOLUME > 0) AS T
WHERE PREVMILEAGE IS NOT NULL) AS T2
ORDER BY T2.MILEAGE;
This is the result:
T2.MILEAGE T2.VOLUME T2.FULL T2.PREVMILEAGE T2.PREVVOLUME T2.PREVFULL 100 * T2.VOLUME / (T2.MILEAGE - T2.PREVMILEAGE)
23385 31.27 Y 22995 29.48 Y 8.017948717948718
23869 16.71 N 23385 31.27 Y 3.4524793388429753
24065 33.18 Y 23869 16.71 N 16.928571428571427
24485 30.59 Y 24065 33.18 Y 7.283333333333333
24956 33.78 Y 24485 30.59 Y 7.171974522292993
16.92 is wrong because the refueling before that one was a partly refueling. I need to sum and calculate both rows. I am aware that there might be more than 1 partly refueling. But I don't have any clue how to build ranges of FULL='N' values, sum them up and add them to the following FULL='Y' value.
Can please somebody put me in the right direction. How can I make that right?
Many thanks in advance.
EDIT/SOLUTION:
SELECT T.MILEAGE,
T.PREVMILEAGE,
SUM(VOLUME),
100 * SUM(VOLUME) / ( T.MILEAGE - T.PREVMILEAGE )
FROM (SELECT F1.MILEAGE AS MILEAGE,
MAX(F2.MILEAGE) AS PREVMILEAGE
FROM FUELINGS F1
LEFT OUTER JOIN FUELINGS F2
ON F1.MILEAGE > F2.MILEAGE
AND F2.FULL = 'Y'
AND F2.MILEAGE IS NOT NULL
AND F2.MILEAGE > 0
AND F2.VOLUME IS NOT NULL
AND F2.VOLUME > 0.0
WHERE F1.FULL = 'Y'
AND F1.MILEAGE IS NOT NULL
AND F1.MILEAGE > 0
AND F1.VOLUME IS NOT NULL
AND F1.VOLUME > 0.0
GROUP BY F1.MILEAGE) AS T,
(SELECT VOLUME
FROM FUELINGS F3
WHERE F3.MILEAGE > T.PREVMILEAGE
AND F3.MILEAGE <= T.MILEAGE)
GROUP BY T.MILEAGE
Your original query would work if you had a table called FuelingsFull, which only contained complete information about full fuelings. This can be summarized from Fueling. The process would be simpler with window functions, but you don't have those in SQLite.
So, here is an idea on how to do this. First, get the previous full id:
select f1.id, max(f2.full) as prevFullId
from fuelings f1 left outer join
fuelings f2
on f1.id > f2.id and
f2.full = 0
group by f1.id
Now, you have a group of fuelings that all belong together. The next query joins this back to the fuelings and then groups these together.
select fills.id, max(mileage) as mileage, sum(volume) as volume, count(*) as numFills
from fuelings f join
(select f1.id, max(f2.full) as prevFullId
from fuelings f1 left outer join
fuelings f2
on f1.id > f2.id and
f2.full = 1
group by f1.id
) fills
on f.id > fills.prevFullId and f.id <= fills.id
group by fills.id
With this as your FuelingFull, you original query should work.

Categories

Resources