How to join tables based on the dates - sql

COMMISSION table
PRODUCT_ID DATE COMMISSION
1 20110101 27.00
1 20120101 28.00
1 20130705 30.00
2 20110101 17.00
2 20120501 16.00
2 20130101 18.00
...
ORDER table
PRODUCT_ID DATE PRICE
1 20110405 2500
2 20130402 3000
2 20130101 1900
Desired output
PRODUCT_ID DATE PRICE COMMISSION
1 20110405 2500 27.00
2 20130402 3000 16.00
2 20130101 1900 18.00
Commission table records commission % based on the product id and date.
Order table is basically a record of orders placed on a particular date,
I'd like to join two tables and bring the appropriate commission based on the date of the order. For example, you can see that the first order's commission is 27.00 as the date for the product_id 1 falls between 20110101 and 20120101.
How do I do this? Seems like a simple 1 to n relationship but I can't figure it out.

Try
SELECT o.*,
(
SELECT TOP 1 commission
FROM commission
WHERE product_id = o.product_id
AND date <= o.date
ORDER BY date DESC
) commission
FROM [order] o
Here is SQLFiddle demo

Related

Subtract Daily amount from Withdraw Amount

I have two tables, tblWithdraw and tblProfit.
tblWithdraw Table
WithdrawId Date User Price
-----------------------------------------------------
1 2021-02-09 SANDANUWAN 2000.00
2 2021-02-09 GAYAN 300.00
3 2021-02-09 KASUN 1500.00
4 2021-02-09 AMAL 4000.00
5 2021-02-09 UDARA 340.00
6 2021-02-09 SULIN 200.00
7 2021-02-09 PERERA 120.00
tblProfit Table
Id Date Inv.No ItemName ItemCode Qty CostPrice DiscountPrice Amount
----------------------------------------------------------------------------------------------
1 2021-02-09 INV0000001 DELL LAP LP001 5 1500.00 1900.00 9500.00
2 2021-02-09 INV0000001 HP MOUSE MO001 7 2500.00 2940.00 20580.00
3 2021-02-09 INV0000001 PACIFIC FAN FAN001 6 2000.00 4000.00 24000.00
4 2021-02-09 INV0000001 SAMSUNG PHONE PH001 8 1000.00 1350.00 10800.00
This is my question. I want to sum all price from tblWithdraw table according to the date. Its mean withdraw date and profit table must be match. New I want to sum all amount from tblProfit table.Then I want to Subtract like this Price - Amount. Finally I want to show total amount of Profit table after subtracted. I used following join but is not working well. please help me to solve this problem. I want to subtract according to the date.
Select MAX(w.Date)Date, SUM(w.Price)Price, SUM(p.Amount)Amount
From tblWithdraw w
Left Join tblProfit p
ON w.Date = p.CurrentDate
Group by w.Date
Out put is like this. its wrong.
Date Price Amount
2021-02-09 33840.00 454160.00
Here's my CTE-based approach based on the comment which I made on the initial question.
WITH WithDraw AS(
SELECT
[date]
,SUM(price) PRICE
FROM tblWithdraw
GROUP BY [date]
),
Profit AS(
SELECT
[date]
,SUM(amount)AMOUNT
FROM tblProfit
GROUP BY [date]
)
SELECT
W.DATE
,W.PRICE
,P.AMOUNT
FROM WithDraw W
INNER JOIN Profit P ON w.date = p.date;
I'm not sure I fully understand the question, this is how I'm reading it:
Select w.Date,
w.agg_price_by_date,
w.agg_price_by_date - COALESCE(p.agg_amount_by_date, 0) AS diff_price_amount
From (SELECT Date,
SUM(Price) AS agg_price_by_date
FROM tblWithdraw w
GROUP
BY Date
) w
Left Join
(SELECT CurrentDate,
SUM(Amount) AS agg_amount_by_date
FROM tblProfit
GROUP
BY CurrentDate
) p
ON w.Date = p.CurrentDate

Max and Avg debt days over a period of time

I have invoices pending payment, every invoice has two dates, first when the invoice is required to pay and the other when the invoice is paid. I want to know in a period of time the max debt and the avg debt
This is the table
Id Invoice Amount InvoiceDate InvoicePayment
----------- ------- ----------- ----------- -------------
1 Bill 1 314 2019-01-20 2019-03-01
2 Bill 2 205 2019-01-14 2019-02-18
3 Bill 3 90 2019-02-04 2019-02-06
4 Bill 4 456 2019-01-03 2019-04-27
I would like to know the max debt amount in february and the avg debt
You can unpivot with cross apply, and use a window sum to compute the "running" debt at each given point in time. The rest is just filtering and aggregation:
select avg(debt) avg_debt, max(debt) max_debt
from (
select x.dt, sum(x.amount) over(order by x.dt) debt
from mytable t
cross apply (values (invoicedate, amount), (invoicepayment, -amount)) as x(dt, amount)
) t
where dt >= '20200201' and dt < '20200301'

sql quest with amount and exchange rate

