Get not selected word in column - sql-server

I have this table structure and data and query that is giving me the child records. This is giving me required data as I wanted now there is another requirements that popped up with time that I want to show the name of the COA which is not selected here i.e Medical
CREATE TABLE TransactionMaster
(
ID Int,
TransactionCode VARCHAR(25),
PRIMARY KEY (ID)
)
INSERT INTO TransactionMaster VALUES (1, 'TRA-001');
INSERT INTO TransactionMaster VALUES (2, 'TRA-002');
INSERT INTO TransactionMaster VALUES (3, 'TRA-003');
CREATE TABLE TransactionDetail
(
ID Int,
MasterID Int,
COATitle VARCHAR(25),
CrAmount NUMERIC(18,2),
DrAmount NUMERIC(18,2),
PRIMARY KEY (ID),
FOREIGN KEY (MasterID) REFERENCES TransactionMaster(ID)
)
INSERT INTO TransactionDetail VALUES (1, 1, 'Medical', '2500', NULL)
INSERT INTO TransactionDetail VALUES (2, 1, 'Travelling', NULL, '2500')
INSERT INTO TransactionDetail VALUES (3, 1, 'Medicine', NULL, '2500')
INSERT INTO TransactionDetail VALUES (4, 1, 'Doc Fee', NULL, '2500')
INSERT INTO TransactionDetail VALUES (5, 2, 'Incentive', '3000', NULL)
INSERT INTO TransactionDetail VALUES (6, 2, 'Extra', NULL, '2500')
INSERT INTO TransactionDetail VALUES (7, 2, 'Bonus', NULL, '500')
INSERT INTO TransactionDetail VALUES (8, 3, 'Medical', NULL, '3000')
INSERT INTO TransactionDetail VALUES (9, 3, 'Tests', '2500', NULL)
INSERT INTO TransactionDetail VALUES (10, 3, 'Juice', '500', NULL)
Sample Query:
SELECT
m.TransactionCode,
d.COATitle,
d.CrAmount,
d.DrAmount
FROM TransactionDetail d
JOIN TransactionMaster m ON d.MasterID=m.ID
WHERE d.MasterID IN(
SELECT MasterID
FROM TransactionDetail
WHERE COATitle='Medical'
)
AND d.COATitle<>'Medical'
Output giving:
TransactionCode COATitle CrAmount DrAmount
------------------------- ------------------------- --------------------------------------- ---------------------------------------
TRA-001 Travelling NULL 2500.00
TRA-001 Medicine NULL 2500.00
TRA-001 Doc Fee NULL 2500.00
TRA-003 Tests 2500.00 NULL
TRA-003 Juice 500.00 NULL
I want to include another column that'll show Medicalin it.
Expected Output:
TransactionCode COATitle CrAmount DrAmount COA
------------------------- ------------------------- --------------------------------------- ----------------------------- ------------------------
TRA-001 Travelling NULL 2500.00 Medical
TRA-001 Medicine NULL 2500.00 Medical
TRA-001 Doc Fee NULL 2500.00 Medical
TRA-003 Tests 2500.00 NULL Medical
TRA-003 Juice 500.00 NULL Medical

DECLARE #prm nvarchar(100)
SET #prm = 'Medical'
SELECT
m.TransactionCode,
d.COATitle,
d.CrAmount,
d.DrAmount,
#prm as COA
FROM TransactionDetail d
JOIN TransactionMaster m ON d.MasterID=m.ID
WHERE d.MasterID IN(
SELECT MasterID
FROM TransactionDetail
WHERE COATitle=#prm
)
AND d.COATitle<>#prm

Related

how to display which product related price is increasing year by year

