Update query Get Latest record SQL - sql

I have a tableA in which there are two fields Telephone,CallTime
There is another TableB which have three fields Name,Telephone1 and LastCallTime
I want to update TableB LastCallTime Field from TableA CallTime field whenever the Telephone1 field of TableB matches the Telephone field of TableA.
But there is an issue.
In TableA there are multiple records of Calltime against the Same Telephone.
i.e
123-456-7891 | 2016-01-01 00:02
456-789-8651 | 2015-03-07 02:09
123-456-7891 | 2016-06-10 12:02
like this,
So whenever i run the update query,it update the record with the record that is not latest. Is there anyway i can update the table with the latest calltime.For example the last record from above example which is the latest one.
UPDATE TableA
SET LastCallTime = TableB.CallTime
FROM TableB
WHERE
TableA.Telephone = TableB.Telephone1

You could use a subquery in your UPDATE statement and use TOP to get the latest CallTime:
UPDATE b
SET b.LastCallTime = (
SELECT TOP 1 CallTime
FROM TableA a
WHERE a.Telephone = b.Telephone
ORDER BY a.CallTime DESC
)
FROM TableB b

You can do this with a join and aggregation:
update b
set lastCallTime = a.callTime
from tableB b join
(select telephone, max(callTime) as callTime
from tablea a
group by telephone
) a
on b.telephone = a.telephone;

try this
Update TABLEB B
set B.lastcalltime= A.calltime
(
select
telephone,
calltime,
from ( select
telephone,
calltime,
ROW_NUMBER() OVER(Order by calltime desc) rnum
from
TABLEA )
where rnum=1
) A
where B.telephone1=A.telephone

Related

How do I update a table that references duplicate records?

I have two SQL tables. One gets a reference value from another table which stores a list of Modules and their ID. But these descriptions are not unique. I am trying to remove the duplicates of Table A but I'm not sure how to update Table B to only reference the single values.
Example:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 2 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1 2 QuickReports
-------------------------------- ------------------------------------
I want the results to be the following:
Table A: Table B:
-------------------------------- ------------------------------------
ID Description RefID ID Name
-------------------------------- ------------------------------------
1 Test 1 1 1 QuickReports
-------------------------------- ------------------------------------
2 Test 2 1
--------------------------------
I managed to delete duplicates from table B using the below code but I haven't been able to update the records in Table A. Each table have over 500 records each.
WITH cte AS(
SELECT
Name,
ROW_NUMBER() OVER (
PARTITION BY
Name
ORDER BY
Name
)row_num
FROM ReportmodulesTest
)
DELETE FROM cte
WHERE row_num > 1;
You would need to update table A first, before deleting from table B.
You tagged your question MySQL but that database would not support the delete statement that you are showing. I suspect that you are running SQL Server, so here is how to do it in that database:
update a
set refid = b.minid
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b
on b.id = a.id and b.minid <> a.id
In MySQL, you would phrase the same query as:
update tablea a
from tablea
inner join (select name, id, min(id) over(partition by name) minid from tableb) b on b.id = a.id
set a.refid = b.minid
where b.minid <> a.id
You can update the first table using :
update a join
(select b.*,
min(id) over (partition by name) as min_id
from b
) b
on a.refid = b.id
set a.refid = b.min_id
where a.refid <> b.min_id;
Then, you can delete rows in the second table with a similar logic :
delete b
from b join
(select b.*,
min(id) over (partition by name) as min_id
from b
) bb
on bb.id = b.id
where b.id <> bb.min_id;
I found a solution that has made this process easier. I first use Row_Number to find duplicates in Table A and SELECT INTO a temporary table.
SELECT
a.Id
, a.Name
, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Id DESC) RN
INTO
#TestTable
FROM
TableA a WITH(NOLOCK)
I then JOIN Table A and Table B to see where the ID's match and identify which ID I need to keep and which ID's I need to delete:
SELECT
b.Id
, b.Name
, b.RefId
, ToKeep.Id KeepId
, ToDelete.Id DeleteId
FROM
#TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE ToDelete.RN > 1
Then using a similar statement, I just update the records:
UPDATE b
SET
b.RefId = ToKeep.Id,
FROM #TestTable ToDelete
JOIN TableB b WITH(NOLOCK)
ON b.RefId = ToDelete.Id
JOIN #TestTable ToKeep
ON ToDelete.Name = ToKeep.Name
AND ToKeep.RN = 1
WHERE
ToDelete.RN > 1
Lastly, I can now delete the duplicate records:
DELETE a
FROM #TestTable b
INNER JOIN TableA a
ON b.Id = a.Id
WHERE
b.RN > 1
After this, you can use the same first SELECT statement to ensure that all duplicates are deleted. Just remove the SELECT INTO statement.
Thanks to an anonymous colleague of mine for this solution and hope this helps someone out there.

Using Min in Update statement to get oldest record

I want to update my tableA with tableB but get only those records from table B having the oldest entry
TableA:
name ID
nick 15
john 12
tableB:
ID sportsname createddate
12 tennis 15march2019
14 baseball 15march2019
15 basketball 16march2019
15 cricket 20march2020
15 football 17may2020
My query:
update a
set a.sportsname=b.sportsname
from tablea a join tableb b
on a.id=b.id where b.createdate=( select min(createdate) from tableb )
But this is not giving correct result
update a
set a.name=b.sportsname
from #T a join (select min(createddate) as min_createddate,ID,sportsname from #t2
group by ID,sportsname) b ON b.ID=a.ID
You can use a SUB QUERY to attain this.
I suspect that the problem with your query is that you are using the minimum create date over the entire tableb rather than per id. Although you could fix that using a correlated subquery, I would recommend apply:
update a
set a.sportsname = b.sportsname
from tablea a cross apply
(select top (1) b.*
from tableb b
where a.id = b.id
order by b.createdate asc
) b;
For performance, you want an index on tableb(id, createdate desc, sportname).
You can use FIRST_VALUE() window function:
UPDATE a
SET a.sportsname=b.sportsname
FROM TableA a INNER JOIN (
SELECT DISTINCT ID,
FIRST_VALUE(sportsname) OVER (PARTITION BY ID ORDER BY createddate) sportsname
FROM TableB
) b ON b.ID = a.ID
See the demo.

