Query to return zero if nothing exist - sql

I have a table with currency, paymenttype and invoiceamount. I have to write query to get currency, paymenttype and total invoiceamount made. This is pretty simple with group by. But actually I have three payment type 0, 1 ,2 and data in table is
Currency. Paymenttype invoice amount
Aaa. 0. 100
Aaa. 1. 200
Aaa. 1. 50
Bbb. 0. 150
Bbb. 1. 100
Bbb. 2. 100
My query is Select currency, paymenttype, sum(invoiceamount) as total from table group by currency, paymenttype
Result
Currency paymenttype total
Aaa. 0. 100
Aaa. 1. 250
Bbb. 0. 150
Bbb. 1. 100
Bbb. 2. 100
But what I want is as Aaa. Does not have 2 paymenttype is should also show a row with 0 value like below.
Aaa. 2. 0
How to do this?

You can generate all the rows using a cross join and then join in the data you want:
select c.currency, pt.paymenttype,
coalesce(sum(i.invoiceamount), 0) as total
from currency c cross join
paymenttype pt left join
invoice i
on i.currency = c.currency and i.paymenttype = pt.paymenttype
group by c.currency, pt.paymenttype;

You should have a table containing all the types.
Then you would simply do a left join on the payment_type_id an output the total, or 0 if nothing.
If you don't have a table with all the types, then you could simulate it but that would be a dirty fix :
select a.currency, b.paymenttype, coalesce(sum(a.invoiceamount), 0)
from (select 0 as paymenttype,
union all select 1 as paymenttype,
union all select 2 as paymenttype) b
left join yourTable a on a.paymenttype = b.paymenttype
group by a.currency, b.paymenttype;

Related

SQL: Select count of accomplished invoices with all items checked

My customers submit invoices with some items in each one. I want to calculate number of accomplished invoices (which all items are checked by operator)
sample data:
invoiceNumber | ItemNumber | Status
a 1 Null
a 2 checked
a 3 Null
b 1 checked
b 5 checked
In sample data above, the number of finished invoice is 1 because all items in invoice number "B" are checked and number of unfinished invoices is 1 because in invoice "A", only 1 item is checked.
My try:
select count(distinct invoiceNumber) as total
from invoices
where status is not null
Returns 2! I should not count row number 2 because 1 and 3 are still Null.
The distinct is the problem as you count the unique appearances of the invoiceNumber as the result. As there are two bs checked and one a, the count is 2
Try using the select count (*) instead or some unique id of the invoice (if there is one).
Edit:
I have misread your question. To count only the invoices that have all the rows with the status checked, you can use the group by and having.
Something similar to:
select count(distinct invoiceNumber) as total
from invoices
group by invoiceNumber, status
having status is not null
use the below query..
SELECT count(distinct invoiceNumber) as total
FROM from invoices
WHERE invoiceNumber NOT IN (SELECT invoiceNumber
FROM invoices WHERE status IS null)
You need to exclude all invoices that have a NULL status for the same invoicenumber:
select count(distinct i1.invoicenumber)
from invoices i1
where not exists (select *
from invoices i2
where i2.invoicenumber = i1.invoicenumber
and i2.status is null);
Another option is to use except to remove those that have a null status:
select count(*)
from (
select invoicenumber
from invoices
except
select invoicenumber
from invoices
where status is null
);

SQL SUM problems