How to choose customers who have made a large amount of payments in December 2018 if we take into account the exchange rate
I have a table:
Trandate date - transaction date
Transum numeric (20,2) - amount of payment
CurrencyRate numeric (20,2) - currency exchange rate
ID_Client Trandate Transum CurrencyRate Currency
--------------------------------------------------------
1 2018.12.01 100 1 UAH
1 2018.12.02 150 2 USD
2 2018.12.01 200 1 UAH
3 2018.12.01 250 3 EUR
3 2018.12.02 300 1 UAH
3 2018.12.03 350 2 USD
7 2019.01.08 600 1 UAH
but I think that "max" is not at all what I need
SELECT ID_Client, MAX(Transum*CurrencyRate)
FROM `Payment.TotalPayments`
WHERE YEAR(Trandate) = 2018
AND MONTH(Trandate) = 12
I need something this
ID_Client Transum
3 1750
Where 1750 is a "UAH" and 350USD + 300UAH + 250EUR, exchange rate of USD is 2, exchange rate of EUR is 3.
If you're trying to get the sum of transaction amounts by client for the year 2018 and month of December, you could write it like this:
SELECT ID_Client, SUM(Transum*CurrencyRate) as payment_total_converted
FROM `Payment.TotalPayments`
WHERE YEAR(Trandate) = 2018
and MONTH(Trandate) = 12
group by ID_Client
If you want things grouped by each client, year, and month in a given date range, you'd write it like this:
SELECT ID_Client, YEAR(Trandate) as tran_year, MONTH(Trandate) as tran_month,
SUM(Transum*CurrencyRate) as payment_total_converted
FROM `Payment.TotalPayments`
WHERE Trandate between '2018-12-01' and '2019-01-01'
group by ID_Client, YEAR(Trandate), MONTH(Trandate)
I added a column name for your computed column so that the result set is still relational (columns need distinct names).
I'd recommend reading up on the SQL 'group by' clause (https://www.w3schools.com/sql/sql_groupby.asp) and aggregate (https://www.w3schools.com/sql/sql_count_avg_sum.asp, https://www.w3schools.com/sql/sql_min_max.asp) operators.
I think you want sum(). Then you can order by the result:
SELECT ID_Client, SUM(Transum*CurrencyRate) as total
FROM `Payment.TotalPayments`
WHERE Trandate >= '2018-12-01' AND Transdate < '2019-01-01'
GROUP BY ID_Client
ORDER BY total DESC;

Calculate payment date for each invoice

Please consider the following table transaction: a company regularly sends invoices to their customers that are part of the same order. The companies' clients will often pay only once per so many weeks.
(trans_date in format yyyy-mm-dd)
id order_id trans_type trans_date trans_amount
----------------------------------------------------------
1 1 invoice 2017-01-10 100
2 1 invoice 2017-05-23 150
3 1 invoice 2017-05-28 200
4 2 invoice 2017-03-01 700
5 2 payment 2017-06-16 700
6 1 payment 2017-10-12 450
7 3 invoice 2017-06-24 199
The company would like to see on what date each invoice was paid for. For example: invoice (id) 1 (part of order_id=1 group) was sent on 2017-01-10 and paid on 2017-10-12 (id=6). Invoice with id=7 has not been paid at all.
The desired output would be the payment date for each invoice (payment_date):
id order_id trans_type trans_date trans_amount payment_date
--------------------------------------------------------------------------
1 1 invoice 2017-01-10 100 2017-10-12
2 1 invoice 2017-05-23 150 2017-10-12
3 1 invoice 2017-05-28 200 2017-10-12
4 2 invoice 2017-03-01 700 2017-06-16
5 2 payment 2017-06-16 700
6 1 payment 2017-10-12 450
7 3 invoice 2017-06-24 199
For transactions 5, 6 and 7, the payment_date is empty because it is either a payment (id=5 and 6) or an unpaid invoice (id=7).
I don't understand how I should solve this issue. In combination with regular scripting, I would get the whole set and loop through it to find each payment. But how can this be solved in SQL only?
Any help would be greatly appreciated!
Did you try a simple left join?
Below code is standard SQL.
Select a.id , a.order_id, a.trans_type, a.trans_date, a.trans_amount, isnull(b.trans_date, '') As payment_date
From transaction a
Left join transaction b
On a.order_id = b.order_id
And a.trans_type = 'invoice'
And b.trans_type = 'payment'
You can do a cumulative sum of payments and invoices and get the first date when the payment total meets or exceeds the invoice total:
with ip as (
select ip.*,
sum(case when ip.trans_type = 'invoice' then ip.trans_amount else 0 end) over (order by ip.trans_date) as running_invoice,
sum(case when ip.trans_type = 'payment' then ip.trans_amount else 0 end) over (order by ip.trans_date) as running_payment,
from invoicepayments i
)
select ip.*,
(select min(ip2.trans_date)
from ip ip2
where ip2.running_payment >= ip.running_invoice and
ip.trans_type = 'invoice'
) as payment_date
from ip;

Datediff with dates in one column but only showing datediff compared to the next invoice

This is to understand how long it took the customer to pay a bill.
The datediff needs to be the next invoice to the payments
as Below example
ID Type1 Amount Date
--------------------------------------------------------------------
1 Invoice 38.16 2014-04-25
1 Payment -40.00 2014-03-23
1 Invoice 40.86 2014-02-22
1 Payment -40.00 2014-02-21
1 Invoice 42.21 2014-01-20
ID Type1 Amount Date DATEDIFF
---------------------------------------------------------
1 Invoice 38.16 2014-04-25
1 Payment -40.00 2014-03-23 29
1 Invoice 40.86 2014-02-22
1 Payment -40.00 2014-02-21 32
1 Invoice 42.21 2014-01-20
This can be done in many ways, one option is to use a correlated sub-query to get the date of the preceding row with item=invoice for all item=payment rows:
select
id, type1, amount, date,
datediff(day,
(select top 1 date
from table1
where date <= t.date
and type1= 'Invoice'
and t.type1='Payment'
order by date desc),
date) as diff
from table1 t;
This might not be the most efficient solution though.
Sample SQL Fiddle
Or you could use an outer apply with the same effect: http://www.sqlfiddle.com/#!6/b1e32/19