i have a table with NO Primary Key.
name age sex
a 12 m
b 61 m
c 23 f
d 12 m
a 12 m
a 12 m
f 14 f
i have exactly 3 similar rows-row-1,row-5 and row-6.
i want to update row-5 without affecting row-1 and row-6.
Pls help me out, how to achieve this.
Your real problem is that you have no row numbers, and no way to distiguish identical rows. If your data is still in the order in which it was inserted you have simply been lucky so far. SQL Server gives no guarantees of row ordering and could randomize the order without notice. To preserve your ordering you can add an identity column to the table.
ALTER TABLE TableWithNoPrimaryKey
ADD RowNum int IDENTITY(1,1) PRIMARY KEY
Its not possible to use ROW_NUMBER function in SQL as this duplicates can be spread over thousands of record.
ROW_NUMBER is use to get the row number with OVER clause and as the storage of such data is non clustred its not possible to delete.
The only option is to add some identity or unique column to the table and then delete the special record and if you dont want table with the new index or new column you can delete that cloumn from the table.
There is a way to do what you wish. It is not recommended though.
;WITH cte AS
(
SELECT *, RowNum = ROW_NUMBER() OVER (ORDER BY GETDATE())
FROM [table]
)
UPDATE cte
SET age = age + 1
WHERE (RowNum = 5)
AND (name = 'a' AND age = 12 AND sex = 'm');
I have considered your table name as T1 and updated one of the rows. I don't want to order the result set but still want to generate the row numbers, so I used a dummy subquery - Select 0. Below query works in Oracle and IBM Netezza. You can try using rowid if it exists in SQL SERVER or any other equivalent to rowid should work.
UPDATE T1 SET name = a1, age = 21, sex = 'm'
FROM (SELECT name, age, sex, rowid,
row_number() over(partition by name, age, sex ORDER BY(SELECT 0)) as rn
FROM T1)A
WHERE T1.name = A.name
AND T1.age = A.age
AND T1.sex = A.sex
AND T1.rowid = A.rowid
AND A.rn = 1;
Related
I have a table where I want to update CID column until it finds another column value, where EID = 7. I ordered my table Using PID in DESC order.
Here is my table structure.
After the update the table will look like:
I basically want to reorder the table by CID, and want to update the top rows (Set CID = 1010 )till it finds where EID = 10. When EID = 10, it will not update the rest beneath, including it,
I tried using Row_Number() the thing is my table contains a different and large number of CID's plus the value of EID for each CID differs, but every CID has where EID = 10. I tried, using cursors, sorting using Row_Number(), but I couldn't fetch the right data. Any help is welcome.
you can use windowing function and bucket he occurrence of 10 and then update as below:
update t
set t.cid = 1010
from #table t join
( select *, sum(case when eid = 10 then 1 else 0 end) over(order by pid desc) rown from #table ) r
on t.PId = r.PId
and rown = 0
Code as below: https://rextester.com/GUW95636
SQL Server 2008 R2
Table CIRTB
CIRLogID PrimaryKey
StaffName
StaffID
Table StaffTB
StaffID - PrimaryKey
Fullname
DOB
CIN
Program
I have StaffID's in the CIRTB table that are Null, so I need to update it from the Staff table.
I know I need something like the following
update CIRTB
set CIRTB>staffid = (select staffid
from stafftb
where stafftb.fullname = cirtb.Staffname)
where CIRTB.staffid is null
One problem that I am stuck on: there are some duplicates in the StaffTB for fullname, dob, program
One way to do the UPDATE is using a CTE:
;WITH ToUpdate AS (
SELECT t1.StaffID AS t1_StaffID, t2.StaffID AS t2_StaffID,
ROW_NUMBER() OVER (PARTITION BY t2.Fullname
ORDER BY t2.DOB DESC) AS rn
FROM CIRTB AS t1
JOIN StaffTB AS t2 ON t1.StaffName = t2.Fullname
WHERE t1.StaffID IS NULL
)
UPDATE ToUpdate
SET t1_StaffID = t2_StaffID
WHERE rn = 1
The CTE uses ROW_NUMBER in order to pick one record per Fullname. The ORDER BY clause of the window function determines which record is picked in case of duplicates: since DOB DESC is used, the record having the most recent DOB is selected.
Use TOP 1 in the sub-select to make sure it only returns one row even if there are duplicates.
I have a table with pk and dept columns:
pk dept
-------
27 A
29 A
30 B
31 B
33 A
I need to select the first consecutive group, that is the first successive set of rows all having the same dept value when the table is ordered by pk, i.e. the expected result is:
pk dept
-------
27 A
29 A
In my example there are 3 consecutive groups (AA, BB and A). The size of a group is unlimited (can be more than 2).
The following query should do what you want (I named your table tx):
SELECT *
FROM tx t1
WHERE NOT EXISTS (
SELECT *
FROM tx t2
WHERE t2.dept <> t1.dept
AND t2.pk < t1.pk);
The idea is to look for tuples such that no tuple with a lesser pk and a different department exists.
The first two A tuples are kept;
The B tuples are dropped because of the first two A tuples;
The last A tuple is dropped because of the B tuples.
Remember about stored functions. Unlike to using window functions its allows to avoid the reading of the whole table:
--drop function if exists foo();
--drop table if exists t;
create table t(pk int, dep text);
insert into t values(27,'A'),(29,'A'),(30,'B'),(31,'B'),(33,'A');
create function foo() returns setof t language plpgsql as $$
declare
r t;
p t;
begin
for r in (select * from t order by pk) loop
if p is null then
p := r;
end if;
exit when p.dep is distinct from r.dep;
return next r;
end loop;
return;
end $$;
select * from foo();
Its a little bit complex and probably, the permformance poor, but you can achieve what you want with the code below. There are four operations:
The first one is where we obtain the base order and base group ids
for the next operation.
In the sencond operation we make the trick computing an unique group
id for each group
In the third operation, where are spreading the unique group id over
the rows of each group.
Finally, we compute a consecutive group id for each group to allow
the discretionary selection of groups, so we only have to filter by
the group number we want to obtain.
Hope this helps.
SELECT fourthOperation.pk,
fourthOperation.dept
FROM (SELECT thirdOperation.pk,
thirdOperation.dept,
DENSE_RANK() OVER (ORDER BY thirdOperation.spreadedIdGroup) denseIdGroup
FROM (SELECT secondOperation.*,
NVL(idGroup, LAG(secondOperation.idGroup IGNORE NULLS) OVER (ORDER BY secondOperation.numRow)) spreadedIdGroup
FROM (SELECT firstOperation.*,
CASE WHEN LAG(firstOperation.rankRow) OVER (ORDER BY firstOperation.numRow) = firstOperation.rankRow
THEN NULL
ELSE firstOperation.numRow
END idGroup
FROM (SELECT yourTable.*,
ROW_NUMBER() OVER (ORDER BY PK) AS numRow,
DENSE_RANK() OVER (ORDER BY DEPT) AS rankRow
FROM ABORRAR yourTable) firstOperation) secondOperation ) thirdOperation) fourthOperation
WHERE fourthOperation.denseIdGroup = 1
I'm not sure if I understand your question, but for the first pk of each dept you can try this:
select min(pk) as pk,
dept
from your_table
group by dept
To do some testing on a new table field, I'd like to fake-up some values on existing records in my test database. I want to assign a value to every 8th record in a table. I can easily select every 8th record using this syntax:
select *
from
(select rownum rn
, jeffs_field_to_update
from jeff)
where mod(rn, 8) = 0;
However, I'm fairly new to SQL, and I can't seem to be able to convert this to an update statement. I see a lot of answers here about selecting nth records, but I've already got that. Any assistance would be appreciated.
You need to join this to UPDATE statement on any key in the table. For example, if you have an unique id column, update statement will look like this:
update jeff
set jeffs_field_to_update = value
where id in
(select id
from
(select rownum rn
, jeff.id
from jeff)
where mod(rn, 8) = 0)
A shorter answer:
UPDATE jeff
SET jeffs_field_to_update = value
WHERE mod(DBMS_ROWID.ROWID_ROW_NUMBER(ROWID), 8)=0;
Assuming your table has a unique id to identify each row, you can do something like this:
update jeff
set . . .
where id in (select id
from (select rownum as rn, id
from jeff
)
where mod(rn, 8) = 0
)
You should also be able to do this with an inline updatable view (see here):
update (select jeffs_field_to_update
from (select rownum rn, jeffs_field_to_update
from jeff)
where mod(rn, 8) = 0
) toupdate
set . . .
even without the key, you can use rowid in oracle for this purpose.
update mytable
set mycol = new_value
where rowid in
(select rowid from
(select rownum rn, id from mytable)
where mod(rn, 8) = 0)
I am using SQL server 2005.
I have a table like this -
ID Name
1 a
1 a
1 a
2 b
2 b
3 c
4 d
4 d
In this, I want to delete all duplicate entries and retain only one instance as -
ID Name
1 a
2 b
3 c
4 d
I can do this easily by adding another identity column to this table and having unique numbers in it and then deleting the duplicate records. However I want to know if I can delete the duplicate records without adding that additional column to this table.
Additionally if this can be done using only one query statement. i.e. Without using Stored procedures or temp tables.
Using a ROW_NUMBER in a CTE allows you to delete duplicate values while retaining unique rows.
WITH q AS (
SELECT RN = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID )
, ID
, Name
FROM ATable
)
DELETE FROM q WHERE RN > 1
Lieven is Right... however you may want to tweak lieven's code by just adding a top clause in the delete statement like this:
delete top(1) from q where RN > 1;
Hope this helps
You may use this query:
delete a from
(select id,name, ROW_NUMBER() over (partition by id,name order by id) row_Count
from dup_table) a
where a.row_Count >1
delete from table1
USING table1, table1 as vtable
WHERE (NOT table1.ID=vtable.ID)
AND (table1.Name=vtable.Name)
DELETE FROM tbl
WHERE ID NOT IN (
SELECT MIN(ID)
FROM tbl
GROUP BY Name
)