Group by in Sqlite? - android

I have 2 tables Products and Invoices. Each Products can be in some Invoices.
Product:
Id| Name
ـــــــــــــــ
1 | pencil
2 | pen
3 | ruler
Invoice:
Id| ProductID| Serial |Qty
ـــــــــــــــــــــــــــــ
1 | 1 |100 |5
2 | 1 |200 |6
3 | 2 |300 |8
4 | 3 |400 |18
When I write the following query
select * , SUM(Invoices.Qty)
FROM Products left outer join Invoices on Products.Id = Invoices.ProductID
Group by Products.Id
result:
Id| Name |Id|ProductID| Serial|SUM(Invoices.Qty)
ـــــــــــــــــــــــــــــــــــــــــــــــــــــ
1 |pencil |2 |1 |200 |11 -> (5+6)
2 |pen |3 |2 |300 |8
3 |ruler |4 |3 |400 |18
it returns a list of all products that is joined by the last Invoice. It calculates the Qty correctly but the problem is the selection of the last Invoice. How can I write a query that calculates Qty correctly and returns the Invoices with the id that I want.
in this example I want the invoice id 1 (serial 100) not 2 (serial 200)

Try this:
SELECT *,
(select sum(i3.qty) from Invoices i3 where i3.productId = i.productId)
FROM invoices I
JOIN products P
on I.productId = P.id
WHERE NOT EXISTS(
SELECT 'PREVIOUS'
FROM invoices I2
where I2.ProductId = I.productId
and I2.id < I.id
)
In this way you get the first invoice about a product. I don't understand if doesn't exist an invoice in you want to show the product. If yes, you must change the query with a left outer join

In SQLite 3.7.11 or later, you can use the MIN or MAX functions to force a specific from the group to be returned:
SELECT *, MIN(Invoices.Serial), SUM(Invoices.Qty)
FROM Products LEFT JOIN Invoices ON Products.Id = Invoices.ProductID
GROUP BY Products.Id

Related

Get Summation using in keyword in Sqlite Database Android

Need to get the total sum and count of the rows using join query while searching with tags ids.
Search can be done using multiple tag ids.I am trying to do it using 'in' keyword but it is returning wrong summation not able to understand how to get the summation while joining tables
Query 1:
SELECT SUM(amount) as Total,count(*) as count FROM
tbl_transactions
where trans_type='Expenses' and DATE(date) BETWEEN '2019-08-01' AND '2019-12-10'
AND trans_type='Expenses'
returns the right value as there is no joining
Query 2:
SELECT SUM(amount) as Total,count(*) as count FROM
tbl_transactions g
left join tbl_dummy2 d2
on d2.colA =g.trans_id
left join tbl_dummy d
on d.dummy_id1=d2.colB
where trans_type='Expenses' and d2.colB in (1,2) and DATE(date) BETWEEN '2019-08-01' AND '2019-12-10'
AND trans_type='Expenses'
returns the wrong value as joining is not properly done
I have three table:
tbl_transactions which holds all the transaction
tbl_dummy which holds all the tags (master table)
tbl_dummy2 which holds the colA(trans_id) and colB(tagids)
Move the condition d2.colB IN (1, 2) in the ON clause, because when you have it in the WHERE clause it will return only the matching rows of the LEFT JOIN which is actually an INNER JOIN:
SELECT SUM(t.amount) as Total, COUNT(*) as count
FROM tbl_transactions t
LEFT JOIN tbl_dummy2 d2 on d2.colA = t.trans_id
LEFT JOIN tbl_dummy d1 on d1.dummy_id1 = d2.colB AND d2.colB IN (1, 2)
WHERE t.trans_type='Expenses' AND DATE(t.date) BETWEEN '2019-08-01' AND '2019-12-10'
See the demo.
Results:
| Total | count |
| ----- | ----- |
| 8585 | 2 |

Get balance in sqlite3

