Update fields in a SQL Server table sequentially - sql

I have a table AoObject with a column DisplayName. In name are values like Joe Smith, John Smith, Jane Smith. This goes on for thousands of records.
I want to update the table so that starting with record one up to the last record the value of DisplayName is like this. Joe Smith = Customer1, John Smith = Customer2, Jane Smith = Customer3... and so on until all the name columns sequentially say Customer with a number appended to it and not the current value of the column.
This is SQL Server 2012
***The examples below don't work and I've amended my question. My fault for not including enough details. The table is called Aoobject. The field that needs to be changed is actually called DisplayName. I need to filter the result set with something like the following.
Where ObjectDescription in ('Portfolio Description', 'Portfolio Group Description')

This seems like a bad idea -- the "customer number" should be put into a separate column. It is not part of the name. However, it is easy to do:
with toupdate as (
select t.*, row_number() over (order by recordnum) as seqnum
from table t
)
update toupdate
set fullname = fullname + ' Customer' + cast(seqnum as varchar(255));
I am assuming that you have some numbering for the records (recordnum) because the question says "with record one up to the last record".
EDIT:
If you want the names to be unique, then append a number only for duplicate names.
with toupdate as (
select t.*,
row_number() over (partition by fullname order by recordnum) as fn_seqnum,
count(*) over (partition by fullname) as fn_cnt
from table t
)
update toupdate
set fullname = fullname + ':' + cast(fn_seqnum as varchar(255));
where fn_cnt > 1;
This appends a unique number only when it needs to (for fullnames that have duplicates). And, it keeps the cardinality of the number as low as possible, so only one digit should suffice for the suffix.

Something like this will do.
Hope the Customer name is unique.
;WITH cte_emp AS
(
SELECT CustomerName , ROW_NUMBER() over (order by CustomerName) slno
FROM Customer
)
UPDATE t SET CustomerName = 'Customer ' + cast(slno as varchar)
FROM Customer t
INNER JOIN cte_emp c ON t.CustomerName = c.CustomerName

Related

How can I write this using SQL?

I need to write a code in sql that writes "del_row" in the column "Adjustment_name" when there are duplicated Id_numbers (e.g:234566) but just when one of the values in Phone_number start with A and other one start with B and in that case, it will write "del_row" just in the row in which the value in column "Phone_number" starts with "B". Imagine that I have two duplicated id_numbers and in one of them, the Phone_number starts with A and in the other row starts with "C". In this last situation, I don't want to write anything.
Id_number
Phone_number
Adjustment_name
234566
A5258528564
675467
A1147887422
675534
P1554515315
234566
B4141415882
del_row
234566
C5346656665
Many thanks!
One approach
SELECT t.id_number, t.Phone_number,
CASE WHEN a.id_number IS NOT NULL THEN 'del_row' ELSE '' END as Adjustment_name
FROM mytable t
LEFT JOIN
(SELECT id_number from mytable
WHERE SUBSTRING(Phone_number FROM 1 FOR 1)='A') a
/* List of IDs that have a phone number starting with A */
ON a.id_number = t.id_number
AND SUBSTRING(t.Phone_number FROM 1 FOR 1)='B'
/* Only check for matching ID with A if this number starts with B */
A rather crude approach would be as below
(assuming your phones rank Axxx, Bxxx, Cxxx, Dxxx). If your phone numbering logic is different - which is not very clear from your req - you can adjust accordingly.
create table temp_table_1 as (
select id_number, phone_number
, case
when dense_rank() over(partition by id_number order by phone_number)>1
and phone_number like 'B%'
then 'del_row'
end adjustment_name
from your_table_name
) with data;
drop table your_table_name;
rename table temp_table_1 to your_table_name;

Select all unique names based on most recent value in different field

