Reputation: 71
I have a table named "ROSTER" and in this table I have 22 columns.
I want to query and compare any 2 rows of that particular table with the purpose to check if each column's values of that 2 rows are exactly the same. ID column always has different values in each row so I will not include ID column for the comparing. I will just use it to refer to what rows will be used for the comparison.
If all column values are the same: Either just display nothing (I prefer this one) or just return the 2 rows as it is.
If there are some column values not the same: Either display those column names only or display both the column name and its value (I prefer this one).
Example:
ROSTER Table:
ID | NAME | TIME |
---|---|---|
1 | N1 | 0900 |
2 | N1 | 0801 |
Output:
ID | TIME |
---|---|
1 | 0900 |
2 | 0801 |
OR
Display "TIME"
Note: Actually I'm okay with whatever result or way of output as long as I can know in any way that the 2 rows are not the same.
What are the possible ways to do this in SQL Server?
I am using Microsoft SQL Server Management Studio 18, Microsoft SQL Server 2019-15.0.2080.9
Upvotes: 2
Views: 10722
Reputation: 983
for future searchers - perfect implementation of Yitzhak Khabinsky answer / John Cappelletti idea
with simple usage
exec Helper_GetTableRowsDiff 'DBName','TableName','IdColumnName',@FirstId,@secondId
Create PROCEDURE [dbo].[Helper_GetTableRowsDiff] @DatabaseName varchar(100),@TableName varchar(100),@KeyColumnName varchar(100), @compareSourceKey int , @compareDestKey int
AS
BEGIN
SET NOCOUNT ON;
declare @compareSourceKeyStr varchar(100)
set @compareSourceKeyStr =(cast(@compareSourceKey as varchar(100)))
declare @compareDestKeyStr varchar(100)
set @compareDestKeyStr =(cast(@compareDestKey as varchar(100)))
declare @sql nvarchar(max) =N'
if not exists (select top(1) * from '+@DatabaseName+'..'+@TableName+' where '+@KeyColumnName+'='+@compareSourceKeyStr+')
begin
THROW 51000, ''The SOURCE record does not exist in table.'', 1;
end
if not exists (select top(1) * from '+@DatabaseName+'..'+@TableName+' where '+@KeyColumnName+'='+@compareDestKeyStr+')
begin
THROW 51000, ''The DEST record does not exist in table.'', 1;
end
declare @DiffT table ( column_name varchar(100) , source_value varchar(max), dest_value varchar(max) )
insert into @DiffT
SELECT
[key] AS [column]
,source_Value = MAX( CASE WHEN Src=1 THEN Value END)
,target_Value = MAX( CASE WHEN Src=2 THEN Value END)
FROM (
SELECT Src=1,'+@KeyColumnName+' ,B.*
FROM '+@DatabaseName+'..'+@TableName+' AS A
CROSS APPLY ( SELECT [Key] ,Value
FROM OpenJson( (SELECT A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES))
) AS B
WHERE '+@KeyColumnName+'='+@compareSourceKeyStr+'
UNION ALL
SELECT Src=2 ,id = '+@compareSourceKeyStr+' ,B.*
FROM '+@DatabaseName+'..'+@TableName+' AS A
CROSS APPLY ( SELECT [Key] ,Value
FROM OpenJson( (SELECT A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES))
) AS B
WHERE '+@KeyColumnName+'='+@compareDestKeyStr+'
) AS A
GROUP BY '+@KeyColumnName+', [key]
HAVING isnull(MAX(CASE WHEN Src=1 THEN Value END),''NULL'')
<> isnull(MAX(CASE WHEN Src=2 THEN Value END),''NULL'')
AND [key] <> '''+@KeyColumnName+''' -- exclude this PK column
ORDER BY '+@KeyColumnName+', [key];
'
set @sql = @sql + ' select * from @difft '
EXEC sp_ExecuteSQL @sql
END
Upvotes: 1
Reputation: 22187
Please try the following solution based on the ideas of John Cappelletti. All credit goes to him.
SQL
-- DDL and sample data population, start
DECLARE @roster TABLE (ID INT PRIMARY KEY, NAME VARCHAR(10), TIME CHAR(4));
INSERT INTO @roster (ID, NAME, TIME) VALUES
(1,'N1','0900'),
(2,'N1','0801')
-- DDL and sample data population, end
DECLARE @source INT = 1
, @target INT = 2;
SELECT id AS source_id, @target AS target_id
,[key] AS [column]
,source_Value = MAX( CASE WHEN Src=1 THEN Value END)
,target_Value = MAX( CASE WHEN Src=2 THEN Value END)
FROM (
SELECT Src=1
,id
,B.*
FROM @roster AS A
CROSS APPLY ( SELECT [Key]
,Value
FROM OpenJson( (SELECT A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES))
) AS B
WHERE id=@source
UNION ALL
SELECT Src=2
,id = @source
,B.*
FROM @roster AS A
CROSS APPLY ( SELECT [Key]
,Value
FROM OpenJson( (SELECT A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES))
) AS B
WHERE id=@target
) AS A
GROUP BY id, [key]
HAVING MAX(CASE WHEN Src=1 THEN Value END)
<> MAX(CASE WHEN Src=2 THEN Value END)
AND [key] <> 'ID' -- exclude this PK column
ORDER BY id, [key];
Output
+-----------+-----------+--------+--------------+--------------+
| source_id | target_id | column | source_Value | target_Value |
+-----------+-----------+--------+--------------+--------------+
| 1 | 2 | TIME | 0900 | 0801 |
+-----------+-----------+--------+--------------+--------------+
Upvotes: 5
Reputation: 521457
A general approach here might be to just aggregate over the entire table and report the state of the counts:
SELECT
CASE WHEN COUNT(DISTINCT ID) = COUNT(*) THEN 'Yes' ELSE 'No' END AS [ID same],
CASE WHEN COUNT(DISTINCT NAME) = COUNT(*) THEN 'Yes' ELSE 'No' END AS [NAME same],
CASE WHEN COUNT(DISTINCT TIME) = COUNT(*) THEN 'Yes' ELSE 'No' END AS [TIME same]
FROM yourTable;
Upvotes: 2