How to get the records of table A, which are in one row in table B

SELECT ClaimID, CPTCode FROM TABLEA
ClaimId CPTCode
**60 62000**
**60 0213T**
60 99383
60 93230
60 96372
SELECT cpt1,CPT2 FROM TABLEB
cpt1 CPT2
**62000 0213T**
**62000 0230T**
62000 0216T
62000 0228T
SELECT the record from tableA only that which is at same row in tableB
Result should be
60 62000
60 0213T
I think this does what you want:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where b.cpt1 = a.cptcode
) or
exists (select 1
from tableb b
where b.cpt2 = a.cptcode
);
This query can take advantage of two indexes: tableb(cpt1) and tableb(cpt2).
You can write this as:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where a.cptcode in (b.cpt1, b.cpt2)
);
However, this version is much harder to optimize.
try this-
select obj.ClaimID, obj.CPTCode from (
select row_number() as row_noA, ClaimID, CPTCode FROM TABLEA
join
select row_number() as row_noB, cpt1,CPT2 FROM TABLEB
on TABLEA.CPTCode = TABLEB.CPT2 and TABLEA.row_noA = TABLEB.row_noB
)obj
join two tables and match each row using same row number and get the output

SQL select newst data in 2 table same primary key

I have two same table:
A(id, ..., modified_date)
and B(id, ..., modified_date). I need to select the record with same id but modified_date larger.
How can I write the SQL? Please help.
Example:
Table A
id | user name | email | modified date
------------------------------------------------
1 | Anne | ana#gmail.com | 2016/12/20
And table B
id | user name | email | modified date
------------------------------------------------
1 | Anne Jr, | ana_j#gmail.com | 2017/01/20
With two record has same id, I need to get the record with modified_date larger. The example above, with id = 1, I need to select the record has modified_date = 2017/01/20
You can do a JOIN and then ORDER BY modified_date column like
select t1.id,t1.modified_date
from table1 t1 join table2 t2 on t1.id = t2.id
order by t1.modified_date desc;
If you need data from the B table, you can use :
SELECT b.*
FROM B b
WHERE b.id = a.id
AND b.modified_date > a.modified.date
Similarly, if you need data from the A table you can use :
SELECT a.*
FROM A a
WHERE a.id = b.id
AND a.modified_date > b.modified.date
In case there are multiple records which fit the criteria and you need only the one record which has the greatest modified date value then you can use :
SELECT TOP 1 a.*
FROM A a
WHERE a.id = b.id
AND a.modified_date > b.modified.date
ORDER BY a.modified_date
OR
SELECT TOP 1 b.*
FROM B b
WHERE b.id = a.id
AND b.modified_date > a.modified.date
ORDER BY b.modified_date
Hope this helps!!!
You can try using a CASE expression on SQL Server
SELECT A.id,A.other_columns,
(CASE WHEN a.modified_date > b.modified_date THEN a.modified_date ELSE b.modified_date END) as modified_date
FROM [A] INNER JOIN [B] on A.id=B.id
If you want the higher of those two values, then use greatest() with a join:
select ta.id,
greatest(ta.modifed_date, tb.modified_date)
from table_a ta
join table_b tb on ta.id = tb.id;
If you want all columns from the row with the later date, you can use a case statement:
select ta.id,
case
when ta.modified_date > tb.modified_date then ta.email
else tb.email
end as email,
case
when ta.modifed_date > tb.modified_date then ta.user_name
else tb.user_name
end as user_name,
greatest(ta.modified_date, tb.modified_date) as modified_date
from table_a ta
join table_b tb on ta.id = tb.id;

getting top row of joined table

I have 2 tables, tableA and tableB
tableA - id int
name varchar(50)
tableB - id int
fkid int
name varchar(50)
Both tables are joined between id and fkid.
Below are sample rows from tableA
Below is output from tableB
I want to join both tables and get only top row of joined table. So output will be like below
Id Name fkid
1 P1 1
2 P2 4
3 P3 null
Here is Sql fiddle
How can i achieve this with single query? I know that i can loop through in my .net code and retrieve top rows. But i want it in single query.
select a.id,a.name,b.fid from tableA a left join
(
select min(id) fid ,fkid from tableB group by fkid
)b
on a.id = b.fkid
select ta.id, ta.name, min(tb.id) from tableA ta
left join tableB tb on tb.fkid=ta.id
group by ta.id, ta.name
You could do this:
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY fkID ORDER BY ID) AS RowNbr,
tableB.*
FROM
tableB
)
SELECT
*
FROM
tableA
LEFT JOIN CTE
ON CTE.fkID=tableA.id
AND CTE.RowNbr=1
Demo here
Or without window function. Like this:
SELECT
*
FROM
tableA
LEFT JOIN
(
SELECT
ROW_NUMBER() OVER(PARTITION BY fkID ORDER BY ID) AS RowNbr,
tableB.*
FROM
tableB
) as tbl
ON tbl.fkID=tableA.id
AND tbl.RowNbr=1
Demo here
Update:
The reason why I choose to do it with row_number is that if there is more columns in tableB then the example. Then there is no need for additional aggregate if you want to show more columns. For me personally it is more clear with an order by on the ID