Need compare tables utility for SQL Server - sql-server

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

Related

left join and get the maximum datetime value

I have two tables ,
Table 1
Id Name
===========
1 Name1
2 Name2
3 Name3
Table 2
Id Tb1Id DateTime
=======================
1 1 20-09-2017
2 1 01-09-2018
3 2 01-09-2016
4 2 02-09-2015
5 3 06-09-2016
6 3 10-09-2019
I want to join those two tables by where Table1.Id = Table2.Tb1Id and get the maximum datetime value from Table2. The result should be like this .
Id Name DateTime
========================
1 Name1 01-09-2018
2 Name2 01-09-2016
3 Name3 10-09-2019
Try This
DECLARE #Table1 AS TABLE(Id INT,Name VARCHAR(20))
INSERT INTO #Table1
SELECT 1,'Name1' UNION ALL
SELECT 2,'Name2' UNION ALL
SELECT 3,'Name3'
DECLARE #Table2 AS TABLE(Id INT, Tb1Id INT,[DateTime] DATETIME)
INSERT INTO #Table2
SELECT 1,1,'2017-09-20' UNION ALL
SELECT 2,1,'2018-09-01' UNION ALL
SELECT 3,2,'2016-09-01' UNION ALL
SELECT 4,2,'2015-09-02' UNION ALL
SELECT 5,3,'2016-09-06' UNION ALL
SELECT 6,3,'2019-09-10'
SELECT t2.Tb1Id AS Id,
t1.Name,
MAX(t2.[DateTime]) AS [DateTime]
FROM #Table1 AS T1
INNER JOIN #Table2 AS t2
ON T1.Id = t2.Tb1Id
GROUP BY
t2.Tb1Id,
t1.Name
Result
Id Name DateTime
-----------------------------------
1 Name1 2018-09-01 00:00:00.000
2 Name2 2016-09-01 00:00:00.000
3 Name3 2019-09-10 00:00:00.000

SQL Server - Split a date range by a given date

