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,
[Amount] NUMERIC,
[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', '2500', 'CRV-0001-LHR');
INSERT INTO [TransactionMaster] VALUES (2, 4, 'Ali', '2018-03-21', '1150', 'BRV-2421-KHI');
INSERT INTO [TransactionMaster] VALUES (3, 1, 'Erick', '2018-03-23', '1200', 'CPV-5435-ISL');
INSERT INTO [TransactionMaster] VALUES (4, 3, 'Asim', '2018-03-24', '1000', 'BPV-2345-CAN');
INSERT INTO [TransactionMaster] VALUES (5, 2, 'Mehboob', '2018-03-25', '2400', 'CRV-2976-PSH');
INSERT INTO [TransactionMaster] VALUES (6, 1, 'Erick', '2018-03-25', '2900', 'CPV-2323-KOH');
INSERT INTO [TransactionMaster] VALUES (7, 1, 'Feroze', '2018-03-21', '3100', 'CRV-0531-SRG');
INSERT INTO [TransactionMaster] VALUES (8, 3, 'Ali', '2018-03-21', '500', 'BRV-2001-RWP');
Here is the query
with data1 as (
select a.id inid,a.VoucherTypeCode,PayeeName,a.Amount InAmount,TransactionDate,RefNo,FullName from TransactionMaster a inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
where a.VoucherTypeCode in (1,3)
),
data2 as (
select a.id outid,a.VoucherTypeCode,PayeeName,a.Amount OutAmount,TransactionDate,RefNo,FullName from TransactionMaster a inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
where a.VoucherTypeCode in (2,4)
)
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 output right now is like this::
inid VoucherTypeCode PayeeName InAmount TransactionDate RefNo FullName outid VoucherTypeCode PayeeName OutAmount TransactionDate RefNo FullName FullDate
-------------------- --------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- --------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------- ----------------------- -------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------
7 1 Feroze 3100 2018-03-21 00:00:00.000 CRV-0531-SRG Cash Payment Voucher NULL NULL NULL NULL NULL NULL NULL 2018-03-21 00:00:00.000
8 3 Ali 500 2018-03-21 00:00:00.000 BRV-2001-RWP Bank Payment Voucher NULL NULL NULL NULL NULL NULL NULL 2018-03-21 00:00:00.000
NULL NULL NULL NULL NULL NULL NULL 2 4 Ali 1150 2018-03-21 00:00:00.000 BRV-2421-KHI Bank Receipt Voucher 2018-03-21 00:00:00.000
NULL NULL NULL NULL NULL NULL NULL 1 2 Asim 2500 2018-03-21 00:00:00.000 CRV-0001-LHR Cash Receipt Voucher 2018-03-21 00:00:00.000
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
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
6 1 Erick 2900 2018-03-25 00:00:00.000 CPV-2323-KOH Cash Payment Voucher NULL NULL NULL NULL NULL NULL NULL 2018-03-25 00:00:00.000
NULL NULL NULL NULL NULL NULL NULL 5 2 Mehboob 2400 2018-03-25 00:00:00.000 CRV-2976-PSH Cash Receipt Voucher 2018-03-25 00:00:00.000
The expected output is this:
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.
use OUTER APPLY to calculate the Amount before the date.
use conditional SUM() to calculate the amount
select *
from [TransactionMaster] m
inner join [VoucherType] t on m.VoucherTypeCode = t.VoucherTypeCode
outer apply
(
select Opening = sum(case when [VoucherTypeCode] in (1, 3)
then Amount
else -Amount
end)
from [TransactionMaster] x
where x.TransactionDate < m.TransactionDate
) o
where m.TransactionDate between '2018-03-23' and '2018-03-24'
order by ID
Explanation on the CASE WHEN statement
the amount is treated as IN or OUT depending on the VoucherTypeCode.
For code 1 and 3 it is IN / positive and others is OUT / negative
What the case statement does is to convert the amount to positive or negative value depending on the VoucherTypeCode
SELECT VoucherTypeCode, Amount
case when [VoucherTypeCode] in (1, 3)
then +Amount
else -Amount
end
FROM ...
SO basically you will get
1 2 2500 -2500
2 4 1150 -1150
3 1 1200 1200
so when you SUM() it up, it will be -2500 - 1150 + 1200 + . .
Related
--demo setup
drop table if exists dbo.product
go
create table dbo.Product
(
ProductId int,
ProductTitle varchar(55),
ProductCategory varchar(255),
Loaddate datetime
)
insert into dbo.Product
values (1, 'Table', 'ABCD', '3/4/2018'),
(1, 'Table', 'ABCD', '3/5/2018'),
(1, 'Table', 'ABCD', '3/6/2018'),
(1, 'Table', 'XYZ', '3/7/2018'),
(1, 'Table', 'XYZ', '3/8/2018'),
(1, 'Table', 'XYZ', '3/9/2018'),
(1, 'Table', 'GHI', '3/10/2018'),
(1, 'Table', 'GHI', '3/11/2018'),
(1, 'Table', 'XYZ', '3/12/2018'),
(1, 'Table', 'XYZ', '3/13/2018')
SELECT
product.productid,
product.producttitle,
product.productcategory,
MIN(product.loaddate) AS BeginDate,
-- ,max(product.LoadDate) as BeginDate1
CASE
WHEN MAX(product.loaddate) = MAX(oa.enddate1)
THEN '12/31/9999'
ELSE MAX(product.loaddate)
END AS EndDate
FROM
dbo.product product
CROSS APPLY
(SELECT MAX(subproduct.loaddate) EndDate1
FROM dbo.product subproduct
WHERE subproduct.productid = product.productid) oa
GROUP BY
productid, producttitle, productcategory
Output:
productid
producttitle
productcategory
BeginDate
EndDate
1
Table
ABCD
2018-03-04 00:00:00.000
2018-03-06 00:00:00.000
1
Table
XYZ
2018-03-07 00:00:00.000
9999-12-31 00:00:00.000
1
Table
GHI
2018-03-10 00:00:00.000
2018-03-11 00:00:00.000
Desired output:
productid
producttitle
productcategory
BeginDate
EndDate
1
Table
ABCD
2018-03-04 00:00:00.000
2018-03-06 00:00:00.000
1
Table
XYZ
2018-03-07 00:00:00.000
2018-03-09 00:00:00.000
1
Table
GHI
2018-03-10 00:00:00.000
2018-03-11 00:00:00.000
1
Table
XYZ
2018-03-12 00:00:00.000
9999-12-31 00:00:00.000
The last two inserted rows repeat the data from Loaddate '3/7/2018'-'3/9/2018', this doesn't happen if any of the new inserted rows doesn't repeat data. The only thing that changes is the LoadDate, giving me incorrect output. how can i get something like that desired output?
Well, first of all, you need to find a sequence number over all your records. If you already have a primary key, that's good. In example you gave us, there's no such column, so let's generate it.
Then, we make pairs with start and end dates for each product's category change. Another thing is to group all these product's category changes.
Finally, we make just a simple group by:
;
with cte as ( select *,
row_number() over(partition by ProductId order by Loaddate) as rn
from product
), cte2 as ( select t1.ProductId,
t1.ProductTitle,
t1.ProductCategory,
t1.Loaddate as BeginDate,
case
when t1.ProductCategory <> t2.ProductCategory
then t1.Loaddate
else coalesce(t2.Loaddate, null)
end as EndDate,
row_number() over(order by t1.ProductId, t1.Loaddate) as rn_overall,
row_number() over(partition by t1.ProductId, t1.ProductCategory order by t1.Loaddate) as rn_category
from cte as t1
left join cte as t2
on t2.ProductId = t1.ProductId
and t2.rn = t1.rn + 1
), cte3 as ( select *,
min(rn_overall) over (partition by ProductId, ProductCategory, rn_overall - rn_category) as product_group
from cte2
)
select ProductId, ProductTitle, ProductCategory,
min(BeginDate) as BeginDate,
case
when max(case when EndDate is null then 1 else 0 end) = 0
then max(EndDate)
else null
end as EndDate
from cte3
group by ProductId, ProductTitle, ProductCategory, product_group
order by ProductId, BeginDate
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
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
I have this table structure and query written with the help of some guy here and it works perfect but I want to order the rows on the basis of dates.
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');
Here is the query
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
)
The output right now is like this::
Refno VType PayeeName TransactionDate Refno VType PayeeName TransactionDate
CPV-5435-ISL Cash Payment Voucher Erick 2018-03-23 00:00:00.000 CRV-0001-LHR Cash Receipt Voucher Asim 2018-03-21 00:00:00.000
BPV-2345-CAN Bank Payment Voucher Asim 2018-03-24 00:00:00.000 BRV-2421-KHI Bank Receipt Voucher Ali 2018-03-21 00:00:00.000
CPV-2323-KOH Cash Payment Voucher Erick 2018-03-25 00:00:00.000 CRV-2976-PSH Cash Receipt Voucher Mehboob 2018-03-25 00:00:00.000
I want to show the date in ascending order and in case no voucher exist on that date it should be null.
I am putting the expected output below
Refno VType PayeeName TransactionDate Refno VType PayeeName TransactionDate
CRV-0001-LHR Cash Receipt Voucher Asim 2018-03-21 00:00:00.000
BRV-2421-KHI Bank Receipt Voucher Ali 2018-03-21 00:00:00.000
CPV-5435-ISL Cash Payment Voucher Erick 2018-03-23 00:00:00.000
BPV-2345-CAN Bank Payment Voucher Asim 2018-03-24 00:00:00.000
CPV-2323-KOH Cash Payment Voucher Erick 2018-03-25 00:00:00.000 CRV-2976-PSH Cash Receipt Voucher Mehboob 2018-03-25 00:00:00.000
You can use COALESCE to concat your dates and then order by it. Hopefully this would resolve your question
with data1 as (
select a.id,a.VoucherTypeCode,PayeeName,TransactionDate,RefNo,FullName from TransactionMaster a inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
where a.VoucherTypeCode in (1,3)
),
data2 as (
select a.id,a.VoucherTypeCode,PayeeName,TransactionDate,RefNo,FullName from TransactionMaster a inner join [VoucherType] b on a.VoucherTypeCode = b.VoucherTypeCode
where a.VoucherTypeCode in (2,4)
)
select *,COALESCE(a.TransactionDate,b.TransactionDate) as FullDate from data1 a full join data2 b on a.TransactionDate = b.TransactionDate
order by FullDate
Result
Try this
select tb1.Refno,
tb1.[FullName] as VType,
tb1.PayeeName,
tb2.Refno,
tb2.[FullName] as VType,
tb2.PayeeName
from(
(
select ROW_NUMBER()over (partition by TransactionDate order by id) as rowid,
TransactionMaster.RefNo,
TransactionMaster.PayeeName,
[VoucherType].FullName,
TransactionMaster.TransactionDate
from TransactionMaster
inner join [VoucherType] on TransactionMaster.VoucherTypeCode = [VoucherType].VoucherTypeCode
where TransactionMaster.[VoucherTypeCode] in (1,3)
)tb1
full outer join (
select ROW_NUMBER()over (partition by TransactionDate order by id) as rowid,
TransactionMaster.RefNo,
TransactionMaster.PayeeName,
[VoucherType].FullName,
TransactionMaster.TransactionDate
from TransactionMaster
inner join [VoucherType] on TransactionMaster.VoucherTypeCode = [VoucherType].VoucherTypeCode
where TransactionMaster.[VoucherTypeCode] in (2,4)
) tb2 on tb1.rowid = tb2.rowid and tb1.TransactionDate = tb2.TransactionDate
)
Command line or library "compare tables" utility for SQL server with comprehensive diff output to a file in .Net
I can't find anything like that. Commercial or free ( XSQL Lite is suitable for my case and ) tools show diffs in grids with possibility to export to CSV. Also they generate sync SQL scripts when run from command line. What I need is an output as a comprehensive report ( XML , HTML ) suitable for parsing so that I would be able to show similar diff grid in my application ( updated old/new values for each column , added - all values for row , deleted - all values for row and etc... ) .
Since it sounds like you only want to show the diffs in your application, just write your own query, it isn't that hard, here is an example:
DECLARE #TableA table (RowID int, Col1 int, Col2 varchar(5), Col3 datetime)
DECLARE #TableB table (RowID int, Col1 int, Col2 varchar(5), Col3 datetime)
set nocount on
INSERT #TableA VALUES( 1,111,'AAA','1/1/2010')
INSERT #TableA VALUES( 2,222,'BBB','1/1/2010')
INSERT #TableA VALUES( 3,333,'CCC','1/1/2010')
INSERT #TableA VALUES( 4,444,'DDD','1/1/2010')
INSERT #TableA VALUES( 5,555,'EEE','1/1/2010')
INSERT #TableA VALUES( 6,666,'FFF','1/1/2010')
INSERT #TableA VALUES( 7,777,'GGG','1/1/2010')
INSERT #TableA VALUES( 9,888,'HHH','1/1/2010')
INSERT #TableA VALUES(10,111,'III','1/1/2010')
INSERT #TableB VALUES( 1,111,'AAA','1/1/2010')
INSERT #TableB VALUES( 3,333,'CCC','1/1/2010')
INSERT #TableB VALUES( 4,444,'DD' ,'1/1/2010')
INSERT #TableB VALUES( 5,555,'EEE','2/2/2010')
INSERT #TableB VALUES( 6,666,'FFF','1/1/2010')
INSERT #TableB VALUES( 7,777,'GGG','1/1/2010')
INSERT #TableB VALUES( 8,888,'ZZZ','1/1/2010')
INSERT #TableB VALUES( 9,888,'HHH','1/1/2010')
INSERT #TableB VALUES(10,111,'III','1/1/2010')
set nocount off
SELECT
a.RowID, CASE WHEN b.RowID IS NULL THEN 'A' ELSE '' END AS RowsOnlyExistsIn
,a.Col1,b.Col1, CASE WHEN a.Col1=b.Col1 OR (COALESCE(a.Col1,b.Col1) IS NULL) THEN 'N' ELSE 'Y' END AS Col1Diff
,a.Col2,b.Col2, CASE WHEN a.Col2=b.Col2 OR (COALESCE(a.Col2,b.Col2) IS NULL) THEN 'N' ELSE 'Y' END AS Col2Diff
,a.Col3,b.Col3, CASE WHEN a.Col3=b.Col3 OR (COALESCE(a.Col3,b.Col3) IS NULL) THEN 'N' ELSE 'Y' END AS Col3Diff
FROM #TableA a
LEFT OUTER JOIN #TableB b On a.RowID=b.RowID
UNION ALL
SELECT
b.RowID, 'B' AS RowsOnlyExistsIn
,null,b.Col1, 'Y' AS Col1Diff
,null,b.Col2, 'Y' AS Col2Diff
,null,b.Col3, 'Y' AS Col3Diff
FROM #TableB b
WHERE b.RowID NOT IN (SELECT RowID FROM #TableA)
ORDER BY 1
OUTPUT:
RowID RowsOnlyExistsIn Col1 Col1 Col1Diff Col2 Col2 Col2Diff Col3 Col3 Col3Diff
----------- ---------------- ----------- ----------- -------- ----- ----- -------- ----------------------- ----------------------- --------
1 111 111 N AAA AAA N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
2 A 222 NULL Y BBB NULL Y 2010-01-01 00:00:00.000 NULL Y
3 333 333 N CCC CCC N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
4 444 444 N DDD DD Y 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
5 555 555 N EEE EEE N 2010-01-01 00:00:00.000 2010-02-02 00:00:00.000 Y
6 666 666 N FFF FFF N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
7 777 777 N GGG GGG N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
8 B NULL 888 Y NULL ZZZ Y NULL 2010-01-01 00:00:00.000 Y
9 888 888 N HHH HHH N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
10 111 111 N III III N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
(10 row(s) affected)
of course you would need to generate this dynamically so any two tables could be compared. This query will get you the columns of any tables:
SELECT
*
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_CATALOG ='database'
AND TABLE_SCHEMA='dbo'
AND TABLE_NAME ='yourtable'
ORDER BY ORDINAL_POSITION
here is a quick dynamic sql version (I attempt to pull in all the PK columns and use them to dynamically join the tables, but I only tested it on tables with 1 PK column):
set up for dynamic sql
CREATE TABLE TableA (RowID int primary key, Col1 int, Col2 varchar(5), Col3 datetime)
CREATE TABLE TableB (RowID int primary key, Col1 int, Col2 varchar(5), Col3 datetime)
set nocount on
INSERT TableA VALUES( 1,111,'AAA','1/1/2010')
INSERT TableA VALUES( 2,222,'BBB','1/1/2010')
INSERT TableA VALUES( 3,333,'CCC','1/1/2010')
INSERT TableA VALUES( 4,444,'DDD','1/1/2010')
INSERT TableA VALUES( 5,555,'EEE','1/1/2010')
INSERT TableA VALUES( 6,666,'FFF','1/1/2010')
INSERT TableA VALUES( 7,777,'GGG','1/1/2010')
INSERT TableA VALUES( 9,888,'HHH','1/1/2010')
INSERT TableA VALUES(10,111,'III','1/1/2010')
INSERT TableB VALUES( 1,111,'AAA','1/1/2010')
INSERT TableB VALUES( 3,333,'CCC','1/1/2010')
INSERT TableB VALUES( 4,444,'DD' ,'1/1/2010')
INSERT TableB VALUES( 5,555,'EEE','2/2/2010')
INSERT TableB VALUES( 6,666,'FFF','1/1/2010')
INSERT TableB VALUES( 7,777,'GGG','1/1/2010')
INSERT TableB VALUES( 8,888,'ZZZ','1/1/2010')
INSERT TableB VALUES( 9,888,'HHH','1/1/2010')
INSERT TableB VALUES(10,111,'III','1/1/2010')
set nocount off
dynamic sql
DECLARE #TableA sysname
,#TableB sysname
,#SQLa varchar(max)
,#SQLb varchar(max)
,#SQL varchar(max)
SELECT #TableA='TableA'
,#TableB='TableB'
,#SQLa=NULL
,#SQLb=NULL
DECLARE #PKs table (RowID int identity(1,1) primary key, PkColumn sysname)
DECLARE #index_id int
,#PK sysname
,#i int
SELECT #index_id=index_id from sys.indexes where object_id=OBJECT_ID(#TableA) AND is_primary_key=1
SELECT #PK=''
,#i=0
while (#PK is not null)
BEGIN
SET #i=#i+1
SELECT #PK = index_col(#TableA, #index_id, #i)
IF #PK IS NULL BREAK
INSERT INTO #PKs (PkColumn) VALUES (#PK)
END
SELECT #SQLa=''
,#SQLb=''''+#TableB+''' '
SELECT
#SQLa=#SQLa+' ,a.'+COLUMN_NAME+',b.'+COLUMN_NAME+', CASE WHEN a.'+COLUMN_NAME+'=b.'+COLUMN_NAME+' OR (COALESCE(a.'+COLUMN_NAME+',b.'+COLUMN_NAME+') IS NULL) THEN ''N'' ELSE ''Y'' END AS '+COLUMN_NAME+'Diff '
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME =#TableA
ORDER BY ORDINAL_POSITION
SELECT
#SQLb=#SQLb+' ,null,b.'+COLUMN_NAME+', ''Y'' AS '+COLUMN_NAME+'Diff'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME =#TableA
ORDER BY ORDINAL_POSITION
SET #SQL='SELECT CASE WHEN b.'+(SELECT PkColumn FROM #PKs WHERE RowID=1)+' IS NULL THEN '''+#TableA+''' ELSE '''' END AS RowsOnlyExistsIn '
+#SQLa
+'FROM '+#TableA+' a LEFT OUTER JOIN '+#TableB+' b ON '
SELECT
#SQL=#SQL+ CASE WHEN RowID!=1 THEN 'AND ' ELSE '' END +'a.'+PkColumn+'=b.'+PkColumn+' '
FROM #PKs
SET #SQL=#SQL+' UNION ALL SELECT '
+#SQLb
+' FROM '+#TableB+' b LEFT OUTER JOIN '+#TableA+' A ON '
SELECT
#SQL=#SQL+ CASE WHEN RowID!=1 THEN 'AND ' ELSE '' END +'b.'+PkColumn+'=a.'+PkColumn+' '
FROM #PKs
SET #SQL=#SQL+'WHERE a.'+(SELECT PkColumn FROM #PKs WHERE RowID=1)+' IS NULL ORDER BY 2,3'
EXEC(#SQL)
output:
RowsOnlyExistsIn RowID RowID RowIDDiff Col1 Col1 Col1Diff Col2 Col2 Col2Diff Col3 Col3 Col3Diff
---------------- ----------- ----------- --------- ----------- ----------- -------- ----- ----- -------- ----------------------- ----------------------- --------
TableB NULL 8 Y NULL 888 Y NULL ZZZ Y NULL 2010-01-01 00:00:00.000 Y
1 1 N 111 111 N AAA AAA N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
TableA 2 NULL Y 222 NULL Y BBB NULL Y 2010-01-01 00:00:00.000 NULL Y
3 3 N 333 333 N CCC CCC N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
4 4 N 444 444 N DDD DD Y 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
5 5 N 555 555 N EEE EEE N 2010-01-01 00:00:00.000 2010-02-02 00:00:00.000 Y
6 6 N 666 666 N FFF FFF N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
7 7 N 777 777 N GGG GGG N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
9 9 N 888 888 N HHH HHH N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
10 10 N 111 111 N III III N 2010-01-01 00:00:00.000 2010-01-01 00:00:00.000 N
(10 row(s) affected)
I;m assuming you want to compare data not schema and I'm assuming that the tables are in diff databases.
I would not do it in SQL but load the data in generic .Net DataSet, and iterate thru Table
object, columns and rows. This way one piece of code would work for any database table, no need for awkward dynamic SQL, however the downside is possible perf hit since you will need to load the data into a dataset - in this case just run the code on SQl server itself and dump the result files to a file share.
Open Source DiffKit will do all of that except the .NET part.
www.diffkit.org