I have an access database with a table called SicknessLog. The fields are ID, StaffName, [Start/Return], DateStamp.
When a member of staff is off work for sickness then a record is added to the table and the value in the [Start/Return] field is 1. When they return to work a new record is added with the same details except the [Start/Return] field is 0.
I am trying to write a query that will return all distinct staff names where the most recent record for that person has a value of 1 (ie, all staff who are still off sick)
Does anyone know if this is possible? Thanks in advance
Here's one way, all staff that has been sick where it does not exist an event after that where that staff is "nonsick":
select distinct x.staffname
from sicknesslog x
where Start/Return = 1
and not exists (
select 1
from sicknesslog y
where x.StaffName = y.StaffName
and y.DateStamp > x.DateStamp
and y.Start/Return = 0
)
You can use group by to achieve this.
select staffname ,max(datestamp) from sicknesslog where start/return = 1 group by staffname
it will return all latest recored for all staff. If ID column is autogenerated PK then you can use it in max function.
select staffname,MAX(datestamp)
from sicknesslog
where [start/return]=1
group by staffname
order by max(datestamp) desc,staffname
This will retrieve latest records who is sick and off to work
This should be close:
select s.StaffName, s.DateStamp, s.[Start/Return]
from SicknessLog s
left join (
select StaffName, max(DateStamp) as MaxDate
from SicknessLog
group by StaffName
) sm on s.StaffName = sm.StaffName and s.DateStamp = sm.MaxDate and s.[Start/Return] = 1

Find incorrect records by Id

I am trying to find records where the personID is associated to the incorrect SoundFile(String). I am trying to search for incorrect records among all personID's, not just one specific one. Here are my example tables:
TASKS-
PersonID SoundFile(String)
123 D10285.18001231234.mp3
123 D10236.18001231234.mp3
123 D10237.18001231234.mp3
123 D10212.18001231234.mp3
123 D12415.18001231234.mp3
**126 D19542.18001231234.mp3
126 D10235.18001234567.mp3
126 D19955.18001234567.mp3
RECORDINGS-
PhoneNumber(Distinct Records)
18001231234
18001234567
So in this example, I am trying to find all records like the one that I indented. The majority of the soundfiles like '%18001231234%' are associated to PersonID 123, but this one record is PersonID 126. I need to find all records where for all distinct numbers from the Recordings table, the PersonID(s) is not the majority.
Let me know if you need more information!
Thanks in advance!!
; WITH distinctRecordings AS (
SELECT DISTINCT PhoneNumber
FROM Recordings
),
PersonCounts as (
SELECT t.PersonID, dr.PhoneNumber, COUNT(*) AS num
FROM
Tasks t
JOIN distinctRecordings dr
ON t.SoundFile LIKE '%' + dr.PhoneNumber + '%'
GROUP BY t.PersonID, dr.PhoneNumber
)
SELECT t.PersonID, t.SoundFile
FROM PersonCounts pc1
JOIN PersonCounts pc2
ON pc2.PhoneNumber = pc1.PhoneNumber
AND pc2.PersonID <> pc1.PersonID
AND pc2.Num < pc1.Num
JOIN Tasks t
ON t.PersonID = pc2.PersonID
AND t.SoundFile LIKE '%' + pc2.PhoneNumber + '%'
SQL Fiddle Here
To summarize what this does... the first CTE, distinctRecordings, is just a distinct list of the Phone Numbers in Recordings.
Next, PersonCounts is a count of phone numbers associated with the records in Tasks for each PersonID.
This is then joined to itself to find any duplicates, and selects whichever duplicate has the smaller count... this is then joined back to Tasks to get the offending soundFile for that person / phone number.
(If your schema had some minor improvements made to it, this query would have been much simpler...)
here you go, receiving all pairs (PersonID, PhoneNumber) where the person has less entries with the given phone number than the person with the maximum entries. note that the query doesn't cater for multiple persons on par within a group.
select agg.pid
, agg.PhoneNumber
from (
select MAX(c) KEEP ( DENSE_RANK FIRST ORDER BY c DESC ) OVER ( PARTITION BY rt.PhoneNumber ) cmax
, rt.PhoneNumber
, rt.PersonID pid
, rt.c
from (
select r.PhoneNumber
, t.PersonID
, count(*) c
from recordings r
inner join tasks t on ( r.PhoneNumber = regexp_replace(t.SoundFile, '^[^.]+\.([^.]+)\.[^.]+$', '\1' ) )
group by r.PhoneNumber
, t.PersonID
) rt
) agg
where agg.c < agg.cmax
;
caveat: the solution is in oracle syntax though the operations should be in the current sql standard (possibly apart from regexp_replace, which might not matter too much since your sound file data seems to follow a fixed-position structure ).

I need a sql query to group by name but return other fields based on the most recent entry

