Update only the top 1 row in sql server - sql

I have a table as below:
As You see, the column officebudge updated with value for all individual offices. i want the update happen only top 1 office
like below:
any suggesion to update the top 1 record?
I used below code. but it updates all the office entries:
UPDATE budget
SET officebudge = ISNULL(ProjectedReturnCount,0)
FROM analyticsdata
join
(
select ofc.officeid,ofc.week,
max(ISNULL(ofc.ProjectedReturnCount,0)) ProjectedReturnCount
from
BudgetOffice ofc
INNER JOIN budget anal
on ofc.OfficeID = anal.OfficeID
and ofc.Week = anal.week
and ofc.RowStatus = 'a'
group by ofc.OfficeID,ofc.week
)z
on (z.officeid = budget.OfficeID
and z.Week = budget .week )
thanks for the help. I have attached a sql fiddle to demonstrate this.
http://sqlfiddle.com/#!3/a2b32/7

You can use CTE like this (I have used only few of your provided columns)
;With cte As
(Select *, Row_Number() Over(Partition By OfficeID order by RowID) As rn
From Employee)
update cte set OfficeBudge = 0 where rn>1
select * from Employee
Find the attached fiddle
sql fiddle demo

You can achieve that you want using cte (Common Table Expression)
https://msdn.microsoft.com/en-us/library/ms186734.aspx
Take a look at item B of the link above.

Related

Updating specific columns within the table of unsequential/skipping Id's

I have a table with ~4k rows that need their data only in specific columns.
In other words UPDATE of only the specific columns within all the rows while in the same time not touching the data of existing columns - with nonsequential Id's e.g. (1,2,3,4,7,8,9,11 etc.).
So this query that I've written fails:
UPDATE dbo.SURFACE2
SET Xwgs = dt.Xwgs, Ywgs = dt.Ywgs
FROM
(
SELECT
Id as InId,
Xwgs,
Ywgs
FROM dbo.SURFACE2
WHERE
Id BETWEEN 3693 AND 7369
) dt
WHERE
Id = dt.InId - 3692
Since Id's are nonsequential not all the rows are filled and many are filled erroneously(in an expected destination row I have data for the earlier one source row).
What would be a better way of accomplishing this without having to recreate this into a new table with sorted Id's?
Your query is fine, but it can be simplified to:
UPDATE s
SET Xwgs = dt.Xwgs,
Ywgs = dt.Ywgs
FROM dbo.SURFACE2 s JOIN
dbo.SURFACE2 ss
ON s.Id = ss.InId - 3692
WHERE ss.Id BETWEEN 3693 AND 7369;
If I follow you correctly, you can use row_number() to renumber the rows first, then apply the logic:
with cte as (select s.*, row_number() over(order by id) rn from surface2)
update t
set t.Xwgs = s.Xwgs, t.Ywgs = s.Ywgs
from cte t
inner join cte s on s.rn = t.rn - 3692
where t.rn between 3693 and 7369
Query was straight; turns out I needed respective Id's for what I've imported from the
excel sheet.

Tricky SQL update

I have a tricky update to make. Any help is highly appreciated. Thanks in advance for your help.
Here is the scenario as shown on the image attached. I have to update P_main.ver_key from Versions.verkey where P_main.ver_key is null. The logic is to get the ver_key for that pid where Versions.pcmm <= max(P_main.vdmm). The values that should be populated in the null spots are shown in the 'after update' column on the image.
Example:
P_main table:
pid = 50000178
vcmm = 2014027001
Versions table:
pid = 50000178
max pdmm <=2014027001 is 2014032000
therefore
update ver_key = 154
This might not be the fastest way, but it should work:
WITH CTE AS
(
SELECT P.*, Q.ver_key ver_key_new
FROM P_Main P
CROSS APPLY(SELECT TOP 1 ver_key
FROM Versions
WHERE pid = P.pid
AND vdmm <= P.vcmm
ORDER BY vdmm DESC) Q
WHERE P.ver_key IS NULL
)
UPDATE CTE
SET ver_key = ver_key_new;

Find records in SQL Server 2008 R2

Please find below image for make understanding my issues. I have a table as shown below picture. I need to get only highlighted (yellow) records. What is the best method to find these records?
In SQL Server 2012+, you can use the lead() and lag() functions. However, this is not available in SQL Server 2008. Here is a method using outer apply:
select t.*
from t outer apply
(select top 1 tprev.*
from t tprev
on tprev.time < t.time
order by tprev.time desc
) tprev outer apply
(select top 1 tnext.*
from t tnext
on tnext.time > t.time
order by tnext.time asc
)
where (t.cardtype = 1 and tnext.cardtype = 2) or
(t.cardtype = 2 and tprev.cardtype = 1);
With your sample data, it would also be possible to use self joins on the id column. This seems unsafe, though, because there could be gaps in that columns values.
Havent tried this, but I think it should work. First, make a view of the table in your question, with the rownumber included as one column:
CREATE VIEW v AS
SELECT
ROW_NUMBER() OVER(ORDER BY id) AS rownum,
id,
time,
card,
card_type
FROM table
Then, you can get all the rows of type 1 followed by a row of type 2 like this:
SELECT
a.id,
-- And so on...
FROM v AS a
JOIN v AS b ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
And all the rows of type 2 preceded by a row of type 1 like this:
SELECT
b.id,
-- And so on...
FROM v AS b
JOIN v AS a ON b.rownum = a.rownum + 1
WHERE a.card_type = 1 AND b.card_type = 2
To get them both in the same set of results, you can just use UNION ALL. Technically, you don't need the view. You could use nested selects instead, but since you will need to query the table four times it might be nice to have it as a view.
Also, if the ID is continous (it goes 1, 2, 3 without any gaps), you don't need the rownum and can just use the ID instead.
here is a code you can run in sql server
select * from Table_name where id in (1,2,6,7,195,160,164,165)