I'd like to get the balance from a 'debit' table given an Id.
For instance:
User Debit
id | name user_from | user_to | value
1 | John 1 | 2 | 13.23
2 | Marie 1 | 2 | 20
3 | Peter 2 | 1 | 53
1 | 3 | 2.45
I'm John, so I'd like to check my balance to other people.
John's balance = +20.23 (to Marie's)
John's balance = -2.45 (to Peter's)
I'm using sqlite 3 for android !
I have created a SQLFIDDLE to see if it helps ! Link: SQLFiddle
Thank you very much for your time and help !
Use correlated subqueries to compute the subtotals for each user:
SELECT id,
name,
(SELECT TOTAL(value)
FROM Debit
WHERE user_from = User.id
AND user_to = 1) -
(SELECT TOTAL(value)
FROM Debit
WHERE user_to = User.id
AND user_from = 1) AS amount
FROM User
WHERE amount <> 0;
id name amount
---------- ---------- ----------
2 Marie 19.77
3 Peter -2.45
I'm thinking something like this for the money you owe people (not subtracting money that they owe you): SELECT SUM(value) FROM debit WHERE user_from = (SELECT id FROM User WHERE name=‘John’)
UPDATE: I haven't tested any of this but try this out and just do your subtraction after you have the 2 columns.
SELECT SUM(value) AS 'owes' FROM debit WHERE user_from = (SELECT id FROM User WHERE name=‘John’) GROUP BY user_from
UNION ALL
SELECT SUM(value) AS 'owed' FROM debit WHERE user_to = (SELECT id FROM User WHERE name=‘John’) GROUP BY user_to

get values based on foreign key

i have two tables:
Acounts:
ID Name
1 cash
2 bank
3 credit card
Transactions
ID accounts_id details income expenses
1 1 abc 1000 0
2 1 xyz 0 500
3 2 avc 200 0
what i want is to get the sum of income and expenses column for all the accounts in account table (even if there is not record in the transaction table for that account_id)
required output:
account_id total_income total_expenses
1 1000 500
2 200 0
3 0 0
what i am trying in sql:
select account_id,coalesce (sum(income),0) as total_income,coalesce(sum(expenses),0) as total_expenses from transactions where account_id in (select id as accounts_id from accounts) group by account_id
what the above query gives:
account_id total_income total_expenses
1 1000 500
2 200 0
account with ID=3 is not included in the result..
i know i am doing something wrong.. or may be completely wrong..
Thanks in advance.
You need to get all the accounts in the account table. To do that, you need a join, specifically an outer join:
select a.account_id, coalesce(sum(t.income),0) as total_income,
coalesce(sum(t.expenses),0) as total_expenses
from accounts a left join
transactions t
on a.account_id = t.account_id
group by a.account_id;
Your attempt to do this in the where clause is counterintuitive. The where clause filters values, so it reduces the number of rows; it cannot increase the number.
WITH TEMP AS
(
SELECT A.ID,T.*
FROM ACCOUNTS A INNER JOIN TRANSACTIONS T
ON A.ID=T.ID
)
SELECT ACCOUNT_ID,SUM(INCOME) AS INCOME,SUM(EXPENSE) AS EXPENSE FROM TEMP
GROUP BY ACCOUNT_ID;

How to run DISTINCT on non-key in SQL