I'm querying a single table called PhoneCallNotes. The caller FirstName, LastName and DOB are recorded for each call as well as many other fields including a unique ID for the call (PhoneNoteID) but no unique ID for the caller.
My requirement is to return a list of callers with duplicates removed along with the PhoneNoteID, etc from their most recent entry.
I can get the list of users I want using a Group By on name, DOB and Max(CreatedOn) but how do I include uniqueID (of the most recent entry in the results?)
select O.CallerFName,O.CallerLName,O.CallerDOB,Max(O.CreatedOn)
from [dbo].[PhoneCallNotes] as O
where O.CallerLName like 'Public'
group by O.CallerFName,O.CallerLName,O.CallerDOB order by Max(O.CreatedOn)
Results:
John Public 4/4/2001 4/6/12 16:42
Joe Public 4/12/1988 4/6/12 16:52
John Public 1/2/1950 4/6/12 17:01
Thanks
You can also write what Andrey wrote somewhat more compactly if you select TOP (1) WITH TIES and put the ROW_NUMBER() expression in the ORDER BY clause:
SELECT TOP (1) WITH TIES
CallerFName,
CallerLName,
CallerDOB,
CreatedOn,
PhoneNoteID
FROM [dbo].[PhoneCallNotes]
WHERE CallerLName = 'Public'
ORDER BY ROW_NUMBER() OVER(
PARTITION BY CallerFName, CallerLName, CallerDOB
ORDER BY CreatedOn DESC
)
(By the way, there's no reason to use LIKE for a simple string comparison.)
Try something like that:
;WITH CTE AS (
SELECT
O.CallerFName,
O.CallerLName,
O.CallerDOB,
O.CreatedOn,
PhoneNoteID,
ROW_NUMBER() OVER(PARTITION BY O.CallerFName, O.CallerLName, O.CallerDOB ORDER BY O.CreatedOn DESC) AS rn
FROM [dbo].[PhoneCallNotes] AS O
WHERE
O.CallerLName LIKE 'Public'
)
SELECT
CallerFName,
CallerLName,
CallerDOB,
CreatedOn,
PhoneNoteID
FROM CTE
WHERE rn = 1
ORDER BY
CreatedOn
Assuming that the set of [FirstName, LastName, DateOfBirth] are unique (#shudder#), I believe the following should work, on pretty much every major RDBMS:
SELECT a.callerFName, a.callerLName, a.callerDOB, a.createdOn, a.phoneNoteId
FROM phoneCallNotes as a
LEFT JOIN phoneCallNotes as b
ON b.callerFName = a.callerFName
AND b.callerLName = a.callerLName
AND b.callerDOB = a.callerDOB
AND b.createdOn > a.createdOn
WHERE a.callerLName LIKE 'Public'
AND b.phoneNoteId IS NULL
Basically, the query is looking for every phone-call-note for a particular name/dob combination, where there is not a more-recent row (b is null). If you have two rows with the same create time, you'll get duplicate rows, though.

SQL help: select the last 3 comments for EACH student?

I have two tables to store student data for a grade-school classroom:
Behavior_Log has the columns student_id, comments, date
Student_Roster has the columns student_id, firstname, lastname
The database is used to store daily comments about student behavior, and sometimes the teacher makes multiple comments about a student in a given day.
Now let's say the teacher wants to be able to pull up a list of the last 3 comments made for EACH student, like this:
Jessica 7/1/09 talking
Jessica 7/1/09 passing notes
Jessica 5/3/09 absent
Ciboney 7/2/09 great participation
Ciboney 4/30/09 absent
Ciboney 2/22/09 great participation
...and so on for the whole class
The single SQL query must return a set of comments for each student to eliminate the human-time-intensive need for the teacher to run separate queries for each student in the class.
I know that this sounds similar to
SQL Statement Help - Select latest Order for each Customer but I need to display the last 3 entries for each person, I can't figure out how to get from here to there.
Thanks for your suggestions!
A slightly modified solution from this article in my blog:
Analytic functions: SUM, AVG, ROW_NUMBER
SELECT student_id, date, comment
FROM (
SELECT student_id, date, comment, (#r := #r + 1) AS rn
FROM (
SELECT #_student_id:= -1
) vars,
(
SELECT *
FROM
behavior_log a
ORDER BY
student_id, date DESC
) ao
WHERE CASE WHEN #_student_id <> student_id THEN #r := 0 ELSE 0 END IS NOT NULL
AND (#_student_id := student_id) IS NOT NULL
) sc
JOIN Student_Roster sr
ON sr.student_id = sc.student_id
WHERE rn <= 3
A different approach would be to use the group_concat function and a single sub select and a limit on that subselect.
select (
select group_concat( concat( student, ', ', date,', ', comment ) separator '\n' )
from Behavior_Log
where student_id = s.student_id
group by student_id
limit 3 )
from Student_Roster s