I have one doubt in SQL server. How to get which productname have price increaseing year by year.
in the below table apple product price is increase year by year so I need that records
if any product one year is high and another year price is drop then no need to get that records
if any product one year price is 10 and next year price must be increast compare to prviouse then that record need to display
CREATE TABLE [dbo].[product](
[pid] [int] NULL,
[price] [money] NULL,
[year] [int] NULL
);
CREATE TABLE [dbo].[productdetails](
[pid] [int] NULL,
[pname] [varchar](50) NULL
);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (1, 10.0000, 2010);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (1, 9.0000, 2011);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (1, 13.0000, 2012);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (2, 30.0000, 2010);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (2, 20.0000, 2011);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (2, 19.0000, 2012);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (3, 8.0000, 2010);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (3, 10.0000, 2011);
INSERT [dbo].[product] ([pid], [price], [year]) VALUES (3, 15.0000, 2012);
INSERT [dbo].[productdetails] ([pid], [pname]) VALUES (1, N'lg');
INSERT [dbo].[productdetails] ([pid], [pname]) VALUES (2, N'samsung');
INSERT [dbo].[productdetails] ([pid], [pname]) VALUES (3, N'apple');
INSERT [dbo].[productdetails] ([pid], [pname]) VALUES (4, N'mi');
Based on the above data I want output like below
+--------------+
| Productname |
+--------------+
| Apple |
+--------------+
I tried like below
SELECT *
FROM product p
JOIN product pd
ON p.pid = pd.pid
AND p.year = pd.year + 1
AND p.price >= pd.price
Can you please tell me how to write query to achieve this task in SQL server
Using LAG() and HAVING with COUNT = SUM, you can get the expected result.
The query is dynamic, no need to hard-code year or the count of occurrences.
SELECT Q.pname AS ProductName
FROM (
SELECT PD.PID, PD.pname,
CASE WHEN COALESCE(
LAG(PR.price) OVER (PARTITION BY PD.PID ORDER BY PR.[year])
, PR.price) <= PR.price THEN 1 ELSE 0 END AS PFlag
FROM product PR
JOIN productdetails PD ON PD.pid = PR.pid
) Q
GROUP BY Q.pname
HAVING COUNT(Q.pname) = SUM(Q.PFlag)
OUTPUT:
+--------------+
| Productname |
+--------------+
| apple |
+--------------+
db<> fiddle for the same
With NOT EXISTS:
select distinct pd.pname [Product Name]
from [dbo].[productdetails] pd inner join [dbo].[product] p
on p.pid = pd.pid
where not exists (
select 1 from product t
where t.pid = pd.pid and
t.price <= (select price from product where pid = t.pid and year = t.year - 1)
)
See the demo.
Results:
> | Product Name |
> | :------------ |
> | apple |
If there are not prices for every year but you want to apply the condition to the previous stored year, then use this:
select distinct pd.pname [Product Name]
from [dbo].[productdetails] pd inner join [dbo].[product] p
on p.pid = pd.pid
where not exists (
select 1 from product t
where t.pid = pd.pid and
t.price <= (select max(price) from product where pid = t.pid and year < t.year)
)
See the demo.
If data always there for fixed year 2010,2011&2012 - this following script will work-
SELECT
PID
FROM [dbo].[product]
GROUP BY PID
HAVING
SUM(CASE WHEN [YEAR] = '2011' THEN PRICE ELSE NULL END)>
SUM(CASE WHEN [YEAR] = '2010' THEN PRICE ELSE NULL END)
AND
SUM(CASE WHEN [YEAR]= '2012' THEN PRICE ELSE NULL END)>
SUM(CASE WHEN [YEAR] = '2011' THEN PRICE ELSE NULL END)
You can use this query...
This works even if you have more 3 records of data per product.
SELECT Max(productdetails.pname) as ProductName
FROM (SELECT *,
Lag(price, 1) OVER (partition BY pid ORDER BY pid, year ) AS LagPrice,
price AS CurrentPrice,
Lead (price, 1) OVER (partition BY pid ORDER BY pid, year) AS LeadPrice
FROM product) t1
INNER JOIN productdetails ON productdetails.pid = t1.pid
WHERE lagprice IS NOT NULL AND leadprice IS NOT NULL
GROUP BY t1.pid
HAVING Max(CASE WHEN leadprice < currentprice OR lagprice > currentprice THEN 1 ELSE 0 END) < 1
Or use this query (Similar to Arulkumar's query).
SELECT Max(productdetails.pname) AS ProductName
FROM (SELECT pid,
CASE WHEN Lead(price) OVER (partition BY pid ORDER BY pid, year) >= price THEN 0 ELSE 1
END AS Decreased
FROM product) tmp
INNER JOIN productdetails ON productdetails.pid = tmp.pid
GROUP BY tmp.pid
HAVING Sum(tmp.Decreased) <= 1
Tables schema and sample data (Added more sample data)
CREATE TABLE [product](
[pid] [int] NULL,
[price] [money] NULL,
[year] [int] NULL
);
CREATE TABLE [productdetails](
[pid] [int] NULL,
[pname] [varchar](50) NULL
);
INSERT [product] ([pid], [price], [year]) VALUES (1, 10.0000, 2010);
INSERT [product] ([pid], [price], [year]) VALUES (1, 9.0000, 2011);
INSERT [product] ([pid], [price], [year]) VALUES (1, 13.0000, 2012);
INSERT [product] ([pid], [price], [year]) VALUES (2, 30.0000, 2010);
INSERT [product] ([pid], [price], [year]) VALUES (2, 20.0000, 2011);
INSERT [product] ([pid], [price], [year]) VALUES (2, 19.0000, 2012);
INSERT [product] ([pid], [price], [year]) VALUES (3, 8.0000, 2010);
INSERT [product] ([pid], [price], [year]) VALUES (3, 10.0000, 2011);
INSERT [product] ([pid], [price], [year]) VALUES (3, 15.0000, 2012);
INSERT [product] ([pid], [price], [year]) VALUES (3, 20.0000, 2013);
INSERT [product] ([pid], [price], [year]) VALUES (3, 15.0000, 2014);
INSERT [product] ([pid], [price], [year]) VALUES (4, 5.0000, 2010);
INSERT [product] ([pid], [price], [year]) VALUES (4, 10.0000, 2011);
INSERT [product] ([pid], [price], [year]) VALUES (4, 15.0000, 2012);
INSERT [product] ([pid], [price], [year]) VALUES (4, 20.0000, 2013);
INSERT [productdetails] ([pid], [pname]) VALUES (1, N'lg');
INSERT [productdetails] ([pid], [pname]) VALUES (2, N'samsung');
INSERT [productdetails] ([pid], [pname]) VALUES (3, N'apple');
INSERT [productdetails] ([pid], [pname]) VALUES (4, N'mi');
All Data
+------+----------+------+
| pid | price | year |
+------+----------+------+
| 1 | 10.0000 | 2010 |
| 1 | 9.0000 | 2011 |
| 1 | 13.0000 | 2012 |
| 2 | 30.0000 | 2010 |
| 2 | 20.0000 | 2011 |
| 2 | 19.0000 | 2012 |
| 3 | 8.0000 | 2010 |
| 3 | 10.0000 | 2011 |
| 3 | 15.0000 | 2012 |
| 3 | 20.0000 | 2013 |
| 3 | 15.0000 | 2014 |
| 4 | 5.0000 | 2010 |
| 4 | 10.0000 | 2011 |
| 4 | 15.0000 | 2012 |
| 4 | 20.0000 | 2013 |
+------+----------+------+
Query Result
+-------------+
| ProductName |
+-------------+
| mi |
+-------------+
Online Demo: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=c55c02790f1a6f99bb8d560ab8d3149b
Reference
- Arulkumar's query: https://stackoverflow.com/revisions/55984816/2
If I understood it correctly. You could take advantage of COUNT(), LAG(), and SUM(), and just divide your logic into :
Get the current and previous year's price
Count the total number of product's records (how many years are there for each product).
Compare the current year price with the last year price, and if the price for the current year is larger than last year then it's incremental (we give it 1) else (it's decreased) we give it 0.
Get the sum of the comparison, if it's equal to the total number of products (the count on #2) then this means the product has never decreased the price.
Example :
SELECT
pname
FROM (
SELECT
p.pid
, p.price
, p.year
, LAG(p.price) OVER(PARTITION BY p.pid ORDER BY p.year) prvPrice
, COUNT(*) OVER(PARTITION BY p.pid) totalPid
, pd.pname
FROM product p
JOIN productdetails pd ON pd.pid = p.pid
) D
GROUP BY
pname
, totalPid
HAVING
SUM(CASE WHEN price > ISNULL(prvPrice,0) THEN 1 ELSE 0 END) = totalPid
So, apple appeared 3 times in product table (totalPid), this means we need the price to increment 3 times (once a year) to fulfill your requirement.
You can correct the conditional logic to fit your need, but I just want to share this simple example for the sake of simplicity.
Another way is
(uncomment the p1 and p0 to see the details)
SELECT Distinct
pd.pname as Product
--,p0.*
--,p1.*
FROM gbaluproduct p0
JOIN gbaluproduct p1
ON p0.pid = p1.pid
AND p0.year + 1 = p1.year
AND p0.price < p1.price
Left Join gbaluproductdetails pd
ON p0.pid = pd.pid
Results--
Product
apple
lg

