Compare two tables and find not matched price SQL Server - sql

create table #tmp1
(
name varchar(100),
price decimal(10, 2)
)
insert into #tmp1 values('Test', 200.00)
insert into #tmp1 values('Test', 100.00)
insert into #tmp1 values('Test', 300.00)
insert into #tmp1 values('Test1', 500.00)
insert into #tmp1 values('Test2', 300.00)
create table #tmp
(
name varchar(100),
price decimal(10,2)
)
insert into #tmp values('Test', 200.00)
insert into #tmp values('Test', 100.00)
insert into #tmp values('Test', 400.00)
insert into #tmp values('Test1', 600.00)
insert into #tmp values('Test3', 300.00)
I have two tables with comparing parameter Name and find not matched price.
Name should match and price will be differ.
Expected output:
Name Price Price
------------------------------
Test1 600.00 500.00
Test 300.00 400.00

Try this
SELECT *
FROM #tmp a
INNER JOIN #tmp1 b ON a.name=b.name AND a.PRICE <> b.PRICE
UPDATED : AS per your below comment you wants to consider order of insertion as well,
;WITH tmp AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY NAME) RN
FROM #tmp
),tmp1 AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY NAME ORDER BY NAME) RN
FROM #tmp1
)
SELECT a.name,a.price,b.price
FROM tmp a
INNER JOIN tmp1 b ON a.name=b.name AND a.RN=b.RN AND a.PRICE <> b.PRICE

Related

SQL to display pivoted data

