How to create sql procedure for calculating Total dues - sql

Can anyone help me by showing a create procedure statement for calculating Total Dues from three tables? Here are the tables along with their data ..
Table_1
accountno shipername shiperaddress Executivename
001 john 123, London Paul
002 Robi 127, China Soma
Table_2
Executivename shipername shiperaddress accountno currentamount anotheramount
paul john 123,london 001 10500 12000
soma robi 127,china 002 11000 6800
Table_3
accountno Date ReceivedAmount MoneyReceiptNo
001 1/1/2012 6500 G 256412
002 1/2/2012 5200 D 246521
Here I am to mention that the Total Dues will be calculated as
(currentamount + anotheramount) - receivedamount
I tried to do that by the following stored procedure.
CREATE PROCEDURE [dbo].[rptexetotaldues] #Executivename varchar(20)
AS BEGIN
select
table_1.Executivename,
sum(table_2.currentamount + table_2.anotheramount
- table_3.receivedamount ) as TotalDues
from
table_1
full join
table_2 on table_1.accountno = table_2.accountno
join
table_3 on table_3.accountno = table_1.accountno
where
table_1.Executivename = #Executivename
group by
table_1.Executivename
end
But that doesn't work. Please somebody help me.

Your sample worked for me. The only thing I changed is "Date" to transdate. I strongly recommend avoiding "Date" as a column name. I also changed the aliasing a bit, but that should have been allright. I thinkg #Gordon Linoff is right - you could have an issue with NULLS.
DECLARE #table_1 TABLE (accountno char(5), shipername char(20), shiperaddress char(40), Executivename varchar(20))
INSERT INTO #table_1 VALUES ('001', 'john', '123, London', 'Paul')
INSERT INTO #table_1 VALUES ('002','Robi','127, China','Soma')
DECLARE #table_2 TABLE (Executivename varchar(20), shipername char(20), shiperaddress char(40),
accountno char(20), currentamount decimal(10,2), anotheramount decimal(10,2))
INSERT INTO #table_2 VALUES ('paul', 'john','123,london','001',10500, 12000)
INSERT INTO #table_2 VALUES ('soma', 'robi', '127,china', '002', 11000, 6800)
DECLARE #table_3 TABLE(accountno char(20), tranDate datetime, ReceivedAmount decimal(10,2), MoneyReceiptNo char(10))
INSERT INTO #table_3 VALUES ('001', '1/1/2012', 6500, 'G 256412')
INSERT INTO #table_3 VALUES ('002', '1/2/2012', 5200,'D 246521')
DECLARE #Executivename varchar(20)
--SET #Executivename = 'Paul'
SET #Executivename = 'Soma'
select
tb1.Executivename,
sum(tb2.currentamount + tb2.anotheramount - tb3.receivedamount ) as TotalDues
from
#table_1 tb1
full join #table_2 tb2 on tb1.accountno = tb2.accountno
join #table_3 tb3 on tb3.accountno = tb1.accountno
where
tb1.Executivename=#Executivename group by tb1.Executivename
Here are my results:
Executivename TotalDues
Soma 12600.00

I can think of two problems. First is that the account number is duplicated in either table 1 or table 2. This will add extra rows.
The second is that there are rows in table three that are not in table 2. This means that the addition within the sum is NULL because one of the values is NULL. You can fix this in one of these ways:
sum(table_2.currentamount) + sum(table_2.anotheramount) - sum(table_3.receivedamount)
or
sum(coalesce(table_2.currentamount, 0.0) + coalesce(table_2.anotheramount, 0.0) - coalesce(table_3.receivedamount, 0.0) ) as TotalDues

I think it would be more straightforward as a UNION query, example below:
CREATE PROCEDURE [dbo].[rptexetotaldues] #Executivename varchar(20)
AS BEGIN
SELECT SUB.ACCOUNTNO, SUM(SUB.DUE) AS TOTALDUE FROM
(SELECT ACCOUNTNO
, CURRENTAMOUNT AS DUE
FROM TABLE_2
INNER JOIN TABLE_1 -- WILL ONLY WORK IF ACCOUNTNO IS UNIQUE WITHIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE2.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
UNION ALL
SELECT ACCOUNTNO
, ANOTHERAMOUNT AS DUE
FROM TABLE_2
INNER JOIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE2.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
UNION ALL
SELECT ACCOUNTNO
, -RECEIVEDAMOUNT AS DUE -- NOTE NEGATIVE SIGN
FROM TABLE 3
INNER JOIN TABLE_1
ON TABLE_1.ACCOUNTNO = TABLE3.ACCOUNTNO
WHERE TABLE_1.EXECUTIVENAME = #Executivename
) SUB
GROUP BY SUB.ACC