Filter Table Before Applying Right Join ON 3RD TABLE

Using MSSQL: Just for clarification
Customer Table
CustomerNumber Name
===================
1 David
2 Thomas
3 Mangold
4 Issac
------------------------------------------------------------
CustomerAddress Table
CustomerNumber State EffectiveDate
==================================
1 AL 01/01/2017
1 VA 06/01/2017
1 GA 02/01/2018
1 FL 10/01/2018
2 TX 01/01/2017
3 MA
4 IL 04/01/2015
SalesOrder Table
CUSTOMER ORDERNo OrderDate
========================
1 1000 03/01/2017
2 1001 10/10/2017
1 1002 11/01/2017
3 1003 12/01/2017
4 1004 01/01/2018
1 1005 02/01/2018
1 1006 01/01/2019
I need to fetch all the orders with the customer detail and the customer address on the order date.
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.NAME, T3.STATE
FROM SALESORDER T1, CUSTOMER T2, CUSTOMERADDRESS T3
RIGHT JOIN(
SELECT CUSTOMER, MAX(EFFECTIVEDATE) FROM CUSTOMERADDRESS
--WHERE EFFECTIVEDATE <= T1.ORDERDATE
GROUP BY CUSTOMER)T4
ON T3.CUSTOMER = T4.CUSTOMER AND T3.EFFECTIVEDATE=T4.EFFECTIVEDATE
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
AND T1.CUSTOMER = T3.CUSTOMERNUMBER
Want to see how to do compare in the join where i compare first table to the 3rd table in the join. see the commented code --WHERE EFFECTIVEDATE <= T1.ORDERDATE
If I remove the commented code, the table in the join cannot reference a table outside.
The expected output is:
CUSTOMER ORDERNo OrderDate CustomerName State
=============================================
1 1000 03/01/2017 David AL
2 1001 10/10/2017 Thomas TX
1 1002 11/01/2017 David VA
3 1003 12/01/2017 Mangold MA
4 1004 01/01/2018 Issac IL
1 1005 02/01/2018 David GA
1 1006 01/01/2019 David FL
The tables in sql fiddle http://sqlfiddle.com/#!18/9eecb:
CREATE TABLE Customer
('CustomerNumber' int, 'CustomerName' varchar(30))
;
INSERT INTO Customer
('CustomerNumber', 'CustomerName')
VALUES
(1, 'David'),
(2, 'Thomas'),
(3, 'Mangold'),
(4, 'Issac')
;
CREATE TABLE CustomerAddress
('CustomerNumber' int, 'State' varchar(2), 'EffectiveDate' date)
;
INSERT INTO CustomerAddress
('CustomerNumber', 'State', 'EffectiveDate')
VALUES
(1, 'AL', 01/01/2017),
(1, 'VA', 06/01/2017),
(1, 'GA', 02/01/2018),
(1, 'FL', 10/01/2018),
(2, 'TX', 01/01/2017),
(3, 'MA',),
(4, 'IL', 04/01/2015)
;
CREATE TABLE SalesOrder
('CUSTOMER' int, 'ORDERNO' int, 'OrderDate' Date)
;
INSERT INTO SalesOrder
('CUSTOMER', 'ORDERNO', 'OrderDate')
VALUES
(1, 1000, 03/01/2017),
(2, 1001, 10/10/2017),
(1, 1002, 11/01/2017),
(3, 1003, 12/01/2017),
(4, 1004, 01/01/2018),
(1, 1005, 02/01/2018),
(1, 1006, 01/01/2019)
;
CREATE TABLE CustomerAddress
(`CustomerNumber` int, 'State' varchar(2), `EffectiveDate` date)
;
INSERT INTO CustomerAddress
(`CustomerNumber`, `State`, 'EffectiveDate')
VALUES
(1, 'AL', 01/01/2017),
(1, 'VA', 06/01/2017),
(1, 'GA', 02/01/2018),
(1, 'FL', 10/01/2018),
(2, 'TX', 01/01/2017),
(3, 'MA',),
(4, 'IL', 04/01/2015)
;
CREATE TABLE SalesOrder
(`CUSTOMER` int, 'ORDERNO' int, `OrderDate` Date)
;
INSERT INTO SalesOrder
(`CUSTOMER `, `ORDERNO`, 'OrderDate')
VALUES
(1, 1000, 03/01/2017),
(2, 1001, 10/10/2017),
(1, 1002, 11/01/2017),
(3, 1003, 12/01/2017),
(4, 1004, 01/01/2018),
(1, 1005, 02/01/2018),
(1, 1006, 01/01/2019)
;
'sql server version'
CREATE TABLE Customer
(CustomerNumber int, CustomerName varchar(30))
;
INSERT INTO Customer
(CustomerNumber, CustomerName)
VALUES
(1, 'David'),
(2, 'Thomas'),
(3, 'Mangold'),
(4, 'Issac');
;
CREATE TABLE CustomerAddress
(CustomerNumber int, State varchar(2), EffectiveDate date)
;
INSERT INTO CustomerAddress
(CustomerNumber, State, EffectiveDate)
VALUES
(1, 'AL', '01/01/2017'),
(1, 'VA', '06/01/2017'),
(1, 'GA', '02/01/2018'),
(1, 'FL', '10/01/2018'),
(2, 'TX', '01/01/2017'),
(4, 'IL', '04/01/2015')
;
INSERT INTO CustomerAddress
(CustomerNumber, State)
VALUES
(3, 'MA' )
;
CREATE TABLE SalesOrder
(CUSTOMER int, ORDERNO int, OrderDate Date)
;
INSERT INTO SalesOrder
(CUSTOMER, ORDERNO, OrderDate)
VALUES
(1, 1000, '03/01/2017'),
(2, 1001, '10/10/2017'),
(1, 1002, '11/01/2017'),
(3, 1003, '12/01/2017'),
(4, 1004, '01/01/2018'),
(1, 1005, '02/01/2018'),
(1, 1006, '01/01/2019')
;
The problem: Need to Pick all the Sales Orders and their customer Name, and the Customer Address. The important and tricky part is the customer address changes based on the date of the sales order.
--MODIFIED VERSION OF THE INCOMPLETE QUERY
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.CustomerName, T3.STATE
FROM CUSTOMER T2, SALESORDER T1 INNER JOIN CUSTOMERADDRESS T3 ON T1.CUSTOMER = T3.CUSTOMERNUMBER
RIGHT JOIN(
SELECT CustomerNumber, MAX(EFFECTIVEDATE) as EffectiveDate4 FROM CUSTOMERADDRESS
--WHERE EFFECTIVEDATE < T1.ORDERDATE
GROUP BY CustomerNumber
--HAVING EFFECTIVEDATE < T1.ORDERDATE
) T4
ON T3.CustomerNumber = T4.CustomerNumber AND T3.EFFECTIVEDATE=T4.EffectiveDate4
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
OUTER APPLY should solve your problem. based on your needs you can change your query.
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.NAME, T3.STATE
FROM SALESORDER T1, CUSTOMER T2, CUSTOMERADDRESS T3
OUTER APPLY(
SELECT CUSTOMER, MAX(EFFECTIVEDATE) FROM CUSTOMERADDRESS
WHERE EFFECTIVEDATE <= T1.ORDERDATE
AND T3.CUSTOMER = CUSTOMER )T4
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
AND T1.CUSTOMER = T3.CUSTOMERNUMBER
AND T3.EFFECTIVEDATE = T4.EFFECTIVEDATE

