count of Balance installments - sql

i got a requirement to write a MS-SQL stored procedure, the requirement is
Table 1
It consists total student fee to be paid in installments
EX:
SID SNAME INST.Date Amount
123 XYZ 01-01-2013 3500
123 XYZ 01-05-2013 3500
123 XYZ 01-10-2013 3500
123 XYZ 01-04-2014 3500
123 XYZ 01-06-2014 3500
`
Table 2
It consists Payment recd details
SID SNAME Paydate amoount
123 XYZ 01-01-2013 1167
123 XYZ 01-02-2013 1167
123 XYZ 01-03-2013 1167
123 XYZ 01-05-2013 1750
123 XYZ 01-05-2013 1750
123 XYZ 01-10-2013 1167
123 XYZ 01-10-2013 1167
now the requirement is as on jan2014,how many installment to paid,what is the Recd amount, no of balance installments to be paid as on jan-14.
Expected output
SID Sname Total Inst.Amt as on01.01.2014 Paid.amount Balance amt Balance.Installments
123 XYZ 10500 9335 1165 1
For reference I gave one student data.
The stored procedure should run for 36000 students.

Here's a query that will give you what you want, expect Balance.Installments I don't know what it means :
SELECT distinct t1.SID
, t1.SNAME
, t1.Total_Inst
, t2.Paid_amount AS 'Paid.Amount'
, t1.Total_Inst - t2.Paid_amount as 'Balance amt'
, CEILING( (t1.Total_Inst - t2.Paid_amount) / t.Amount ) as 'Balance.Installments'
FROM
table_1 as t
JOIN
( SELECT SID, SNAME, SUM(Amount) as Total_Inst
FROM table_1
WHERE Date < STR_TO_DATE('01/01/2014', '%m/%d/%Y') group by SID, SNAME
)
ON ( t1.SID = t.SID AND t1.SNAME = t.SNAME )
AS t1
LEFT JOIN
( SELECT SID, SNAME, SUM(Amount) as Paid_amount
FROM table_2
WHERE Paydate < STR_TO_DATE('01/01/2014', '%m/%d/%Y') group by SID, SNAME
) AS t2
ON ( t1.SID = t2.SID AND t1.SNAME = t2.SNAME )

why you will need to run for 36000 record at one time.Also what is actially installment.There is only one instalment for any student no several.So i think database is lil wrong.
There should only one instalment amount and time interval(due date) per student in table.
Check the latest change.It is only for one student .
Declare #student table(SID int,SNAME varchar(50),INST Date ,Amount int)
insert into #student
select 123,'XYZ','01-01-2013',3500 union all
select 123, 'XYZ', '01-05-2013', 3500 union all
select 123, 'XYZ', '01-10-2013', 3500 union all
select 123, 'XYZ', '01-04-2014', 3500 union all
select 123, 'XYZ', '01-06-2014', 3500
Declare #instalmentamount float
select #instalmentamount=amount from #student where sid=123
--select #instalmentamount
Declare #Table2 table(SID int,Paydate date,amoount int)
insert into #Table2
select 123, '01-01-2013', 1167 union all
select 123, '01-02-2013', 1167 union all
select 123, '01-03-2013', 1167 union all
select 123, '01-05-2013', 1750 union all
select 123, '01-05-2013', 1750 union all
select 123, '01-10-2013', 1167 union all
select 123, '01-10-2013', 1167
declare #input date='01-01-2014'
;With CTE as
(select s.SID, sum(s.amount) as [Total Inst.Amt ] from #student s
where s.INST<=#input
group by s.SID),
cte1 as
(
select t.SID, sum(t.amoount) as [Paid.amount] from #Table2 t
where t.Paydate<=#input
group by t.SID
)
select c.sid,
(select top 1 s.SNAME from #student s where s.SID=c.SID) [Name],
c.[Total Inst.Amt ],c1.[Paid.amount],
c.[Total Inst.Amt ]-c1.[Paid.amount] [BalanceAmount],cast(((c.[Total Inst.Amt ]-c1.[Paid.amount])/#instalmentamount) as int)+1 [Balance.Installments]
from CTE c inner join cte1 c1 on c.SID=c1.SID

TRY THIS...
SELECT t.ID,
T.SNAME,
T.AMT 'Total Inst.Amt as on01.01.2014',
ISNULL(SUM(amoount),0) AS 'PAID AMT',
T.AMT - ISNULL(SUM(amoount),0) AS 'BALANCE AMT' ,
CEILING((T.AMT- ISNULL(SUM(amoount),0) )/( T.InstAmt*1.)) 'Balance.Installments'
FROM
(
SELECT ID,SNAME,SUM(AMT)AMT,MAX(AMT) AS InstAmt FROM #Table1 WHERE DT_ < '01-31-2014' GROUP BY ID,SNAME
) T
LEFT JOIN #Table2 P ON P.ID = T.id AND P.Paydate < '01-31-2014'
GROUP BY t.ID,SNAME,t.InstAmt,T.AMT

Related

Find sum() from two different tables and join them based on a condition?

I have two tables,
Table1:
ID Amount Date
------------------
123 500.00 02-Sep-2020
123 240.00 02-Sep-2020
124 200.50 02-Sep-2020
125 150.70 03-Sep-2020
123 480.80 03-Sep-2020
Table2
ID Settled_Amount Date
-------------------------------
123 150.25 02-Sep-2020
124 200.00 03-Sep-2020
125 100.40 03-Sep-2020
I want to sum the Amount column of table1 and sum the settled_amount column of Table2 of a particular ID group by the Date column.
So My result would be for ID=123:
Sum(Amount) Sum(Settled_amount) Date
------------------------------------------
740.00 150.25 02-Sep-2020
480.80 03-Sep-2020
You can use union all and group by. For all ids:
select id, date, sum(amount), sum(amount_settled)
from ((select id, date, amount, null as amount_settled
from table1
) union all
(select id, date, null as amount, amount_settled
from table2
)
) t
group by id, date
order by date;
You can filter for a particular id using a where clause in the outer query.
Another way to write it without subseleting as Gordon does.
declare #table1 table (id int, amount numeric(18,2), Dates Date)
Insert into #table1
values
(123 ,500.00 ,'02-Sep-2020'),
(123 ,240.00 ,'02-Sep-2020'),
(124 ,200.50 ,'02-Sep-2020'),
(125 ,150.70 ,'03-Sep-2020'),
(123 ,480.80 ,'03-Sep-2020')
declare #table2 table (id int, Settled_Amount numeric(18,2), Dates Date)
insert into #table2
values
(123 , 150.25 ,'02-Sep-2020'),
(124 , 200.00 ,'03-Sep-2020'),
(125 , 100.40 ,'03-Sep-2020');
with Table1 as (
select sum(amount) as Amount,ID,Dates from #table1
group by ID,Dates
)
,
Table2 as (
Select sum(Settled_amount) as Settled_amount, ID,Dates from #table2
group by ID,Dates
)
select Amount,Settled_amount,a.Dates,a.ID from Table1 a left join table2 b on a.id = b.id and a.Dates = b.Dates
where a.id=123

T SQL Cte delete where group by is greater than 1

I'm using SQL Server 2016. I have the below table:
SKU Mkt Week Cost Code
ABC 05 1 10 100
ABC 05 2 12 100
DEF 05 3 20 100
DEF 05 3 25 125
XYZ 08 1 10 100
XYZ 08 2 12 100
XZY 08 2 14 125
This is the desired result:
SKU Mkt Week Cost Code
ABC 05 1 10 100
ABC 05 2 12 100
DEF 05 3 25 125
XYZ 08 1 10 100
XZY 08 2 14 125
So if a SKU\Mkt\Week\Cost exist more than once, I want to keep the record where code = 125 and delete the row where the code is 100.
I'm using the below Cte:
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
ORDER BY SKU, Mkt, Week)
FROM [table]
WHERE code = 100
)
DELETE FROM CTE
WHERE RN > 1
However, the Cte doesnot delete anything -what am I missing?
Based on the query and sample data you have provided, You need to note to this section of the cte inner query:
WHERE code = 100
when this filter applied you have the following data:
SKU Mkt Week Cost Code
ABC 05 1 10 100
ABC 05 2 12 100
DEF 05 3 20 100
which will get the 1 as Row_Number()'s output!, so running the following query will not effect any rows:
DELETE FROM CTE
WHERE RN > 1
To achieve the desired result you need to remove the WHERE section in CTE's inner query.
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
ORDER BY SKU, Mkt, Week, Cost DESC) --Code/Cost DESC <==== Note this too
FROM [table]
--WHERE code = 100 <========== HERE, I've commented it
)
DELETE FROM CTE
WHERE RN > 1
You need to also add the Cost DESC or Code Desc to Row_Number()'s Order By section.
Ranking function will be evaluated in the select statement , which means the where clause WHERE code = 100 is evaluated before ROW_NUMBER() and so it has already removed the rows with code 125. Use order by Code as well and then apply the code=100 check when deleting from the CTE
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
ORDER BY SKU, Mkt, Week,Code DESC)
FROM tt1
)
DELETE FROM CTE
WHERE RN > 1
AND CODE = 100
Try below query to get the desired result -
Sample data and Query
Declare #Table table
(SKU varchar(20), Mkt int, [Week] int, Cost int, Code int)
Insert into #Table
values
( 'ABC', 05 , 1, 10 , 100),
( 'ABC' , 05 , 2 , 12 , 100),
('DEF' ,05 , 3 , 20 , 100),
('DEF' ,05 , 3 ,25 , 125),
('XYZ' , 08 , 1 ,10 , 100),
('XYZ' , 08 , 2 ,12 , 100),
('XYZ' , 08, 2 ,14, 125)
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
ORDER BY SKU, Mkt, Week, code desc)
FROM #Table
)
delete from Cte where RN > 1
Along with moving your Where statement, I believe you also want a second cte to work with the records you are identifying... In the following your first cte identifies the duplicate records while the second cte isolates them so you can perform your delete against those SKUs
Table
Create Table #tbl
(
SKU VarChar(10),
Mkt VarChar(10),
Week Int,
Cost Int,
Code Int
)
Insert Into #tbl Values
('ABC','05',1,10,100),
('ABC','05',2,12,100),
('DEF','05',3,20,100),
('DEF','05',3,25,125),
('XYZ','08',1,10,100),
('XYZ','08',2,12,100),
('XYZ','08',2,14,125)
Query
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
ORDER BY SKU, Mkt, Week)
FROM #tbl
--WHERE code = 100
)
, cte1 As
(
Select sku from cte where rn > 1
)
DELETE c FROM CTE c inner join cte1 c1 On c.SKU = c1.SKU
WHERE c.Code = 100
Select * From #tbl
Result (Your 'desired result' example removed an XYZ record where the week was not duplicated?)
SKU Mkt Week Cost Code
ABC 05 1 10 100
ABC 05 2 12 100
DEF 05 3 25 125
XYZ 08 1 10 100
XYZ 08 2 12 100
XZY 08 2 14 125
Your CTE statement is only considering rows with code = 100. If you remove it, then CTE will rank based on all rows from the table. Using this, first find out which combination of have multiple rows. Then, among these combinations, identify rows with code = 100 and delete them.
create table #e1
(
SKU varchar(50)
,Mkt varchar(50)
,_Week int
,Cost int
,_code int
)
insert into #e1(SKU, Mkt, _Week, Cost, _code)
select 'ABC', '05', 1, 10, 100 UNION
SELECT 'ABC', '05', 2, 12, 100 union
SELECT 'DEF', '05', 3, 20, 100 UNION
SELECT 'DEF', '05', 3, 25, 125 UNION
SELECT 'XYZ', '08', 1, 10, 100 UNION
SELECT 'XYZ', '08', 2, 12, 100 UNION
SELECT 'XZY', '08', 2, 14, 125
delete s
from
#e1 s
JOIN
(
SELECT SKU, Mkt, _Week
FROM #e1
group by
SKU, Mkt, _Week
having count(1) > 1
) m
ON
s.SKU = m.sku and s.mkt = m.mkt and s._Week = m._Week
WHERE s._code = 100
Create table #tab1 (SKU varchar(50),Mkt varchar(50),[Week] varchar(50),Cost varchar(50),Code varchar(50))
insert into #tab1
select 'ABC','05','1','10','100'
union
select 'ABC','05','2','12','100'
union
select 'DEF','05','3','20','100'
union
select 'DEF','05','3','25','125'
union
select 'XYZ','08','1','10','100'
union
select 'XYZ','08','2','12','100'
union
select 'XYZ','08','2','14','125'
delete t from #tab1 t
inner join (select t1.SKU,t1.Mkt,t1.[Week],t1.Cost as Cost,t1.Code as Code,ROW_NUMBER()over(partition by t1.SKU,t1.Mkt,t1.[Week] order by t1.Cost desc,t1.Code desc ) as rno
from #tab1 t1
) c on c.SKU = t.SKU and c.Mkt = t.Mkt and c.Cost = t.Cost and c.[Week] = t.[Week] and c.Code = t.Code
where c.rno = 2
select * from #tab1
Output:
SKU Mkt Week Cost Code
ABC 05 1 10 100
ABC 05 2 12 100
DEF 05 3 25 125
XYZ 08 1 10 100
XYZ 08 2 14 125

How to use SUM and COUNT and add the results as a resulting column

CREATE TABLE my_table ( bank_account, bank_id, amount ) AS
SELECT 123, 600, 1500 FROM DUAL UNION ALL
SELECT 123, 600, 2500 FROM DUAL UNION ALL
SELECT 123, 600, 3500 FROM DUAL UNION ALL
SELECT 123, 700, 500 FROM DUAL UNION ALL
SELECT 123, 700, 1000 FROM DUAL UNION ALL
SELECT 456, 800, 2000 FROM DUAL UNION ALL
SELECT 456, 900, 2000 FROM DUAL UNION ALL
SELECT 456, 900, 4000 FROM DUAL;
I need to write the SQL code where the result would look like this:
Where:
total_amount - the sum of all transactions bank_account made in specific bank_id
number_of_transactions - number of transactions made by bank_account in specific bank_id
total_num_trans - total number of transactions made by bank_account
total_am_trans - total amount of transactions made by bank_account
I've only managed to get some of the results I need, but can't get them all.
This is with what I've started:
SELECT t.bank_account
, t.bank_id
, count(*) number_of_transactions
, sum(t.amount) total_amount
FROM my_table t
GROUP BY t.bank_account
, t.bank_id
ORDER BY t.bank_account
Thanks.
Oracle Setup:
CREATE TABLE my_table ( bank_account, bank_id, amount ) AS
SELECT 123, 600, 1500 FROM DUAL UNION ALL
SELECT 123, 600, 2500 FROM DUAL UNION ALL
SELECT 123, 600, 3500 FROM DUAL UNION ALL
SELECT 123, 700, 500 FROM DUAL UNION ALL
SELECT 123, 700, 1000 FROM DUAL UNION ALL
SELECT 456, 800, 2000 FROM DUAL UNION ALL
SELECT 456, 900, 2000 FROM DUAL UNION ALL
SELECT 456, 950, 4000 FROM DUAL;
Query:
SELECT bank_account,
bank_id,
total_amount,
number_of_transactions,
SUM( number_of_transactions ) OVER ( PARTITION BY bank_account ) AS total_num_trans,
SUM( total_amount ) OVER ( PARTITION BY bank_account ) AS total_am_trans,
number_of_transactions
/ SUM( number_of_transactions ) OVER ( PARTITION BY bank_account )
* 100 AS percentage_trans,
total_amount
/ SUM( total_amount ) OVER ( PARTITION BY bank_account )
* 100 AS percentage_trans
FROM (
SELECT bank_account,
bank_id,
count(*) AS number_of_transactions,
sum(amount) AS total_amount
FROM my_table
GROUP BY bank_account
, bank_id
)
Output:
BANK_ACCOUNT BANK_ID TOTAL_AMOUNT NUMBER_OF_TRANSACTIONS TOTAL_NUM_TRANS TOTAL_AM_TRANS PERCENTAGE_TRANS PERCENTAGE_TRANS
------------ ---------- ------------ ---------------------- --------------- -------------- ---------------- ----------------
123 600 7500 3 5 9000 60 83.3333333
123 700 1500 2 5 9000 40 16.6666667
456 800 2000 1 3 8000 33.3333333 25
456 900 2000 1 3 8000 33.3333333 25
456 950 4000 1 3 8000 33.3333333 50
Try this;)
select t1.*, t2.total_num_trans, t2.total_am_trans, (t1.number_of_transactions / t2.total_num_trans) * 100 as percentage_trans, (t1.total_amount / t2.total_am_trans) * 100 as percentage_amount
from (
select bank_account, bank_id, sum(amount) as total_amount, count(1) as number_of_transactions
from my_table
group by bank_account, bank_id) t1
left join (
select bank_account, sum(total_amount) as total_am_trans, sum(number_of_transactions) as total_num_trans
from (
select bank_account, bank_id, sum(amount) as total_amount, count(1) as number_of_transactions
from my_table
group by bank_account, bank_id ) t
group by bank_account ) t2 on t1.bank_account = t2.bank_account
order by t1.bank_account
Try to join 2 aggregations, the coarse one only groups by bank account, the finer one also by bank id.
SELECT tfine.bank_account
, tfine.bank_id
, tfine.total_amount
, tfine.number_of_transactions
, tcoarse.total_num_trans
, tcoarse.total_am_trans
FROM (
SELECT t1.bank_account
, t1.bank_id
, count(*) number_of_transactions
, sum(t1.amount) total_amount
FROM my_table t1
GROUP BY t1.bank_account
, t1.bank_id
) tfine
JOIN (
SELECT t2.bank_account
, count(*) total_num_trans
, sum(t2.amount) total_am_trans
FROM my_table t2
GROUP BY t2.bank_account
) tcoarse
ON tcoarse.bank_account = tfine.bank_account
ORDER BY tfine.bank_account
, tfine.bank_id
;
Online demo on ideone.

Unite two column tables together within SELECT

How do I unit two tables to a new table that doesn't include a primary key?
For example:
First Table:
Team_Code ID
----------------------------------
433 203994834
436 203994834
436 309228372
435 309228373
434 309228374
433 399064113
Second Table:
number_of_times Team_Code
------------------------------------
3 433
2 434
1 435
1 436
The first lines of the output should look like:
number_of_times Team_Code ID
---------------------------------------------
3 433 203994834
2 434 309228374
1 435 309228373
1 436 203994834
; with
query1 as
(
-- Your Query 1
SELECT * FROM Fireman_Team WHERE Team_Code in (
SELECT Answer.Team_Code FROM Answer WHERE
Answer.Call_Number IN(
SELECT Call_Number FROM (SELECT * FROM Call WHERE Call.Time_Started
BETWEEN ('2016-01-01 00:00:00') AND
('2016-01-31 23:59:59')) AS SSS))
),
query2 as
(
-- Your Query 2
SELECT COUNT(Team_Code) as number_of_times,
Team_Code FROM (SELECT Answer.Team_Code FROM Answer WHERE
Answer.Call_Number IN(
SELECT Call_Number FROM (SELECT * FROM Call WHERE Call.Time_Started
BETWEEN ('2016-01-01 00:00:00') AND
('2016-01-31 23:59:59')) AS SSS)
) AS re GROUP BY Team_Code
)
select *
from query1 q1 inner join query2 q2 on q1.Team_Code = q2.Team_Code
Use CTEs for readability -
WITH CTE1 AS
(
SELECT [Team_Code],[ID] FROM Fireman_Team WHERE Team_Code in (
SELECT Answer.Team_Code FROM Answer WHERE
Answer.Call_Number IN(
SELECT Call_Number FROM (SELECT * FROM Call WHERE Call.Time_Started
BETWEEN ('2016-01-01 00:00:00') AND
('2016-01-31 23:59:59')) AS SSS))
)
;WITH CTE2 AS
(
SELECT COUNT(Team_Code) as number_of_times,
Team_Code FROM (SELECT Answer.Team_Code FROM Answer WHERE
Answer.Call_Number IN(
SELECT Call_Number FROM (SELECT * FROM Call WHERE Call.Time_Started
BETWEEN ('2016-01-01 00:00:00') AND
('2016-01-31 23:59:59')) AS SSS)
) AS re GROUP BY Team_Code
)
SELECT b.[number_of_times], b.[Team_Code], a.[ID]
FROM CTE1 a
INNER JOIN CTE2 b
ON a.[Team_Code] = b.[Team_Code]

single row multiple columns into one column using sql server

I have table like this
OrderNo Item_Description1 Rate1 Quantity1 Item_Description2 Rate2 Quantity2 Item_Description3 Rate3 Quantity3
-------- ------------------ ------ ---------- ------------------ ------ ---------- ------------------ ------ ----------
1001 Laptop 50000 8 Air Conditioner 20000 10 Television 25000 12
1002 Washing Machine 35000 10 Camera 4000 20 Speaker 1500 15
From this I need to create a temp table or table like this:
OrderNo Item_Description Rate Quantity
-------- ------------------ ------ ----------
1001 Laptop 50000 8
Air Conditioner 20000 10
Television 25000 12
1002 Washing Machine 35000 10
Camera 4000 20
Speaker 1500 15
Is there a way I can do this in SQL Server?
You can also use CROSS APPLY to unpivot the data:
select t.order_no,
c.item_description,
c.rate,
c.quantity
from yourtable t
cross apply
(
select item_description1, rate1, quantity1 union all
select item_description2, rate2, quantity2 union all
select item_description3, rate3, quantity3
) c (item_description, rate, quantity)
SELECT * FROM
(select ORDER_NO,ITEM_DESCRIPTION1,RATE1,QUANTITY1FROM TABLE
UNION
select ORDER_NO,ITEM_DESCRIPTION2,RATE2,QUANTITY2 FROM TABLE
UNION
select ORDER_NO,ITEM_DESCRIPTION3,RATE3,QUANTITY3 FROM TABLE)AS A ORDER BY ORDER_NO
Try this
SELECT t.*
FROM Table1
OUTER APPLY
(
VALUES
([OrderNo],item_description1, rate1, quantity1),
(NULL, item_description2, rate2, quantity2),
(NULL, item_description3, rate3, quantity3)
) t([OrdNo],item_description, rate, quantity)
SQL FIDDLE DEMO
Or use #bluefeet answer with NULL
SELECT c.[OrderNo],
c.item_description,
c.rate,
c.quantity
FROM Table1 t
CROSS APPLY
(
SELECT [OrderNo],item_description1, rate1, quantity1 UNION ALL
SELECT NULL, item_description2, rate2, quantity2 UNION ALL
SELECT NULL, item_description3, rate3, quantity3
) c ([OrderNo],item_description, rate, quantity)
SQL FIDDLE DEMO
hope to help you!
select t.* from
(
select order_No, Item_Description1 as Item_Desription, Rate1 as Rate
from Table
union
select order_No, Item_Description2 as Item_Desription, Rate2 as Rate
from Table
union
select order_No, Item_Description3 as Item_Desription, Rate3 as Rate
from Table
) as t
Order by t.order_No asc
this is my test
select t.* from
(select id, apple1 as apple, orange1 as orange
from Test
union all
select id, apple2 as apple, orange2 as orange
from Test
union all
select id, apple3 as apple, orange3 as orange
from Test) as t
order by t.id asc