Related

Getting values from multiple tables in one column

Let's say I have three tables:
table orders:
invoice_ID
customer_ID
202201
1000
202202
2000
202203
3000
202204
4000
table department_north
customer_ID
product
price
4000
VW Rabbit
$5000.00
1000
BMW X5
$15.000
table department_south
customer_ID
product
price
3000
Tesla S
$30.000
2000
BMW X3
$20.000
Wanted Result
A table with invoice_id, a new column with all cars that contain '%BMW%', a new column with the attached price
invoice_ID
product_bmw
price_bmw
202201
BMW X5
$5.000
202202
BMW X3
$20.000
I figured out how to get the results for one department table but can't find a statement for both.
SELECT DISTINCT orders.invoice_ID,
department_north.product AS product_BMW,
department_north.price AS price_BMW
FROM orders
JOIN LEFT department_north
ON department_north.customer_ID = order.customer_id
JOIN LEFT department_south
ON department_south.customer_ID = order.customer_id
WHERE department_north.product LIKE '%BMW%'
I would UNION ALL all departments. See following example:
DECLARE #orders TABLE
(
invoice_ID varchar(20),
customer_ID int
);
INSERT #orders VALUES
(202201, 1000),
(202202, 2000),
(202203, 3000),
(202204, 4000);
DECLARE #department_north TABLE
(
customer_ID int,
product nvarchar(20),
price decimal(15,2)
);
INSERT #department_north VALUES
(4000, 'VW Rabbit', 5000),
(1000, 'BMW X5', 15000);
DECLARE #department_south TABLE
(
customer_ID int,
product nvarchar(20),
price decimal(15,2)
);
INSERT #department_south VALUES
(3000, 'Tesla S', 30000),
(2000, 'BMW X3', 20000);
WITH AllDepartments AS
(
SELECT *
FROM #department_north
UNION ALL
SELECT *
FROM #department_south
)
SELECT invoice_ID, product, price
FROM #orders O
JOIN AllDepartments D ON O.customer_ID=D.customer_ID
WHERE product LIKE '%BMW%';
I would use union all like Paweł Dyl's answer above, but would create a single department table and create an extra column, called location or similar and put an 'S' for south and an 'N' for north into it as per below:
create table #department
(
customer_ID int
, product varchar(64)
, price decimal(15,2)
, "location" varchar(64) -- to allow for other locations
)
;
insert into #department values (4000, 'VW Rabbit', 5000.00, 'N');
insert into #department values (1000, 'BMW X5', 15.000, 'N');
insert into #department values (3000, 'Tesla S', 30.000, 'S');
insert into #department values (2000, 'BMW X3', 20.000, 'S');
This means that you are just using the one department table and you have the additional 'location' column for adding east or west if need be. This will reduce the need to create a new database table for each new location added to your list. You could expand this to include city and/or state or whatever depending on the range of the data but you should aim to use only one table for this purpose.
Creating multiple tables based purely on location would not be recommended and think, what would you do if there were many locations e.g. 50 or more? It would be a nightmare to manage this code by creating a separate table for each location.

I need to migrate data from one old table to a new table by storing appropriate CityId instead CityName

I'm migrating data from one table to another table in SQL Server, In this process what I need to do is "I have 10 columns in old table one column is 'CityName' which is varchar and in the new table, I have a column 'CityId' which is an integer. And I have other table which has data about city id and names. I need store the appropriate cityId in new table instead of CityName. Please help me. Thanks in advance.
You'll need to join the source table to the CityName field in the city information table:
INSERT INTO dbo.Destination (CityID, OtherStuff)
SELECT t1.CityID, t2.OtherStuff
FROM CityInformationTable t1
INNER JOIN SourceTable t2
ON t1.CityName = t2.CityName
Below should give you an idea, you need to inner join to your look up table to achieve this.
declare #t_cities table (Id int, City nvarchar(20))
insert into #t_cities
(Id, City)
values
(1, 'London'),
(2, 'Dublin'),
(3, 'Paris'),
(4, 'Berlin')
declare #t table (City nvarchar(20), SomeColumn nvarchar(10))
insert into #t
values
('London', 'AaaLon'),
('Paris', 'BeePar'),
('Berlin', 'CeeBer'),
('London', 'DeeLon'),
('Dublin', 'EeeDub')
declare #finalTable table (Id int, SomeColumn nvarchar(10))
insert into #finalTable
select c.Id, t.SomeColumn
from #t t
join #t_cities c on c.City = t.City
select * from #finalTable
Output:
Id SomeColumn
1 AaaLon
3 BeePar
4 CeeBer
1 DeeLon
2 EeeDub