Get child accounts

I have this table structure and some sample data as well. The logic here is that against any COATitle I enter child records that are the expenditures against that specific head account. In my sample data as Medical have multiple child records and same as Incentive.
My problem is that when I select specific head account like if I select Medical it should show its child records in this case they should not include records with MasterID 2 as they are of Incentive
CREATE TABLE TransactionMaster
(
ID Int,
TransactionCode VARCHAR(25),
PRIMARY KEY (ID)
)
INSERT INTO TransactionMaster VALUES (1, 'TRA-001');
INSERT INTO TransactionMaster VALUES (2, 'TRA-002');
INSERT INTO TransactionMaster VALUES (3, 'TRA-003');
CREATE TABLE TransactionDetail
(
ID Int,
MasterID Int,
COATitle VARCHAR(25),
CrAmount NUMERIC(18,2),
DrAmount NUMERIC(18,2),
PRIMARY KEY (ID),
FOREIGN KEY (MasterID) REFERENCES TransactionMaster(ID)
)
INSERT INTO TransactionDetail VALUES (1, 1, 'Medical', '2500', NULL)
INSERT INTO TransactionDetail VALUES (2, 1, 'Travelling', NULL, '2500')
INSERT INTO TransactionDetail VALUES (3, 1, 'Medicine', NULL, '2500')
INSERT INTO TransactionDetail VALUES (4, 1, 'Doc Fee', NULL, '2500')
INSERT INTO TransactionDetail VALUES (5, 2, 'Incentive', '3000', NULL)
INSERT INTO TransactionDetail VALUES (6, 2, 'Extra', NULL, '2500')
INSERT INTO TransactionDetail VALUES (7, 2, 'Bonus', NULL, '500')
INSERT INTO TransactionDetail VALUES (8, 3, 'Medical', NULL, '3000')
INSERT INTO TransactionDetail VALUES (9, 3, 'Tests', '2500', NULL)
INSERT INTO TransactionDetail VALUES (10, 3, 'Juice', '500', NULL)
Query Sample:
SELECT [Voucher].[TransactionCode], [Detail].[COATitle], [Detail].[CrAmount], [Detail].[DrAmount]
FROM [TransactionMaster] [Voucher], [TransactionDetail] [Detail]
WHERE [Voucher].[ID] = [Detail].[MasterID] AND COATitle NOT IN ('Medical')
OutPut:
TransactionCode COATitle CrAmount DrAmount
------------------------- ------------------------- --------------------------------------- ---------------------------------------
TRA-001 Travelling NULL 2500.00
TRA-001 Medicine NULL 2500.00
TRA-001 Doc Fee NULL 2500.00
TRA-002 Incentive 3000.00 NULL
TRA-002 Extra NULL 2500.00
TRA-002 Bonus NULL 500.00
TRA-003 Tests 2500.00 NULL
TRA-003 Juice 500.00 NULL
The desired output shouldn't include rows with TransactionCode with 'TRA-002'.
Try the following query
SELECT
m.TransactionCode,
d.COATitle,
d.CrAmount,
d.DrAmount
FROM TransactionDetail d
JOIN TransactionMaster m ON d.MasterID=m.ID
WHERE d.MasterID IN(
SELECT MasterID
FROM TransactionDetail
WHERE COATitle='Medical'
)
AND d.COATitle<>'Medical'

