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....
Related
I am relatively new to SQL and I will try to get the terminology correct. I have 2 tables, tbl_Trans which holds the general transaction details, and tbl_TransData which holds the details of the transaction.
I want to show each Trans record and the category of the trans which is held in the tbl_TransData. If there is more than one category for each Trans I want the text to be 'Mulitple', otherwise to return the category field
TRANS table content
int_Trans_ID dtm_TransDate txt_Type txt_Description txt_Bank dbl_Amount
1 17/12/2018 REC Sales Current 1000
2 20/12/2018 PAY Expenses paid Current -155
3 21/12/2018 PAY MW Repairs Current -250
TRANSDATA table content
int_TransData_ID int_TransID txt_Category dbl_Amount
1 1 Sales A -600
2 1 Sales B -400
3 2 Travel 100
4 2 Meal 55
5 3 MW Repairs 250
This is the code so far, but if I replace the ELSE 'Single' with ELSE txt_Category it does not work.
SELECT
int_Trans_ID,
dtm_TransDate AS Date,
txt_Type AS Type,
txt_Description AS Description,
(SELECT
CASE
WHEN count(int_TransID) > 1
THEN 'Multiple'
ELSE 'Single'
END
FROM
dbo.tbl_TransData TD
WHERE
TD.int_TransID = T.int_Trans_ID) AS Category
FROM
tbl_Trans T
GROUP BY
int_Trans_ID, dtm_TransDate, txt_Type, txt_Description
This is what I would like to see.
int_Trans_ID Date Type Description Category
1 2018-12-17 REC Sales Multiple
2 2018-12-20 PAY Expenses paid Multiple
3 2018-12-21 PAY Car Repairs MW Repairs
Sorry for the format of the tables.
Any help would be much appreciated, or even pointing me in the direction of other posts.
I would do:
with
x as (
select ins_trans_id, count(*) as cnt, max(txt_category) as cat
from transdata
group by ins_trans_id
)
select
t.int_trans_id,
t.dtm_transdate,
t.txt_type,
t.txt_description,
case when x.cnt = 0 then 'no category'
when x.cnt = 1 then x.cat
else 'Multiple' end as Category
from trans t
left join x on x.int_trans_id = t.int_trans_id
Please have a look at this,
I wrote subquery for case condition
SELECT
int_Trans_ID,
dtm_TransDate,
txt_type,
txt_Description,
CASE WHEN (SELECT COUNT(*) FROM tbl_Trans_Data td WHERE td.int_Trans_ID = t.int_Trans_ID)) > 1 THEN
'MULTÄ°PLE'
ELSE
(SELECT Category from tbl_trans_data td Where td.int_Trans_ID = t.int_Trans_ID)
END AS Category
FROM
tbl_Trans t
I have two tables.
One is inventorytable with columns PO No,index,item name,amount,date,
PO Index Item amount date unit price
PO01 1 pen 20 1/2/2018 10
PO01 2 pad 15 1/3/2018 10
PO02 1 book 30 2/5/2018 10
Another table is paymentrecord with PO No,index,item name, amount, value.
PO Index Item amount
PO01 1 pen 10
PO01 2 pad 15
How to find inventory not paid or not fully paid?
PO Index Item amount unpaid value
PO01 1 pen 10 100
PO02 1 book 30 3000
I tried following sql
select *
from inventory
where not exists (select inventory.PONo,inventory.index
from inventory,payment
where inventory.PO=payment.PO )
but it returns nothing
Use an outer join to link payments to inventory. Filter on payment.amount being less than the calculated value of the inventory items, unit_price * amount:
select i.po_no
, i.Index
, i.Item
, i.amount
, ((i.unit_price * i.amount) - nvl(p.amount, 0) as unpaid_value
from inventory i
left join payment p
on p.po_no = i.po_no
and p.index = i.index
where (i.unit_price * i.amount) > nvl(p.amount, 0)
/
Note: the names of things are inconsistent across all your examples. So you may need to tweak this solution to make it run on your schema.
I guess you will need both, PO and Index, to uniquely identify record.
Try out below.
select * from inventory
where not exists
(select 1 from inventory,payment where inventory.PO=payment.PO and inventory.Index=payment.Index)
You can use below query
select i.ipo, i.iindex, i.iitem,
(i.iamount - coalesce(p.pamount,0)) as Tamount
from payment p right outer join invent i
on (i.ipo = p.ppo and i.iindex = p.pindex and i.iitem = p.pitem)
where i.iamount != coalesce(p.pamount,0)
This is result in
ipo iindex iitem Tamount
PO01 1 pen 10
PO02 1 book 30
Table structure followed is
create table invent
(
iPO varchar(4),
iIndex int,
iItem varchar(10),
iamount int,
idate date,
iunit_price int);
create table payment
(
pPO varchar(4),
pIndex int,
pItem varchar(10),
pamount int);
Hope following query helps. Use same column name instead of *.
select * from inventory
Except
select * from payment
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;
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.
Apologies for the confusing question title, but I'm not exactly sure how to describe the issue at hand.
I have two tables in Oracle 9i:
Pricing
-------
SKU
ApplicableTime
CostPerUnit
Inventory
---------
SKU
LastUpdatedTime
NumberOfUnits
Pricing contains incremental updates to the costs of each particular SKU item, at a specific Unix time. For example, if I have records:
SKU ApplicableTime CostPerUnit
------------------------------------
12345 1000 1.00
12345 1500 1.50
, then item 12345 is $1.00 per unit for any time between 1000 and 1500, and $1.50 for any time after 1500.
Inventory contains SKU, last updated time, and number of units.
What I'm trying to do is construct a query such that for each row in Inventory, I join the two tables based on SKU, I find the largest value for Pricing.ApplicableTime that is NOT greater than Inventory.LastUpdatedTime, get the CostPerUnit of that particular record from Pricing, and calculate TotalCost = CostPerUnit * NumberOfUnits:
SKU TotalCost
-----------------------------------------------------------------------------------
12345 (CostPerUnit at most recent ApplicableTime <= LastUpdatedTime)*NumberOfUnits
12346 <same>
... ...
How would I do this?
SELECT *
FROM
(select p.SKU,
p.ApplicableTime,
p.CostPerUnit*i.NumberOfUnits as cost,
row_number over (partition by p.SKU order by p.ApplicableTime desc) as rnk
from Pricing p
join
Inventory i on (p.sku = i.sku and i.LastUpdatedTime > p.ApplicableTime)
)
where rnk=1
select SKU, i1.NumberOfUnits * p1.CostPerUnit as TotalCost
from Inventory i1,
join (
select SKU, max(ApplicableTime) as ApplicableTime, max(i.LastUpdatedTime) as LastUpdatedTime
from Pricing p
join Inventory i on p.sku = i.sku
where p.ApplicableTime < i.LastUpdatedTime
group by SKU
) t on i1.sku = t.sku and i1.LastUpdatedTime = t.LastUpdatedTime
join Pricing p1 on p1.sku = t.sku and p1.ApplicableTime = t.ApplicableTime