I have the following table:
and i want the following output displayed:
the above is basically the (quan*cst) for each day. Now I can acieve this by the following sql:
select t1.pid, isnull(b.m1,0) as day1sale, isnull(a.m2,0) as day2sale
from dbo.test1 t1
left join(select pid, sum(quan*cst) m1
from dbo.test1 where date='2017-05-01' group by pid) b on b.pid=t1.pid
left join (select pid, sum(quan*cst) m2
from dbo.test1 where date='2017-05-02' group by pid) a on a.pid=t1.pid
group by t1.pid,m2 ,m1
order by t1.pid
But i was wondering if there is a simpler way to do it without actually having to hard code the dates?
thanks in advance for the help!
Using a self join to get a list of distinct dates, the result set can be pivoted and the desired aggregates applied to each PID.
CREATE TABLE #TEMP_EXAMPLE
(
[DATE] DATE,
[ID] INT,
[PID] INT,
[QUAN] INT,
[CST] INT
)
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','1','1','2','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','2','2','6','2')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','3','3','5','1')
INSERT INTO #TEMP_EXAMPLE VALUES('05/01/2017','4','1','1','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','5','3','3','1')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','6','4','4','7')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','7','1','7','3')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','8','5','2','8')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','9','6','5','6')
INSERT INTO #TEMP_EXAMPLE VALUES('05/02/2017','10','2','8','2')
SELECT ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY [DATE]) AS ID,*
INTO #TEMP_DYNAMIC_DATES
FROM (SELECT DISTINCT [DATE] FROM #TEMP_EXAMPLE ) AS X
SELECT * FROM #TEMP_DYNAMIC_DATES
SELECT PID,ISNULL(DAY1SALE,0) AS DAY1SALE,ISNULL(DAY2SALE,0) AS DAY2SALE FROM (
SELECT PID,SUM([QUAN] * [CST]) AS X, INDIC FROM (
SELECT A.*,
CASE WHEN B.ID = 1 THEN 'DAY1SALE'
WHEN B.ID = 2 THEN 'DAY2SALE'
END AS INDIC
FROM #TEMP_EXAMPLE AS A
JOIN #TEMP_DYNAMIC_DATES AS B
ON A.DATE = B.DATE
) AS X
GROUP BY PID,INDIC) AS O
PIVOT(SUM(X) FOR INDIC IN([DAY1SALE],[DAY2SALE])) AS PT

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

Deleting records that are similar with previous one SQL Server

I am looking for a query which fetches me the data that is different compared to the previous row,
A sample code (with table creation and data)
create table #temp
(id int, eid int, name char(10),estid int, ecid int, epid int, etc char(5) )
insert into #temp values (1,1,'a',1,1,1,'a')
insert into #temp values (2,1,'a',1,1,1,'a')
insert into #temp values (3,1,'a',2,1,1,'a')
insert into #temp values (4,1,'a',1,1,1,'a')
insert into #temp values (5,1,'a',1,1,1,'a')
insert into #temp values (6,1,'a',1,2,1,'a')
insert into #temp values (7,1,'a',1,1,1,'a')
insert into #temp values (8,1,'a',2,1,1,'a')
insert into #temp values (9,1,'a',1,1,1,'a')
insert into #temp values (10,1,'a',1,1,1,'a')
insert into #temp values (11,2,'a',1,1,1,'a')
insert into #temp values (12,2,'a',1,1,1,'a')
insert into #temp values (13,2,'a',2,1,1,'a')
insert into #temp values (14,2,'a',1,1,1,'a')
insert into #temp values (15,2,'a',1,1,1,'a')
insert into #temp values (16,2,'a',1,2,1,'a')
insert into #temp values (17,2,'a',1,1,1,'a')
insert into #temp values (18,2,'a',2,1,1,'a')
insert into #temp values (19,2,'a',1,1,1,'a')
insert into #temp values (20,2,'a',1,1,1,'a')
I tried with some ways of getting the data as the way that i expected
SELECT * INTo #Temp_Final
FROM #temp
WHERE #temp.%%physloc%%
NOT IN (SELECT Min(b.%%physloc%%)
FROM #temp b
GROUP BY eid,name,estid,ecid,epid,etc)
ORDER BY id
SELECT * FROM #temp WHERE id not in (SELECT id FROM #Temp_Final) ORDER BY id
But i wasn't getting the result as i expected...
This is how the result needs to be
select * from #temp where id in (1,3,4,6,7,8,9,11,13,14,16,17,18,19)
You can do this with a simple self-join and appropriate comparison:
select t.*
from #temp t left outer join
#temp tprev
on t.id = tprev.id + 1
where tprev.id is null or
t.name <> tprev.name or
t.estid <> tprev.estid or
t.ecid <> tprev.ecid or
t.epid <> tprev.epid or
t.etc <> tprev.etc;
This assumes that the ids are sequential with no gaps. If the ids are not, you can get the previous id using a correlated subquery or the lag() function.
Your title says "delete" but the question seems to just want the list of such rows. You can phrase this as a delete query if you need to.
For SQL Server 2012 (SQL Fiddle)
WITH CTE
AS (SELECT *,
LAG(eid) OVER (ORDER BY id) AS prev_eid,
LAG(name) OVER (ORDER BY id) AS prev_name,
LAG(estid) OVER (ORDER BY id) AS prev_estid,
LAG(ecid) OVER (ORDER BY id) AS prev_ecid,
LAG(epid) OVER (ORDER BY id) AS prev_epid,
LAG(etc) OVER (ORDER BY id) AS prev_etc
FROM #temp)
DELETE FROM CTE
WHERE EXISTS (SELECT eid,
name,
estid,
ecid,
epid,
etc
INTERSECT
SELECT prev_eid,
prev_name,
prev_estid,
prev_ecid,
prev_epid,
prev_etc)
select
t.id,
t.eid,
t.name,
t.estid,
t.ecid,
t.epid,
t.etc
from #temp t
left join #temp d
on d.id = t.id-1
and d.eid = t.eid
and d.name = t.name
and d.estid = t.estid
and d.ecid = t.ecid
and d.epid = t.epid
and d.etc = t.etc
where d.id is null

Select one records from three tables based on latest date

I have a TransactionMaster table in SQL Server 2012 that has unique TransactionID. The same TransactionID wil be availabe in LowTransaction ,MediumTransaction and HighTransaction tables.
For each TransactionID in TransactionMaster, I need to display one StatusMessage. The StatusMessage may come from any of the 3 tables - based on date formulated from CRTDTEC and CRTTIME columns..
What is the best way in SQL Server 2012 to select the StatusMessage corresponding to latest date?
Note: CRTDTEC Format - YYMMDD and CRTTIME Format - HHMMSS
CODE
DECLARE #TransactionMaster TABLE (TransactionID INT)
DECLARE #LowTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
DECLARE #MediumTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
DECLARE #HighTransaction TABLE (TransactionID INT, StatusMessage VARCHAR(80), CRTDTEC VARCHAR(8), CRTTIME VARCHAR(6))
INSERT INTO #TransactionMaster VALUES (1)
INSERT INTO #TransactionMaster VALUES (2)
INSERT INTO #TransactionMaster VALUES (3)
INSERT INTO #LowTransaction VALUES (1,'1 Low','20131213','235959')
INSERT INTO #MediumTransaction VALUES (1,'1','20131213','235900')
INSERT INTO #HighTransaction VALUES (1,'1 High','20111213','235959')
INSERT INTO #LowTransaction VALUES (2,'2 Low','20111213','235959')
INSERT INTO #LowTransaction VALUES (3,'3 Low','20111213','235959')
INSERT INTO #MediumTransaction VALUES (3,'3 Medium','20111213','235959')
INSERT INTO #HighTransaction VALUES (3,'3 High','20140101','235959')
Expected Result
(1,'1 Low','20131213','235959')
(2,'2 Low','20111213','235959')
(3,'3 High','20140101','235959')
The simplest way would probably be
WITH TransConsolidated
AS (SELECT *
FROM #LowTransaction
UNION ALL
SELECT *
FROM #MediumTransaction
UNION ALL
SELECT *
FROM #HighTransaction)
SELECT TM.TransactionID,
CA.*
FROM #TransactionMaster TM
CROSS APPLY (SELECT TOP 1 *
FROM TransConsolidated TC
WHERE TC.TransactionID = TM.TransactionID
ORDER BY CRTDTEC DESC,
CRTTIME DESC) CA
Or another possibility (if there is a covering index ordered by TransactionID on all tables) would be to merge join all four tables involved
;WITH CTE
AS (SELECT TM.TransactionID,
MAX(CA.CRTDTEC + CA.CRTTIME + CA.StatusMessage) AS MaxRow
FROM #TransactionMaster TM
LEFT MERGE JOIN #LowTransaction LT
ON LT.TransactionID = TM.TransactionID
LEFT MERGE JOIN #MediumTransaction MT
ON MT.TransactionID = TM.TransactionID
LEFT MERGE JOIN #HighTransaction HT
ON HT.TransactionID = TM.TransactionID
CROSS APPLY (SELECT LT.*
UNION ALL
SELECT MT.*
UNION ALL
SELECT HT.*) CA
GROUP BY TM.TransactionID)
SELECT TransactionID,
SUBSTRING(MaxRow, 1, 8),
SUBSTRING(MaxRow, 9, 6),
SUBSTRING(MaxRow, 16, 80)
FROM CTE
I guess you could do something like this...
SELECT TransactionID, StatusMessage, CRTDTEC, CRTTIME
FROM
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY TransactionID ORDER BY CRTDTEC DESC)
FROM
(
SELECT * FROM #LowTransaction
UNION ALL
SELECT * FROM #MediumTransaction
UNION ALL
SELECT * FROM #HighTransaction
)q
) q2
WHERE rn = 1
Result Set
TransactionID StatusMessage CRTDTEC CRTTIME
1 1 Low 20131213 235959
2 2 Low 20111213 235959
3 3 High 20140101 235959

SQL Server Simple Group by query

I have a simple problem , Although i believe its simple , am not able to figure out the same.
Consider i have the below table with exactly same data as given below :
CREATE TABLE #temp
(
link varchar(255),
number INT,
fname varchar(255)
)
insert into #temp VALUES ('abc',1,'f1')
insert into #temp VALUES ('abc',2,'f2')
insert into #temp VALUES ('abc',3,'f3')
insert into #temp VALUES ('abc',4,'f6')
insert into #temp VALUES ('abc',10,'f100')
insert into #temp VALUES ('abe',-1,'f0')
insert into #temp VALUES ('abe',1,'f1')
insert into #temp VALUES ('abe',2,'f2')
insert into #temp VALUES ('abe',3,'f3')
insert into #temp VALUES ('abe',4,'f6')
insert into #temp VALUES ('abe',20,'f200')
insert into #temp VALUES ('cbe',-1,'f0')
insert into #temp VALUES ('cbe',1,'f1')
insert into #temp VALUES ('cbe',2,'f2')
insert into #temp VALUES ('cbe',3,'f3')
Now for a given link , i need to get the max 'number' and the corresponding 'fname' which has the max 'number' for the given 'link'.
1)Ex : if link is 'abc' , output should be
abc, 10, f100
2)Ex : if link if 'abe' , Output should be
abe, 20, f200
3)Now link can be also given as a pattern , like (link like 'ab%') , so output should be
abc, 10, f100
abe, 20, f200
4)if (link like 'cb%') , so output should be
cbe, 3, f3
Any help in writing this group by query. I have a solution using CAST and string concat like below , but that seems to be in-efficient.
select link,number,fname from #temp
where link like 'ab%' and link+'_'+CAST(number AS varchar(255))
in (select link+'_'+CAST(MAX(number) AS varchar(255)) from #temp
group by link)
Thanks..
Using a self join:
SELECT x.link,
x.number,
x.fname
FROM #temp x
JOIN (SELECT t.link,
MAX(t.number) AS max_number
FROM #temp t
GROUP BY t.link) y ON y.link = x.link
AND y.max_number = x.number
Using a CTE and ROW_NUMBER (SQL Server 2005+):
WITH cte AS (
SELECT x.link,
x.number,
x.fname,
ROW_NUMBER() OVER(PARTITION BY x.link
ORDER BY x.number DESC) rank
FROM #temp x)
SELECT c.link,
c.number,
c.fname
FROM cte c
WHERE c.rank = 1