Opening and Closing Balance is wrt Debit and Credit amount

I have this table structure and query written with the help of some guy here and it works perfect. I want to get the opening and closing balance between the dates. I have commented the date on which I want to get the date and if I run that date check the expected output I want is shown below.
Here is the structure and sample data:
DROP TABLE [TransactionMaster];
DROP TABLE [VoucherType];
CREATE TABLE [VoucherType](
[VoucherTypeCode] [tinyint] NOT NULL PRIMARY KEY,
[FullName] [nvarchar](255) NOT NULL
);
INSERT INTO [VoucherType] VALUES (1, 'Cash Payment Voucher');
INSERT INTO [VoucherType] VALUES (2, 'Cash Receipt Voucher');
INSERT INTO [VoucherType] VALUES (3, 'Bank Payment Voucher');
INSERT INTO [VoucherType] VALUES (4, 'Bank Receipt Voucher');
CREATE TABLE [TransactionMaster](
[ID] [bigint] NOT NULL PRIMARY KEY,
[VoucherTypeCode] [tinyint] NOT NULL,
[PayeeName] [varchar](255) NOT NULL,
[TransactionDate] datetime,
[RefNo] [nvarchar](50) NULL
CONSTRAINT [FK_tbl_TransactionMaster_tbl_VoucherType] FOREIGN KEY([VoucherTypeCode])
REFERENCES [VoucherType] ([VoucherTypeCode])
)
INSERT INTO [TransactionMaster] VALUES (1, 2, 'Asim', '2018-03-21', 'CRV-0001-LHR');
INSERT INTO [TransactionMaster] VALUES (2, 4, 'Ali', '2018-03-21', 'BRV-2421-KHI');
INSERT INTO [TransactionMaster] VALUES (3, 1, 'Erick', '2018-03-23', 'CPV-5435-ISL');
INSERT INTO [TransactionMaster] VALUES (4, 3, 'Asim', '2018-03-24', 'BPV-2345-CAN');
INSERT INTO [TransactionMaster] VALUES (5, 2, 'Mehboob', '2018-03-25', 'CRV-2976-PSH');
INSERT INTO [TransactionMaster] VALUES (6, 1, 'Erick', '2018-03-25', 'CPV-2323-KOH');
INSERT INTO [TransactionMaster] VALUES (7, 1, 'Feroze', '2018-03-21', 'CRV-0531-SRG');
INSERT INTO [TransactionMaster] VALUES (8, 3, 'Ali', '2018-03-21', 'BRV-2001-RWP');
CREATE TABLE TransactionDetail
(
ID NUMERIC NOT NULL PRIMARY KEY,
TransactionCode bigint,
DrAmount NUMERIC,
CrAmount NUMERIC
);
INSERT INTO TransactionDetail VALUES (1, 1, '2500', NULL);
INSERT INTO TransactionDetail VALUES (2, 1, NULL, '1500');
INSERT INTO TransactionDetail VALUES (3, 1, NULL, '1000');
INSERT INTO TransactionDetail VALUES (4, 2, '1150', NULL);
INSERT INTO TransactionDetail VALUES (5, 2, NULL, '1150');
INSERT INTO TransactionDetail VALUES (6, 3, '600', NULL);
INSERT INTO TransactionDetail VALUES (7, 3, '400', NULL);
INSERT INTO TransactionDetail VALUES (8, 3, '200', NULL);
INSERT INTO TransactionDetail VALUES (9, 3, NULL, '1200');
INSERT INTO TransactionDetail VALUES (10, 4, '1000', NULL);
INSERT INTO TransactionDetail VALUES (11, 4, NULL, '1000');
INSERT INTO TransactionDetail VALUES (12, 5, '2400', NULL);
INSERT INTO TransactionDetail VALUES (13, 5, NULL, '1200');
INSERT INTO TransactionDetail VALUES (14, 5, NULL, '1000');
INSERT INTO TransactionDetail VALUES (15, 5, NULL, '200');
INSERT INTO TransactionDetail VALUES (16, 6, '2900', NULL);
INSERT INTO TransactionDetail VALUES (17, 6, NULL, '2900');
INSERT INTO TransactionDetail VALUES (18, 7, '700', NULL);
INSERT INTO TransactionDetail VALUES (19, 7, '300', NULL);
INSERT INTO TransactionDetail VALUES (20, 7, '2100', NULL);
INSERT INTO TransactionDetail VALUES (21, 7, NULL, '3100');
INSERT INTO TransactionDetail VALUES (22, 8, '500', NULL);
INSERT INTO TransactionDetail VALUES (23, 8, NULL, '500');
Here is the query
with data1 as (
select a.id inid,a.VoucherTypeCode,PayeeName,MAX(c.DrAmount) InAmount,TransactionDate,RefNo,FullName from TransactionMaster a
inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
inner join TransactionDetail c on a.ID = c.TransactionCode
where a.VoucherTypeCode in (1,3)
GROUP BY a.id,a.VoucherTypeCode,PayeeName,TransactionDate,RefNo,FullName
),
data2 as (
select a.id outid,a.VoucherTypeCode,PayeeName,MAX(c.CrAmount) OutAmount,TransactionDate,RefNo,FullName from TransactionMaster a
inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
inner join TransactionDetail c on a.ID = c.TransactionCode
where a.VoucherTypeCode in (2,4)
GROUP BY a.id,a.VoucherTypeCode,PayeeName,TransactionDate,RefNo,FullName
)
select *,COALESCE(a.TransactionDate,b.TransactionDate) as FullDate from data1 a full join data2 b on inid = outid and a.TransactionDate = b.TransactionDate
--WHERE COALESCE(a.TransactionDate,b.TransactionDate) BETWEEN '2018-03-23 00:00:00.000' AND '2018-03-24 00:00:00.000'
order by FullDate
The expected output is provided below when you remove the commenting from the date check:
inid VoucherTypeCode PayeeName InAmount TransactionDate RefNo FullName outid VoucherTypeCode PayeeName OutAmount TransactionDate RefNo FullName FullDate Opening
-------------------- --------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- --------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------
3 1 Erick 1200 2018-03-23 00:00:00.000 CPV-5435-ISL Cash Payment Voucher NULL NULL NULL NULL NULL NULL NULL 2018-03-23 00:00:00.000 -50
4 3 Asim 1000 2018-03-24 00:00:00.000 BPV-2345-CAN Bank Payment Voucher NULL NULL NULL NULL NULL NULL NULL 2018-03-24 00:00:00.000 1150
The formula is that (Opening+InAmount) - Out Amount will be the Closing Balance and Opening will be previous rows Closing Balance.
So for first record opening will be 0 and closing will be 3100 and for second opening = 3100 and closing 3600 and so on.
If the VoucherType is 1 or 3 than I have to get the Credit Amount CrAmount and if the VoucherType is 2 or 4 then I need to get the Debit Amount DrAmount.
I've asked this question before and got the expected output as well but now the DB structure is changed a bit and I am unable to use that logic here.
basically it is the same as the previous query that i posted in your other thread.
Since the details in the other table TransactionDetail, you just need to INNER JOIN from the TransactionMaster to it and do the SUM(). I didn't verify the Dr - Cr or Cr - Dr logic. Please verify yourself.
SELECT t.*, v.FullName, o.Opening
FROM [TransactionMaster] t
INNER JOIN [VoucherType] v on t.VoucherTypeCode = v.VoucherTypeCode
OUTER APPLY
(
SELECT Opening = sum(case when m.[VoucherTypeCode] in (1, 3)
then - ISNULL(d.CrAmount, 0)
else + ISNULL(d.CrAmount, 0)
end)
FROM [TransactionMaster] m
INNER JOIN [TransactionDetail] d ON m.ID = d.TransactionCode
WHERE m.TransactionDate < t.TransactionDate
) o
WHERE t.TransactionDate BETWEEN '2018-03-23' AND '2018-03-24'
order by t.TransactionDate
EDIT:
You don't need to use FULL JOIN to identify IN and OUT. Just use CASE statement as below
SELECT inID = case when t.VoucherTypeCode in (1,3) then t.ID end,
inAmount = case when t.VoucherTypeCode in (1,3) then a.Amount end,
outID = case when t.VoucherTypeCode in (2,4) then t.ID end,
outAmount = case when t.VoucherTypeCode in (2,4) then a.Amount end,
t.PayeeName, t.TransactionDate, t.RefNo,
v.FullName, Opening = isnull(o.Opening, 0)
FROM [TransactionMaster] t
INNER JOIN [VoucherType] v on t.VoucherTypeCode = v.VoucherTypeCode
CROSS APPLY
(
SELECT Amount = sum(case when m.[VoucherTypeCode] in (1, 3)
then -CrAmount
else DrAmount
end)
FROM [TransactionMaster] m
INNER JOIN [TransactionDetail] d ON m.ID = d.TransactionCode
WHERE m.ID = t.ID
) a
OUTER APPLY
(
SELECT Opening = sum(case when m.[VoucherTypeCode] in (1, 3)
then -CrAmount
else DrAmount
end)
FROM [TransactionMaster] m
INNER JOIN [TransactionDetail] d ON m.ID = d.TransactionCode
WHERE m.TransactionDate < t.TransactionDate
) o
order by t.TransactionDate