I have this Query:
Select Denumire,Sum(Livrari.Cantitate)as Stoc,
isnull(Sum(Facturi_Emise.Cantitate),0) as 'Sold',
isnull(Sum(Livrari.Cantitate),0)-isnull(sum(Facturi_Emise.Cantitate),0) As 'Stoc After Sales',
Livrari.Id_Depozit
From Livrari
Left join Produse On Livrari.Id_Produs=Produse.Id_Produs
Left join Facturi_Emise On Produse.Id_Produs=Facturi_Emise.Id_Produs
group by Denumire, Livrari.Id_Depozit
order by Denumire
I need to get the Stock, the quantity of the items that are required to be sold, and what I got in the 2 deposits after the items are sold. But in the table "Livrari" I got the same item in both deposit, with the amount of 300 for deposit 1, and 300 for deposit 2 and when I make the sum and group by Id_Depozit I get that item with the amount of 600 in deposit 1 and 600 in deposit 2, same is for table Facutri_Emise as I should take only 250 items from deposit 1 and 300 from deposit 2, it takes 550(250+300) from both deposit and I got the Stoc after Sale 50 for each, instead of 50 for deposit 1 and 0 for deposit 2.
fiddle
My problem is that the result in row 8 and 9(that means Pahare) in column Stoc should be 300 for each. In next column Sold, row 8 should be 250 and for row 9 300. In the end, in column Stoc after Sale should be the difference, as row 8=50, row 9=0.
I mean each time a products repeats, my query is gonna make the sum and put the same value in deposit 1 and in deposit 2, as I give different values for each deposit it should show me the correspondent values. A supplier will bring a certain amount if items(let's say apples) into deposit 1 and another supplier will bring another amount of apples in deposit 2. When the bill is made("Facturi_Emise") for the client I should sent an amount of apples from deposit 1 and another from deposit 2 and I wanna see what amount remains in one deposit,and what remains in other one.
Here it is.
It is not ordered by deposit numbers,but it's okey.
SELECT Produse.Denumire,
Isnull(a.suma,0) AS Intrari,
Isnull(b.suma,0) AS Iesiri,
isnull(a.suma,0) - isnull(b.suma,0) AS Stoc
FROM Produse
LEFT JOIN
(SELECT ID_Produs, Sum(Cantitate) AS suma FROM Livrari GROUP BY ID_Produs)
AS a
ON Produse.ID_Produs = a.ID_Produs
LEFT JOIN
(SELECT ID_Produs, Sum(Cantitate) AS suma FROM Facturi_Emise GROUP BY ID_Produs)
AS b
ON Produse.ID_Produs = b.ID_Produs
SOLLUTION
Select Denumire,Sum(Livrari.Cantitate)as Stoc,
SUM(ISNULL(Facturi_Emise.Cantitate,0)) as 'Sold',
SUM(ISNULL(Livrari.Cantitate,0))-SUM(ISNULL(Facturi_Emise.Cantitate,0)) As 'Stoc After Sales',
Livrari.Id_Depozit
From Livrari
Left join Produse On Livrari.Id_Produs=Produse.Id_Produs
Left join Facturi_Emise On Produse.Id_Produs=Facturi_Emise.Id_Produs
and Livrari.Id_Depozit=Facturi_Emise.Id_Depozit
group by Denumire, Livrari.Id_Depozit
order by Denumire
You need ceck null before sum, soo first ISNULL and then SUM.
If you SUM and one is null then all SUM will be null.

Postgres/SQL: modeling charges and refunds against a payment source

I have the following models and I want to write a query which will return unspent credits. Credits have many charges which in turn have many refunds. My attempt at the query so far is below but I have found a problem with it and need a little help. All the amount columns are positive.
Credit
id (integer)
amount (decimal)
Charge
id (integer)
credit_id (integer)
amount (decimal)
Refund
id (integer)
charge_id (integer)
amount (decimal)
My query looks like this:
SELECT credits.*,
"credits"."amount" - coalesce(sum("charges"."amount"), 0) + coalesce(sum("refunds"."amount"), 0) AS unspent_amount
FROM "credits"
LEFT OUTER JOIN "charges" ON "charges"."credit_id" = "credits"."id"
LEFT OUTER JOIN "refunds" ON "refunds"."charge_id" = "charges"."id"
GROUP BY "credits"."id"
HAVING "credits"."amount" > coalesce(sum("charges"."amount"), 0) - coalesce(sum("refunds"."amount"), 0) LIMIT 1
The problem I have encountered is that if a charge has many refunds, the sum of the charges amount will be N* where N is the number of refunds. I want to count the charge amount only once for each charge id.
Ultimately I want credits where credits.amount > sum of charges_against_credits.amount - refunds_for_those_charges.amount. How can I achieve this?
EDIT:
Here are some sample records which will reproduce the problem:
credits
id 1
amount 25.0
charges
id 1
credit_id 1
amount 25.0
refunds
id 1
charge_id 1
amount 20.0
-----------
id 2
charge_id 1
amount 5.0
EDIT 2:
Expected output:
credits:
1 row:
id: 1, amount: 25.0, unspent_amount: 25.0
SELECT a.ID,
(a.amount - COALESCE(b.totalCharges, 0)) + COALESCE(c.totalRefunds, 0) AS unspent_amount
FROM credits AS a
LEFT JOIN
(
SELECT credit_ID, SUM(amount) totalCharges
FROM charges
GROUP BY credit_ID
) AS b ON a.ID = b.credit_ID
LEFT JOIN
(
SELECT aa.credit_ID, SUM(bb.amount) totalRefunds
FROM charges AS aa
LEFT JOIN Refund AS bb
ON aa.ID = bb.Charge_ID
GROUP BY aa.credit_ID
) AS c ON b.credit_ID = c.credit_ID
-- WHERE clause ...here....

Individual percentage for each item, throughput

With the following code I get how many items that is not "Out", but it returns percentage for all the items and not for each individual. I know it has to do with the count(date) that counts all the date of the all the unitids. Is there any way to count each item individual so it doesn't show the total percentage?
SELECT unitid, (COUNT(date)* 100 / (SELECT COUNT(*) FROM items)) AS Percentage
FROM items
WHERE date !='Out'
GROUP BY unitid
EDIT1, clarification: Lets say I have 2 of each product, product a, b, c, d and e, one of each item is 'Out'. The result I get is:
unitid Percentage
1. a 10
2. b 10
3. c 10
4. d 10
5. e 10
I'd like it to show this instead:
unitid Percentage
1. a 50
2. b 50
3. c 50
4. d 50
5. e 50
Thanks :)
You need a link between the count items and the item selected.
SELECT
unitid,
COUNT(date) * 100
/ (SELECT COUNT(*) FROM items B WHERE B.unidid = A.unitid) AS Percentage
FROM items A
WHERE date !='Out'
GROUP BY unitid
You query does not require a subquery, just a conditional aggregation:
SELECT i.unitid, 100*sum(case when date <> 'Out' then 1 else 0 end)/count(date) as Percentage
FROM items i
GROUP BY unitid
Assuming that [date] is never NULL, you express this more simply as:
select i.unitid, 100*avg(case when date<>'out' then 1.0 else 0 end) as Percentage
from items i
group by unitid
Let's see if I understand this correctly. If you have one a, two b, three c, and four d's, one of each is "Out", whatever that is, your result set should be:
unitid Percentage
1. a 100.00
2. b 50.00
3. c 33.33
4. d 25.00
To do that, you can try this:
Select counts.unitId, 100.0 *outcounts.count/ counts.count as Percentage
from (select unitid, count(*) as count
from items
where items.date ='Out'
group by unitid) as outcounts
inner join (select unitid, count(*) as count
from items
group by unitid) as counts
on outcounts.unitId = counts.unitId
here's an SQL Fiddle with the setup

mysql table inside join

I have table tblsale.
In this table i have field called BillType, which contains "s" and "r" (s = sale , r = returns )
The table has rougly 25 records. Of that, 7 records are "r", and rest of the records are "s".
How do I write the query so that my result set includes the following columns:
What is want exactly is below
Amount BillType Amount BillType Date
100 s 50 r 29-11-2010
120 s 20 r 28-11-2010
130 s 30 r 27-11-2010
140 s 50 r 26-11-2010
What you appear to want are the results of two queries, sales and returns, side by side. It can be done with a kludge like this:
select amount, sale, returnamount, returned, returndate
from
(
select amount, 1 as sale, 0 as returnamount, 0 as returned, '' as returndate
from sales where billtype='s'
union
select 0 as amount, 0 as sale, amount as returnamount, 1 as returned, date as returndate
from sales where billtype ='r'
)
You may have to cast date into a string representation. The unioned sets need the same column structure, so you create dummy columns. (You didn't ask for a sale date for sales.)
Or you can do this with CASE WHEN statement.
I'm not sure what you are asking, but maybe:
SELECT BillNo, VAT, BillType, AfterDiscount FROM tblsale WHERE BillType = 's';