Match the codes and copy columns

I am working in SQL Server 2008. I have 2 tables Table1 & Table2.
Table1 has columns
SchoolCode, District, Type, SchoolName
and Table2 has columns
SchoolCode1, District1, Type1, SchoolName1
SchoolCode columns in both tables have the same codes like "1234"; code is the same in both schoolcode columns.
Now I want to copy the District, Type and SchoolName column values from Table1 to Table2 if SchoolCode in both tables is same.
I think the query will use join but I don't know how it works. Any help on how I can do this task?
Maybe use an update statement in join if by copying over you mean updating rows
update t2
set
District1= District,
Type1= Type,
SchoolName1= SchoolName
from Table1 t1
join
Table2 t2
on t1.SchoolCode=t2.SchoolCode1
I could give you a little bit of idea. here is it:
Insert into table2 (District1, Type1, SchoolName1)
SELECT District, Type, SchoolName
FROM table1
where table1.Schoolcode=table2.Schoolcode1
You have to use Inner join to update data from table 1 to table 2, Inner join will join values that are equal. . To learn more about joins, I highly recommend you to read the below article
SQLServer Joins Explained - W3Schools
Please refer the below code, for the convenience I have used the temporary tables..
DECLARE #Table1 TABLE
(
SchoolCode INT,
District VARCHAR(MAX),
Type VARCHAR(MAX),
SchoolName VARCHAR(MAX)
)
DECLARE #Table2 TABLE
(
SchoolCode1 INT,
District1 VARCHAR(MAX),
Type1 VARCHAR(MAX),
SchoolName1 VARCHAR(MAX)
)
INSERT INTO #Table1
( SchoolCode ,District , Type , SchoolName
)
VALUES ( 1 ,'DIS1' ,'X' ,'A'),
( 2 ,'DIS2' ,'Y' ,'B'),
( 3 ,'DIS3' ,'Z' ,'C'),
( 4 ,'DIS4' ,'D' ,'D'),
( 5 ,'DIS5' ,'K' ,'E')
INSERT INTO #Table2
( SchoolCode1 ,District1 , Type1 , SchoolName1
)
VALUES ( 1 ,'DIS1' ,'X' ,'A'),
( 2 ,NULL ,'Z' ,NULL),
( 3 ,'DIS3' ,'Z' ,'C'),
( 4 ,NULL ,'Z' ,'S'),
( 5 ,'DIS5' ,'K' ,'E')
--BEFORE
SELECT * FROM #Table1
SELECT * FROM #Table2
--Logic UPDATE Table 2
UPDATE t2 SET t2.District1 = t1.District,
t2.Type1 = t1.Type,
t2.SchoolName1 = t1.SchoolName
FROM #Table1 t1
INNER JOIN #Table2 t2 ON t1.SchoolCode = t2.SchoolCode1
-- End Logic UPDATE Table 2
--AFTER
SELECT * FROM #Table1
SELECT * FROM #Table2
You can join tables in an UPDATE statement.
Note, I have aliased the tables, table1 and table2 as t1 and t2 respectively.
This is what I did:
create table Table1
(SchoolCode varchar(50),
District varchar(50),[Type] varchar(50),SchoolName varchar(50))
go
create table Table2
(SchoolCode1 varchar(50), District1 varchar(50),[Type1] varchar(50),SchoolName1 varchar(50))
go
insert into table1 values ('1234','District1','High','Cool School')
insert into table1 values ('2222','District2','Lower','Leafy School')
insert into table2 (SchoolCode1) values ('1234')
go
update t2
set District1 = District,
Type1 = [Type],
SchoolName1 = SchoolName
from table1 t1
join table2 t2
on t2.SchoolCode1 = t1.SchoolCode
go
select * from table2
go

SQL Query Profit and Loss