Breaking data into multiple columns

I am working on a query where I require data to be divided in multiple columns based on the type of the value in it. I have a Voucher Type table where I am defining types now I want payment and receipt to be divided in two columns.
Here is the structure of the tables and sample data:
DROP TABLE [TransactionMaster];
DROP TABLE [VoucherType];
CREATE TABLE [VoucherType](
[VoucherTypeCode] [tinyint] NOT NULL PRIMARY KEY,
[FullName] [nvarchar](255) NOT NULL
);
INSERT INTO [VoucherType] VALUES (1, 'Cash Payment Voucher');
INSERT INTO [VoucherType] VALUES (2, 'Cash Receipt Voucher');
INSERT INTO [VoucherType] VALUES (3, 'Bank Payment Voucher');
INSERT INTO [VoucherType] VALUES (4, 'Bank Receipt Voucher');
CREATE TABLE [TransactionMaster](
[ID] [bigint] NOT NULL PRIMARY KEY,
[VoucherTypeCode] [tinyint] NOT NULL,
[PayeeName] [varchar](255) NOT NULL,
[RefNo] [nvarchar](50) NULL
CONSTRAINT [FK_tbl_TransactionMaster_tbl_VoucherType] FOREIGN KEY([VoucherTypeCode])
REFERENCES [VoucherType] ([VoucherTypeCode])
)
INSERT INTO [TransactionMaster] VALUES (1, 2, 'Asim', 'CRV-0001-LHR');
INSERT INTO [TransactionMaster] VALUES (2, 4, 'Ali', 'BRV-2421-KHI');
INSERT INTO [TransactionMaster] VALUES (3, 1, 'Erick', 'CPV-5435-ISL');
INSERT INTO [TransactionMaster] VALUES (4, 3, 'Asim', 'BPV-2345-CAN');
INSERT INTO [TransactionMaster] VALUES (5, 2, 'Mehboob', 'CRV-2976-PSH');
INSERT INTO [TransactionMaster] VALUES (6, 1, 'Erick', 'CPV-2323-KOH');
This is the query.
SELECT [Master].[RefNo], [Type].[FullName] [V.Type], [Master].[PayeeName]
FROM [TransactionMaster] [Master], [VoucherType] [Type]
WHERE [Type].[VoucherTypeCode] = [Master].[VoucherTypeCode]
Inward Outward
RefNo V.Type PayeeName RefNo V.Type PayeeName
CPV-5435-ISL Cash Payment Voucher Erick CRV-0001-LHR Cash Receipt Voucher Asim
BPV-2345-CAN Bank Payment Voucher Asim BRV-2421-KHI Bank Receipt Voucher Ali
CPV-2323-KOH Cash Payment Voucher Erick CRV-2976-PSH Cash Receipt Voucher Mehboob
So basically if the VoucherCode is 1 or 3 it'll be in Inward part columns and if the VoucherCode is 2 or 4 then it'll be in outward part columns.
So I require total six columns instead of three in one row. Hope this can be done. Outward and Inward is just to clear out columns part they are not required to be shown or something.
Check out this:
select tb1.Refno, tb1.[FullName] as VType, tb1.PayeeName, tb2.Refno, tb2.[FullName] as VType, tb2.PayeeName from(
(select ROW_NUMBER()over (order by id) as rowid, TransactionMaster.RefNo, TransactionMaster.PayeeName, [VoucherType].FullName
from TransactionMaster
inner join [VoucherType] on TransactionMaster.VoucherTypeCode = [VoucherType].VoucherTypeCode
where TransactionMaster.[VoucherTypeCode] in (1,3))tb1
full outer join
(select ROW_NUMBER()over (order by id) as rowid, TransactionMaster.RefNo, TransactionMaster.PayeeName, [VoucherType].FullName
from TransactionMaster
inner join [VoucherType] on TransactionMaster.VoucherTypeCode = [VoucherType].VoucherTypeCode
where TransactionMaster.[VoucherTypeCode] in (2,4)
) tb2 on tb1.rowid = tb2.rowid)

Resources