How to find out which column value changed in SQL - sql

I have two tables with 100 of columns, and I want to find out how which column value changed in those two tables. I can find which row has changed but I want to which column was changed not the whole row.
Table 1
name ID Dept Email EmpID Salary Gender
Rob 1 IT I#i.com 100 5000 M
Mary 2 HR M#m.com 20 6000 F
Jack 3 IT J#j.com 30 7000 M
Harry 4 Fin h#h.com 50 5000 M
Jay 5 Eng Null 60 5000 M
Ken 6 HR K#K.com 70 Null M
Table 2
name ID Dept Email EmpID Salary Gender
Rob 1 IT I#i.com 100 5000 M
Mary 2 HR M#m.com 20 6000 F
Jack 3 IT J#j.com 150 7000 M
Harry 4 Fin h#h.com 50 Null M
Jay 5 Eng Jy#jy.com 60 5000 M
Ken 6 HR K#K.com 70 6000 M
As we can see Email for Jay existed, Emp ID for Jack was changed, Salary for Harry is null in Table 2 and Salary was added for Ken.
Expected Output (If this is possible, As I don't want to see all the row values, I just want to see which column value changed, as ID is a unique identifier, I would like to know which ID did column value change)
ID columnvaluechanged
3 EmpID
4 Salary
5 Email
6 Salary

Here is one way using unpivot technique
;WITH tab1
AS (SELECT id,
colName,
value
FROM Yourtable1
CROSS apply (VALUES (NAME,'name'),(Dept,'Dept'),(Email,'Email'),
(Cast(EmpID AS VARCHAR(50)),'EmpID'),
(Cast(Salary AS VARCHAR(50)),'Salary'),
(Gender,'Gender')) cs (value, colName)),
tab2
AS (SELECT id,
colName,
value
FROM Yourtable2
CROSS apply (VALUES (NAME,'name'),(Dept,'Dept'),(Email,'Email'),
(Cast(EmpID AS VARCHAR(50)),'EmpID'),
(Cast(Salary AS VARCHAR(50)),'Salary'),
(Gender,'Gender')) cs (value, colName))
SELECT t1.ID,
t1.colName,
t1.value AS tab1_value,
t2.value AS tab2_value
FROM tab1 t1
INNER JOIN tab2 t2
ON t1.ID = t2.ID
AND t1.colName = t2.colName
AND Isnull(t1.value, '') <> Isnull(t2.value, '')
Demo

Related

Combining two tables with some matching IDs but not all

So I have two tables. Both tables have some matching IDs but not all IDs are in each table. I need to be able to combine the two. Example down below:
Table 1
Name Money ID
Bob 500 1
Nick 600 2
Kim 575 3
Table 2
Name Fees ID
Bob 200 1
Nick 250 2
Ian 100 4
OUTPUT
Name Money Fees ID
Bob 500 200 1
Nick 600 250 2
Kim 575 3
Ian 100 4
This is a simple full outer join with some coalesce to keep the values in a single column:
select coalesce(tbl1.[Name], tbl2.[Name]) [Name]
, tbl1.[Money]
, tbl2.Fees
, coalesce(tbl1.ID, tbl2.ID) ID
from tbl1
full outer join tbl2
on tbl1.ID = tbl2.ID
order by ID

Join UNNESTED Values GoogleSQL

I have the following scenario
Table1
Row
Col1
Col2
1
[12345, 32145, 647834]
abcd
2
[23145, 11111, 12345]
efg
3
[647834, 23145]
zyx
4
[11111]
cba
Table2
Row
valuesforcol1
names
1
12345
Jon
2
32145
Bob
3
647834
Jack
4
23145
Dave
5
11111
Alice
Result
Row
Col1
Names
1
[12345, 32145, 647834]
[Jon, Bob, Jack]
2
[23145, 11111, 12345]
[Dave, Alice, Jon]
3
[647834, 23145]
[Jack, Dave]
4
[11111]
[Alice]
How do I do that?
If you were using BigQuery, then the logic would look like:
select t1.*,
(select array_agg(t2.name order by n) as names
from unnest(t1.col1) el with offset n join
table2 t2
on el = t2.valuesforcol1
) as names
from table1 t1

Select Row from Other Table if Doesn't Exist in Current Table

I have two tables:
Table1
id name qty
1 Tedd 6
2 Jim 7
3 Sally 8
4 Victoria 1
Table2
id name qty
1 Tedd 2
2 Jim 2
3 Sally 2
4 Victoria 1
5 Alex 9
I need to select all the rows from Table1. However, if a row exists in Table2 that doesn't exist in Table1, I need to include that in the result set. So, in the end, my query should return this:
id name qty
1 Tedd 6
2 Jim 7
3 Sally 8
4 Victoria 1
5 Alex 9
Is there a way I can do this? Thanks.
You can use a FULL OUTER JOIN:
select
coalesce(t1.id, t2.id) id,
coalesce(t1.name, t2.name) name,
coalesce(t1.qty, t2.id) qty
from table1 t1
full outer join table2 t2
on t1.id = t2.id
See SQL Fiddle with Demo

Please advise SQL Update issue

I have a SQL database with two tables
TableA (ID, State, Value)
1 England 20
2 France 50
3 USA 40
4 ........
5 ........
and
TableB (ID, username, age, stateID)
1 John 15 1
2 Adam 20 2
3 Jane 40 3
4 Scott 50 1
5 Edwin 60 2
6 Alex 20 3
7 Olsen 30 1
8 ...........
9 ...........
What I need is to update TableB by setting the age for all users
from England to be 20
and from France to be 50
and so on...
update tableB
set age = (select tableA.value from tableA where tableA.StateID=TableB.id)
I like this form below:
update b set
age = a.value
from tableB b
join tableA a on a.id = b.stateId
because you can write it this way (at last in SQL Server Management Studio):
update b set
age = a.value
--select b.age, a.value, b.*, a.*
from tableB b
join tableA a on a.id = b.stateId
then highlight the part from select ... to the end of query and execute it (F5) to check what you are going to change (value before and after).

Tricky SQL - Select non-adjacent numbers

Given this data on SQL Server 2005:
SectionID Name
1 Dan
2 Dan
4 Dan
5 Dan
2 Tom
7 Tom
9 Tom
10 Tom
How would I select records where the sectionID must be +-2 or more from another section for the same name.
The result would be:
1 Dan
4 Dan
2 Tom
7 Tom
9 Tom
Thanks for reading!
SELECT *
FROM mytable a
WHERE NOT EXISTS
(SELECT *
FROM mytable b
WHERE a.Name = b.Name
AND a.SectionID = b.SectionID + 1)
Here's LEFT JOIN variant of Anthony's answer (removes consecutive id's from the results)
SELECT a.*
FROM mytable a
LEFT JOIN mytable b ON a.Name = b.Name AND a.SectionID = b.SectionID + 1
WHERE b.SectionID IS NULL
EDIT: Since there is another interpretation of the question (simply getting results where id's are more than 1 number apart) here is another attempt at an answer:
WITH alternate AS (
SELECT sectionid,
name,
EXISTS(SELECT a.sectionid
FROM mytable b
WHERE a.name = b.name AND
(a.sectionid = b.sectionid-1 or a.sectionid = b.sectionid+1)) as has_neighbour,
row_number() OVER (PARTITION by a.name ORDER BY a.name, a.sectionid) as row_no
FROM mytable a
)
SELECT sectionid, name
FROM alternate
WHERE row_no % 2 = 1 OR NOT(has_neighbour)
ORDER BY name, sectionid;
gives:
sectionid | name
-----------+------
1 | Dan
4 | Dan
2 | Tom
7 | Tom
9 | Tom
Logic: if a record has neighbors with same name and id+/-1 then every odd row is taken, if it has no such neighbors then it gets the row regardless if it is even or odd.
As stated in the comment the condition is ambiguous - on start of each new sequence you might start with odd or even rows and the criteria will still be satisfied with different results (even with different number of results).