I have two tables in SQL Server: TblGroup and TblAmount
TblGroup
Grp_Id Grp_Name GrpType
------ -------------- -----------
1 Direct Incomes Income
2 Indirect Incomes Income
3 Misc. Expences Expence
4 Other Incomes Income
5 Purchases Expence
6 Selling Expences Expence
7 Sales Income
TblAmount
Grp_Id Amount
------ -------
1 2000
2 1500
3 3000
4 5000
5 4000
6 1000
7 4500
This is the output that I need:
Income Amount Expence Amount
------------- ----- ------------- ----------
Direct Incomes 2000 Misc. Expences 3000
Indirect Incomes 1500 Purchases 4000
Other Incomes 5000 Selling Expences 1000
Sales 4500
This is my query, but not getting the right result:
declare #TblGroup as table (Grp_Id int, Grp_Name varchar(50), GrpType varchar(20))
insert into #TblGroup values
(1,'Direct Incomes','Income')
,(2,'Indirect Incomes','Income')
,(3,'Misc. Expences','Expence')
,(4,'Other Incomes','Income')
,(5,'Purchases','Expence')
,(6,'Selling Expences','Expence')
,(7,'Sales','Income')
declare #TblAmount as table(Grp_Id int,Amount int)
insert into #TblAmount values
(1,2000)
,(2,1500)
,(3,3000)
,(4,5000)
,(5,4000)
,(6,1000)
,(7,4500)
select * from (
SELECT Grp_Name AS Income, Amount AS Amount
FROM #TblGroup g
LEFT JOIN #TblAmount a ON g.Grp_Id = a.Grp_Id
WHERE GrpType = 'Income') as Income
JOIN (
SELECT Grp_Name AS Expence, Amount AS Amount
FROM #TblGroup g
LEFT JOIN #TblAmount a ON g.Grp_Id = a.Grp_Id
WHERE GrpType = 'Expence') as Expence on Income.Income<>Expence.Expence
Where duplicate Income and Expense is coming in an output, How could I overcome this Issue.
This is a fairly simple Left Join question, here's half of the solution
SELECT GrpType AS Income, TblAmount.Amount AS Amount
FROM TblGroup
LEFT JOIN TblAmount
ON TblGroup.Grp_Id = TblAmount.Grp_Id
WHERE GrpType = "Income"
You should be able to guess how to get the other result.
CREATE TABLE TblGroup ( Grp_Id int, Grp_Name varchar(200),
GrpType varchar(200));
INSERT INTO TblGroup
VALUES(1,
'Direct Incomes',
'Income');
INSERT INTO TblGroup
VALUES(2,
'Indirect Incomes',
'Income');
INSERT INTO TblGroup
VALUES(3,
'Misc. Expences',
'Expence');
INSERT INTO TblGroup
VALUES(4,
'Other Incomes',
'Income');
INSERT INTO TblGroup
VALUES(5,
'Purchases',
'Expence');
INSERT INTO TblGroup
VALUES(6,
'Selling Expences',
'Expence');
INSERT INTO TblGroup
VALUES(7,
'Sales',
'Income');
CREATE TABLE TblAmount ( Grp_Id int, amount int);
INSERT INTO TblAmount
VALUES(1,
2000);
INSERT INTO TblAmount
VALUES(2,
1500);
INSERT INTO TblAmount
VALUES(3,
3000);
INSERT INTO TblAmount
VALUES(4,
5000);
INSERT INTO TblAmount
VALUES(5,
4000);
INSERT INTO TblAmount
VALUES(6,
1000);
INSERT INTO TblAmount
VALUES(7,
4500);
SELECT DISTINCT Income,
c.amount,
Expence,
d.amount from
(SELECT a.Grp_Id, CASE
WHEN GrpType='Income' THEN Grp_Name
END AS Income, b.amount
FROM TblGroup a
INNER JOIN TblAmount b ON a.Grp_Id=b.Grp_Id)c
LEFT OUTER JOIN
(SELECT a.Grp_Id,
CASE
WHEN GrpType='Expence' THEN Grp_Name
END AS Expence,
amount
FROM TblGroup a
INNER JOIN TblAmount b ON a.Grp_Id=b.Grp_Id)d ON c.Grp_Id=d.Grp_Id;
SELECT TG.Grp_Name AS Income, TA.Amount
FROM TblGroup TG, TblAmount TA
WHERE TA.Grp_Id = TG.Grp_Id
AND TG.GrpType = 'Income';
SELECT TG.Grp_Name AS Expence, TA.Amount
FROM TblGroup TG, TblAmount TA
WHERE TA.Grp_Id = TG.Grp_Id
AND TG.GrpType = 'Expence';
First query will give you the details for grpType income and the second gives the details for grpType expense.
A simple statement in the where clause can give you the output. You can also try it with SQL joins. But I prefer to go easy.
At last I got the Answer, Here is the solution.
declare #TblGroup as table (Grp_Id int, Grp_Name varchar(50), GrpType varchar(20))
insert into #TblGroup values
(1,'Direct Incomes','Income')
,(2,'Indirect Incomes','Income')
,(3,'Misc. Expences','Expence')
,(4,'Other Incomes','Income')
,(5,'Purchases','Expence')
,(6,'Selling Expences','Expence')
,(7,'Sales','Income')
declare #TblAmount as table(Grp_Id int,Amount int)
insert into #TblAmount values
(1,2000)
,(2,1500)
,(3,3000)
,(4,5000)
,(5,4000)
,(6,1000)
,(7,4500)
SELECT Row_Number() OVER (ORDER BY (SELECT 1)) as SNo, TG.Grp_Name AS Income, TA.Amount into #Incme
FROM #TblGroup TG, #TblAmount TA
WHERE TA.Grp_Id = TG.Grp_Id
AND TG.GrpType = 'Income';
SELECT Row_Number() OVER (ORDER BY (SELECT 1)) as SNo , TG.Grp_Name AS Expence, TA.Amount into #Expnse
FROM #TblGroup TG, #TblAmount TA
WHERE TA.Grp_Id = TG.Grp_Id
AND TG.GrpType = 'Expence';
DECLARE #TblMain as table(Income varchar(50), Amount int, Expense varchar(50), Amount2 int)
DECLARE #row INT = 1
,#ROWCOUNT int
,#RowCount_Incme INT = (select COUNT(*) from #Incme)
,#RowCount_Expnse INT = (select COUNT(*) from #Expnse)
set #ROWCOUNT = case when #RowCount_Incme > #RowCount_Expnse then #RowCount_Incme else #RowCount_Expnse end
WHILE (#ROW <= #ROWCOUNT)
BEGIN
insert into #TblMain(Income, Amount,Expense,Amount2) (
select Income, Amount
,(select Expence from #Expnse where SNo=#row)
,(select Amount from #Expnse where SNo=#row)
from #Incme where SNo=#row
)
SET #ROW = #ROW+1
END
select * from #TblMain
drop table #Incme
drop table #Expnse

Subquery: how to retrieve the last non-zero value from a column?

Considering a table customerBalance with 3 columns: name, date and balance. Suppose a set of records like:
cus_name cus_date cus_balance
John 06/14/2011 1000
John 06/15/2011 500
John 06/16/2011 0
Mary 06/14/2011 3000
Mary 06/15/2011 2800
Mary 06/16/2011 0
How to create a SQL query which returns, for the date 6/16/2011 instead 0, the last non-zero value based on date (in sample, $500 for John and $2800 for Mary)?
I'm trying to do it using a subquery which uses Max function to retrieve the last date with non-zero value, but I didn't succeed. This example is quite "nonsensical", but I really need to do an operation like this in my dataset. Thanks!
Note: If you can specify the DB and version this query can be improved.
Try this:
SELECT *
FROM customers
WHERE (cus_name, cus_date)
IN
(
SELECT cus_name, MAX(cus_date)
FROM customers
WHERE cus_balance <> 0
GROUP BY cus_name
)
Update: Alternate version:
SELECT a.*
FROM customers a,
(
SELECT cus_name, MAX(cus_date)
FROM customers
WHERE cus_balance <> 0
GROUP BY cus_name
) b
WHERE a.cus_name = b.cus_name
AND a.cus_date = b.cus_date
Here it goes:
CREATE Table #temp
(
Cus_Name VARCHAR(200) NULL,
Cus_Date Char(8) NULL,
Cus_Balance INT NULL
)
INSERT INTO #temp VALUES ('John' , '20110614' ,1000 )
INSERT INTO #temp VALUES ('John' , '20110615' , 500 )
INSERT INTO #temp VALUES ('John' , '20110616' , 0 )
INSERT INTO #temp VALUES ('Mary' , '20110614' ,3000 )
INSERT INTO #temp VALUES ('Mary' , '20110615' ,2800 )
INSERT INTO #temp VALUES ('Mary' , '20110616' , 0 )
SELECT
T.Cus_Name ,
MIN(t.Cus_Balance)
FROM #temp t
WHERE t.Cus_Balance <>0
GROUP BY t.Cus_Name
DROP TABLE #temp