Updating a field based on a count of records from a different table

I need to set a value to 1 in table where the count for a given role in another table is > 1.
The table cursillo.members has fields memid and hsd. Table cursillo.teams has fields memid (the link between the two) a field called movement and another called role.
What I am trying to accomplish is something similar to this:
update cursillo.members_eligible p, cursillo.teams pp
set p.hsd=1
where p.memid = pp.memid AND (pp.role = 'HSD' OR pp.role = 'SD')
and pp.movement = 'Cursillo' AND count(pp.role) > 1;
or this:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and count(teams.role) > 1;
In other words if a given memid has more than one record in the cursillo.teams table where the value of the role is equal to either HSD or SD, then set cursillo.members_eligible.hsd to 1.
I can't figure out to handle the count() part.
Thanks,
Mike Reed
Possible duplicate question:
MySQL - Using COUNT(*) in the WHERE clause
Try using the 'having' keyword
Here's the relevant section from the linked answer (in this case, a select statement):
select gid
from `gd`
group by gid
having count(*) > 10
order by lastupdated desc
It looks like 'having' can only be used in select statments though:
http://www.mysqltutorial.org/mysql-having.aspx
So you may need to have your update's where clause include a select statement:
update members_eligibile
set hsd=1
from teams
where teams.memid=members_eligible.memid
and (teams.role = 'HSD' OR teams.role = 'SD')
and teams.movement = 'Cursillo'
and members_eligible.memid IN
(SELECT members_eligible.memid from members_eligible where teams.memid=members_eligible.memid having count(teams.role) > 1);
You will have to adjust the select statement, I haven't tested it
SQL Server 2005+
UPDATE x
SET x.hsd = 1
FROM (SELECT e.hsd, COUNT(*) OVER (PARTITION BY t.role) AS cnt
FROM teams t JOIN members_eligibile e ON t.memid = e.memid
WHERE (t.role = 'HSD' OR t.role = 'SD') AND t.movement = 'Cursillo') x
WHERE x.cnt > 1

Update based on subquery fails

I am trying to do the following update in Oracle 10gR2:
update
(select voyage_port_id, voyage_id, arrival_date, port_seq,
row_number() over (partition by voyage_id order by arrival_date) as new_seq
from voyage_port) t
set t.port_seq = t.new_seq
Voyage_port_id is the primary key, voyage_id is a foreign key. I'm trying to assign a sequence number based on the dates within each voyage.
However, the above fails with ORA-01732: data manipulation operation not legal on this view
What is the problem and how can I avoid it ?
Since you can't update subqueries with row_number, you'll have to calculate the row number in the set part of the update. At first I tried this:
update voyage_port a
set a.port_seq = (
select
row_number() over (partition by voyage_id order by arrival_date)
from voyage_port b
where b.voyage_port_id = a.voyage_port_id
)
But that doesn't work, because the subquery only selects one row, and then the row_number() is always 1. Using another subquery allows a meaningful result:
update voyage_port a
set a.port_seq = (
select c.rn
from (
select
voyage_port_id
, row_number() over (partition by voyage_id
order by arrival_date) as rn
from voyage_port b
) c
where c.voyage_port_id = a.voyage_port_id
)
It works, but more complex than I'd expect for this task.
You can update some views, but there are restrictions and one is that the view must not contain analytic functions. See SQL Language Reference on UPDATE and search for first occurence of "analytic".
This will work, provided no voyage visits more than one port on the same day (or the dates include a time component that makes them unique):
update voyage_port vp
set vp.port_seq =
( select count(*)
from voyage_port vp2
where vp2.voyage_id = vp.voyage_id
and vp2.arrival_date <= vp.arrival_date
)
I think this handles the case where a voyage visits more than 1 port per day and there is no time component (though the sequence of ports visited on the same day is then arbitrary):
update voyage_port vp
set vp.port_seq =
( select count(*)
from voyage_port vp2
where vp2.voyage_id = vp.voyage_id
and (vp2.arrival_date <= vp.arrival_date)
or ( vp2.arrival_date = vp.arrival_date
and vp2.voyage_port_id <= vp.voyage_port_id
)
)
Don't think you can update a derived table, I'd rewrite as:
update voyage_port
set port_seq = t.new_seq
from
voyage_port p
inner join
(select voyage_port_id, voyage_id, arrival_date, port_seq,
row_number() over (partition by voyage_id order by arrival_date) as new_seq
from voyage_port) t
on p.voyage_port_id = t.voyage_port_id
The first token after the UPDATE should be the name of the table to update, then your columns-to-update. I'm not sure what you are trying to achieve with the select statement where it is, but you can' update the result set from the select legally.
A version of the sql, guessing what you have in mind, might look like...
update voyage_port t
set t.port_seq = (<select statement that generates new value of port_seq>)
NOTE: to use a select statement to set a value like this you must make sure only 1 row will be returned from the select !
EDIT : modified statement above to reflect what I was trying to explain. The question has been answered very nicely by Andomar above