I have a table that stores an Id and an effective period indicating when it is active
PortfolioId StartDate EndDate
1 2018-01-01 00:00:00.000 2018-05-31 00:00:00.000
2 2017-01-01 00:00:00.000 2018-05-31 00:00:00.000
I have another table that stores a component related to the above Id and that too has an effective period. Table 2 can have more that on entry for any given entry in table 1.
PortfolioComponentId PortfolioId SplitDate
1 1 2018-02-28 00:00:00.000
2 1 2018-03-31 00:00:00.000
3 2 2017-03-31 00:00:00.000
4 2 2017-09-20 00:00:00.000
5 2 2018-01-15 00:00:00.000
I have a period where I am running the query for
i.e
StartDate : 30-JUN-2017
End date : 15-MAY-2018
I have looking for a result like the below, where data in table 1 is split based on the data from table 2
PortfolioId StartDate EndDate
1 2018-01-01 00:00:00.000 2018-02-28 00:00:00.000
1 2018-03-01 00:00:00.000 2018-03-31 00:00:00.000 - Starts from End date + 1 from the prev row
1 2018-04-01 00:00:00.000 2018-05-15 00:00:00.000
2 2017-06-30 00:00:00.000 2017-09-20 00:00:00.000 - Starts from Seach date [Portfolio component Id 3 ignored as it falls outside of search date range]
2 2017-09-21 00:00:00.000 2018-01-15 00:00:00.000
2 2018-01-16 00:00:00.000 2018-05-15 00:00:00.000 - Ends by seach end date
Data setup - In case it helps
DECLARE #SearchStartDate DATETIME = '30-JUN-2017'
DECLARE #SearchEndDate DATETIME = '15-MAY-2018'
DECLARE #Portfolio TABLE
(
PortfolioId INT PRIMARY KEY IDENTITY(1,1),
StartDate DATETIME,
EndDate DATETIME
)
INSERT INTO #Portfolio
SELECT '01-JAN-2018', '31-MAY-2018'
INSERT INTO #Portfolio
SELECT '01-JAN-2017', '31-MAY-2018'
DECLARE #PortfolioComponents TABLE
(
PortfolioComponentId INT PRIMARY KEY IDENTITY(1,1),
PortfolioId INT,
SplitDate DATETIME
)
INSERT INTO #PortfolioComponents
SELECT 1, '28-FEB-2018'
INSERT INTO #PortfolioComponents
SELECT 1, '31-MAR-2018'
INSERT INTO #PortfolioComponents
SELECT 2, '31-MAR-2017'
INSERT INTO #PortfolioComponents
SELECT 2, '20-SEP-2017'
INSERT INTO #PortfolioComponents
SELECT 2, '15-JAN-2018'
SELECT * from #Portfolio
SELECT * from #PortfolioComponents
I believe I have got a result close to what I want, though not
the most ideal approach
the best approach from a performance perspective
DECLARE #Temp TABLE (BenchmarkDate Datetime, ComponentType int, PortfolioId INT)
INSERT INTO #Temp
SELECT StartDate , 1, PortfolioId FROM #Portfolio
UNION
SELECT EndDate , 2, PortfolioId FROM #Portfolio
INSERT INTO #Temp
SELECT SplitDate , 2, PortfolioId FROM #PortfolioComponents
UNION
SELECT SplitDate + 1 , 1, PortfolioId FROM #PortfolioComponents
DECLARE #Results TABLE
(
Id INT IDENTITY(1,1),
StartDate DATETIME,
EndDate DATETIME,
PortfolioId INT
)
INSERT INTO #Results
SELECT rset1.BenchmarkDate [Startdate],
( SELECT MIN(rset2.BenchmarkDate)
FROM #Temp rset2
WHERE rset2.ComponentType = 2
AND rset2.BenchmarkDate > rset1.BenchmarkDate
AND rset1.PortfolioId = rset2.PortfolioId) [Enddate],
rset1.PortfolioId
FROM #Temp rset1
WHERE rset1.ComponentType = 1
ORDER BY rset1.PortfolioId, rset1.BenchmarkDate
SELECT
CASE WHEN (#SearchStartDate BETWEEN StartDate AND EndDate ) THEN #SearchStartDate ELSE StartDate END StartDate,
CASE WHEN (#SearchEndDate BETWEEN StartDate AND EndDate) THEN #SearchEndDate ELSE EndDate END EndDate,
PortfolioId ,
(
SELECT PortfolioComponentId
FROM #PortfolioComponents pc
WHERE
(pc.PortfolioID = r.PortfolioId AND
(DATEADD(d, 1, pc.SplitDate) = r.StartDate ))
) PortfolioComponentId
FROM #Results r
WHERE
(#SearchStartDate < StartDate AND #SearchStartDate < EndDate AND #SearchEndDate > EndDate)
OR
(#SearchEndDate BETWEEN StartDate AND EndDate)
OR
(#SearchStartDate BETWEEN StartDate AND EndDate )

Please advise my the stored procedure which is group by and total which different criteria

I have answered one of the interview questions as below.
There are two tables (employee and Department).
Show report No. of people(count) and total salary where IT Dept. salary from 250 to 500 and Sales Dept. salary from 250 to 1000 and Marketing Dept. salary from 250 to 1500.
Sample expected result below
Marketing 0 0.00
Information Technology 1 250.00
Sales 2 1200.00
Employee table
EmpID EmpName DeptID Salary
1 Mike 1 1000.00
2 Paul 1 1500.00
3 John 1 2000.00
4 Joe 2 500.00
5 Kim 3 2000.00
6 Lim 3 2500.00
7 Sam 2 700.00
8 Mario 1 250.00
Department table
DeptID DeptCode DeptName
1 IT Information Technology
2 ST Sales
3 MT Marketing
My Answer:
ALTER PROCEDURE [dbo].[TheseAndThat]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT dd.DeptName, ISNULL(TT.c,0) AS StaffCount , ISNULL(TT.s,0) AS TotalSalary FROM [dbo].[Department] dd
LEFT JOIN
(
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 500 AND d.DeptID = 1
GROUP BY e.DeptID, d.DeptCode
UNION
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 1000 AND d.DeptID = 2
GROUP BY e.DeptID, d.DeptCode
UNION
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 1500 AND d.DeptID = 3
GROUP BY e.DeptID, d.DeptCode
) TT
ON dd.DeptCode = TT.dcode
ORDER BY TT.c
END
I'm not sure my answer is correct. However, the result seems to be ok.
Please advise.
If I was you I will go this this query (only 1 time scan to employee table)
SELECT d.DeptName, ISNULL(e.NoEmp,0) AS NoEmp, ISNULL(SumSalary,0) AS SumSalary
FROM [dbo].[Department] AS d
LEFT JOIN (
SELECT DeptID, COUNT(EmpID) As NoEmp, SUM (Salary) AS SumSalary
FROM [dbo].[Employee]
WHERE Salary BETWEEN 250 AND CASE WHEN DeptID = 1 THEN 500
WHEN DeptID = 2 THEN 1000
WHEN DeptID = 3 THEN 1500
END
GROUP BY DeptID) AS e ON d.DeptID = e.DeptID
WHERE d.DeptID IN(1,2,3)
First, the code to setup temp tables:
declare #employees table
(
EmpID int,
EmpName varchar(100),
DeptID int,
Salary decimal
)
declare #departament table
(
DeptID int,
DeptCode char(2),
DeptName varchar(100)
)
insert into #employees values (1,'Mike',1,1000.00)
insert into #employees values (2,'Paul',1,1500.00)
insert into #employees values (3,'John',1,2000.00)
insert into #employees values (4,'Joe',2,500.00)
insert into #employees values (5,'Kim',3,2000.00)
insert into #employees values (6,'Lim',3,2500.00)
insert into #employees values (7,'Sam',2,700.00)
insert into #employees values (8,'Mario',1,250.00)
insert into #departament values (1, 'IT', 'Information Technology')
insert into #departament values (2, 'ST', 'Sales')
insert into #departament values (3, 'MT', 'Marketing')
Now, the report:
select DeptName, COALESCE(d2.DeptID, 0), COALESCE(Salaries,0) from #departament d2
left join
(
select COUNT(*) as DeptID, SUM(Salary) as Salaries from #departament d
inner join #employees e on d.DeptID = e.DeptID
where
(d.DeptID = 1 and e.Salary between 250 and 500)
or
(d.DeptID = 2 and e.Salary between 250 and 1000)
or
(d.DeptID = 3 and e.Salary between 250 and 1500)
group by d.DeptID) as sums on sums.DeptID = d2.DeptID
An alternative (uses the same temp tables as #GustavoF answer):
DECLARE #Input TABLE( DeptID INT, SalaryRangeMin decimal, SalaryRangeMax decimal )
INSERT INTO #Input
VALUES
( 1, 250, 500),
( 2 ,250 ,1000 ),
( 3 ,250 , 1500 )
SELECT D.DeptName, COUNT(EmpID) as EmployeeCount, ISNULL( SUM( e.Salary ), 0.0 ) as TotalSalary
FROM #Input AS I
INNER JOIN #departament AS D ON I.DeptID = D.DeptID
LEFT JOIN #Employees AS E ON I.DeptID = E.DeptID AND E.Salary BETWEEN I.SalaryRangeMin AND I.SalaryRangeMax
GROUP BY E.DeptID, D.DeptCode, D.DeptName
ORDER BY TotalSalary ASC
Output:
DeptName EmployeeCount TotalSalary
--------------------------- ------------- -------------
Marketing 0 0
Information Technology 1 250
Sales 2 1200

JOIN on multilple rows to SELECT only TOP row in SQL Sever

I have a table which has only 1 row per ID/Date while the other one can have overlapping ID/Dates. I need to JOIN them in such a way that only top row is selected (actually any row from duplicates table is fine!). Its fairly easy to do this in 2 steps (Insert & Update) but I'm looking if it can be done in a single step.
CREATE TABLE #Row1Each (ID VARCHAR(10), Date_ DATETIME, Value FLOAT) INSERT INTO #Row1Each SELECT 'AAPL', '1/10/2015', 100 INSERT INTO #Row1Each SELECT 'MSFT', '1/10/2015', 20
CREATE TABLE #Table1 (ID VARCHAR(10), Date_ DATETIME, Qty FLOAT) INSERT INTO #Table1 SELECT 'AAPL', '1/10/2015', 55000
CREATE TABLE #Duplicates (ID VARCHAR(10), StartDate DATETIME, EndDate DATETIME, Quote FLOAT) INSERT INTO #Duplicates SELECT 'AAPL', '1/2/2015', '12/31/2016', 0.1 INSERT INTO #Duplicates SELECT 'AAPL', '1/4/2015', '10/05/2016', 0.11
/*
AAPL 2015-01-10 00:00:00.000 100
MSFT 2015-01-10 00:00:00.000 20
AAPL 2015-01-10 00:00:00.000 55000
AAPL 2015-01-02 00:00:00.000 2016-12-31 00:00:00.000 0.1
AAPL 2015-01-04 00:00:00.000 2016-10-05 00:00:00.000 0.1
*/
SELECT A.*
, B.Qty
, C.Quote
FROM #Row1Each A
LEFT JOIN #Table1 B ON B.ID = A.ID
AND B.Date_ = A.Date_
LEFT JOIN #Duplicates C ON C.ID = A.ID
AND A.Date_ BETWEEN C.StartDate AND C.EndDate
DROP TABLE #Row1Each DROP TABLE #Table1 DROP TABLE #Duplicates
/* Desired output
AAPL 2015-01-10 00:00:00.000 100 55000 0.1
MSFT 2015-01-10 00:00:00.000 20 NULL NULL
*/
You can do this using APPLY.
SELECT
r.Id,
r.Date_,
r.Value,
t.Qty,
d.Quote
FROM #Row1Each r
LEFT JOIN #Table1 t
ON t.ID = r.ID
AND t.Date_ = r.Date_
OUTER APPLY(
SELECT TOP 1 *
FROM #Duplicates d
WHERE
d.ID = r.ID
AND r.Date_ BETWEEN d.StartDate AND d.EndDate
ORDER BY EndDate DESC -- Returns Top 1 Based on EndDate
)d

Move row from one table to another?

I have two tables with the same column definitions. I need to move (not copy) a row from one table to another. Before I go off and use INSERT INTO/DELETE (in a transaction), is there a smarter way?
SQL Server 2005
for SQL Server 2005 and up, try the OUTPUT Clause (Transact-SQL) clause:
DELETE OldTable
OUTPUT DELETED.col1, DELETED.col2...
INTO NewTable
WHERE ID=...
Working example:
DECLARE #OldTable table(col1 int, col2 varchar(5), col3 char(5), col4 datetime)
DECLARE #NewTable table(col1 int, column2 varchar(5), col3 int , col_date char(23), extravalue int, othervalue varchar(5))
INSERT #OldTable VALUES (1 , 'AAA' ,'A' ,'1/1/2010' )
INSERT #OldTable VALUES (2 , 'BBB' ,'12' ,'2010-02-02 10:11:22')
INSERT #OldTable VALUES (3 , 'CCC' ,null ,null )
INSERT #OldTable VALUES (4 , 'B' ,'bb' ,'2010-03-02' )
DELETE #OldTable
OUTPUT DELETED.col1
,DELETED.col2
,CASE
WHEN ISNUMERIC(DELETED.col3)=1 THEN DELETED.col3
ELSE NULL END
,DELETED.col4
,CONVERT(varchar(5),DELETED.col1)+'!!'
INTO #NewTable (col1, column2, col3, col_date, othervalue)
OUTPUT 'Rows Deleted: ', DELETED.* --this line returns a result set shown in the OUTPUT below
WHERE col1 IN (2,4)
SELECT * FROM #NewTable
OUTPUT:
col1 col2 col3 col4
-------------- ----------- ----- ----- -----------------------
Rows Deleted: 2 BBB 12 2010-02-02 10:11:22.000
Rows Deleted: 4 B bb 2010-03-02 00:00:00.000
(2 row(s) affected)
col1 column2 col3 col_date extravalue othervalue
----------- ------- ----------- ----------------------- ----------- ----------
2 BBB 12 Feb 2 2010 10:11AM NULL 2!!
4 B NULL Mar 2 2010 12:00AM NULL 4!!
(2 row(s) affected)
You can try Insert into abc (a,b,c)
select(a,b,c) from def
doing above so will insert column a, b,c of def into column a,b,c of abc. after inserting run a delete table, drop table or truncate whatever is your criteria.
sample is:
Begin
Begin try
Begin Transaction
Insert into emp(name, department, salary)
Select empName,empDepartment,empSal from employees
Where employees.empID = 211
Truncate table employees
End Transaction
End try
Begin Catch
if ##Error > 0
Rollback Transaction
End Catch
End
There is no such thing as a MOVE command in SQL.
You'll have to first insert from table 1 to table 2
Then remove the copy from table 1.
No, you are pretty much stuck with insert and delete wrapped inside a transaction
INSERT dbo.newtable(
name,
department,
Salary
) SELECT
name,
FirstName,
Lastname
FROM (
DELETE dbo.oldtable
OUTPUT
DELETED.name,
DELETED.department,
DELETED.Salary
WHERE ID IN ( 1001, 1003, 1005 )
) AS RowsToMove
SELECT * FROM dbo.newtable
SELECT * FROM dbo.oldtable

Resources