I have a database that can have similar rows, but have different keys and a different boolean column. Here is what the database looks like:
columns: _id, name, img, address, available
Two entries can look like this:
_id | name | img | address | available
-------------------------------------------------------
1 | John | http://img.com/222 | 1 Main St | 1
2 | John | http://img.com/222 | 1 Main St | 0
I want a query that will give me all results that have a distinct key, and if there are duplicate entries(ignoring the fact that _id would be different), it will give back only the first one. Here is the query I have:
SELECT p1.*
FROM (SELECT DISTINCT _id, available FROM people) p
INNER JOIN people p1
ON p1._id=p._id
ORDER BY p1.available DESC;
I know this isn't right, but maybe it explains a little what I am looking for. Would I want to use GROUP BY here?
I want a query that will give me all results that have a distinct key, and if there are duplicate entries(ignoring the fact that _id would be different), it will give back only the first one.....the _id isn't what I want to be distinct, as they [the ids] are already unique. ... . Ideally it will order by 'available' in descending order so that if there are two columns with the same data(aside from _id and available), it will return the row with '1' for the available column
select name, image, address, max(availability) as avail
from T
group by name, image, address
Then you can join the set returned by the query above, as an inline view, to your table:
select * from T
inner join
(
select name, image, address, max(availability) avail
from T
group by name, image, address
) as foo
on T.name = foo.name and T.image = foo.image and T.address = foo.address and T.availability = foo.avail
It would help to have a composite index so: (name, image, address).
Caveat: if there is more than one row where a specific {name, image, address} triad has availablility =1, the query will return multiple rows for the triad:
2 | John | http://img.com/222 | 1 Main St | 1
6 | John | http://img.com/222 | 1 Main St | 1
P.S. It sounds as though you wished the triad (name, image, address) had been created in your table an alternate UNIQUE key.
this sql may solve your problem:
select b.* from (select distinct _id from people) a, people b where a._id = b._id order by b.available
I actually just asked a similar question and received a great answer from an experienced user here:
SQL Populating with distinct data and a sequence
Based on what he told me, perhaps this query would provide you with what you want:
SELECT p1.*
FROM (SELECT DISTINCT _id, name from people) p
INNER JOIN people p1
ON p1._id=p._id
ORDER BY p1.available desc
apologies if that's a fail and doesn't work!
EDIT: It just occurred to me that I have no idea which distinct name+_id combo this will extract.. the available=1 or the available=0 or a random selection..! Let me know what happens anyway..
If you want the first row which has the lowest _id among those that have the highest available value (between 1 and 0), you can "record" the _id inside the aggregated value generated by the grouping.
The value to compare is constructed in a way that orders the record by their available field in descending order and then by their _id field in descending order, and allow to easily retrieve the value of the _id with the modulo operator (assuming available max value is 1 and the ids are never above 100000000).
select people.* from people
inner join (
select name, img, address,
min((1-available)*100000000 + _id) avail_id
from people group by name, img, address
) as foo on people._id = foo.avail_id % 100000000;
I adapted it Tim's query.
You can also do that without subquery:
select people.* from people
left outer join people as other on
other.name = people.name and
other.img = people.img and
people.address=other.address and
(1 - people.available) * 100000000 + people._id >
(1 - other.available) * 100000000 + other._id
where other.available is null;

Sql query for filtering data with WHERE clause on same column

I have to tables:
Table A
id | title
1 | toto
2 | tata
3 | titi
Table B
id | title_id | tag_id
1 | 1 | 6
2 | 1 | 16
3 | 1 | 26
4 | 2 | 6
5 | 2 | 7
6 | 2 | 16
7 | 3 | 2
8 | 3 | 1
9 | 3 | 16
(Sorry for the bad table display)
In my application I have a tag listview with checkboxes, and when the user clicks a checkbox, I want to filter the titles with the clicked checkboxes:
(E.g: if user clicks tag 16, I should have title 1, 2 and 3 displayed. But if user clicks tag with id 26 AND tag with id 16, as result I should have only title with id 1)
I thought to a query like that:
SELECT DISTINCT A.title , A.id
FROM A
INNER JOIN B
ON B.title_id = A.id
WHERE B.tag_id = 26 AND B.tag_id = 16;
but obviously the last part of the query (two AND clause on a same column) is wrong, and I do not find a query which will give me this result.
I tried this :
SELECT DISTINCT A.title , A.id
FROM A
INNER JOIN B
ON B.title_id = A.id
WHERE B.tag_id IN ( '26', '16');
but the IN clause is like a OR clause, and as result, I get all the rows for value 26 plus all the rows for value 16 (title 1, 2 and 3) and not ONLY title 1.
I absolutely need to do this with and sql query because I'm using a SimpleCursorAdapter in order retrieve the datas and to fill an other listview.
I searched for a while, but I didn't find any relevant solution. (Or maybe I typed the wrong words...)
Do you have solution for me please?
PS: I hope I've been clear. Sorry for my bad english.
Use subqueries:
SELECT DISTINCT A.title, A.id FROM A WHERE
A.id IN (SELECT DISTINCT B.title_id FROM B WHERE B.tag_id='16')
AND A.id IN (SELECT DISTINCT B.title_id FROM B WHERE B.tag_id='26')

Categories

Resources