Update a field with a counter in Oracle - sql

I have a table in Oracle like this:
+---------------------------------------------------------------+
| KA_ACTEUR | NIF | NIF_EXT | NAME | LASTNAME |
+---------------------------------------------------------------+
| AAAAAAAA1 | 123456789X | 1 | JHON | DOE |
| AAAAAAAA2 | 123456789X | 2 | JHON | DOE |
| AAAAAAAA3 | 123456789X | 3 | JHON | DOE |
| AAAAAAA34 | 123456789X | | JHON | DOE |
| AAAAA6AA5 | 123456789X | | JHON | DOE |
+---------------------------------------------------------------+
The field NIF is the Primary key
And I want to update the entries with the field EXT empty continuing the sequence (max+1).
I used the following code but there are a lot of entries and It takes a lot of time.
DECLARE
CURSOR clientCursor IS
SELECT * from my_table
where nif_ext is null;
BEGIN
FOR client IN clientCursor LOOP
UPDATE my_table
SET nif_ext = (select nvl(max(nif_ext)+1,1) from my_table where nif=client.nif)
WHERE ka_acteur=client.ka_acteur;
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
Do you know another way to resolve this?
Thanks.

This can be achieve using a merge statement:
merge into my_table
using
(
select ka_acteur,
(select max(nif_ext) from my_table) as max_nif,
row_number() over (order by ka_acteur) as rn
from my_table
where nif_ext is null
) t on (t.ka_acteur = my_table.ka_acteur)
when matched then
set nif_ext = t.max_nif + t.rn;

Related

Dedup rows with insensitive values in snowflake

I would like to dedup rows with case insensitive values.
original table:
| ID | Name |
| ---| -------------- |
| 1 | Apple |
| 2 | Banana |
| 1 | apple |
desired output after deduping (keep the lowercase):
| ID | Name |
| ---| -------------- |
| 2 | Banana |
| 1 | apple |
Following statement only works for case sensitive match.
create table DELETE2 as select distinct * from DELETE1;
drop table DELETE1;
alter table DELETE2 rename to DELETE1;
I tried to use following statement, but it did not work.
ALTER SESSION SET QUOTED_IDENTIFIERS_IGNORE_CASE = TRUE;
Thank you!
knozawa
You could group by lower(x):
select id, max(name) name
from table
group by 1, lower(name)

How to create a column containing a JSON that has names defined from the value of a column in another table?

I have a source table with data in VARCHAR format like the example below.
I want to insert the data in another table in a JSON format (the result column itself can be of JSON or VARCHAR type).
For each Id, there is at least 1 JSONName/JSONValue pair.
But each Id doesn't have the same kinds and number of JSONName/JSONValue pairs.
Each Id can have maximum 50 JSONName/JSONValue pairs.
The order of the pairs in the value of the ResultJSON column doesn't matter.
SourceTable:
____________________________
| Id | JSONName | JSONValue |
|____|__________|___________|
| 1 | Name | John |
| 2 | Name | Henry |
| 2 | Age | 32 |
| 3 | Age | 56 |
| 3 | Location | US |
| 4 | Age | 24 |
| 4 | Name | Andrew |
| 4 | Location | |
What I want:
Expected ResultTable:
____________________________________________________
| Id | ResultJSON |
|____|______________________________________________|
| 1 | {"Name":"John"} |
| 2 | {"Name":"Henry","Age":"32"} |
| 3 | {"Age":"56", "Location":"US"} |
| 4 | {"Age":"24","Name":"Andrew","Location":null} |
What I get with my current query:
Wrong resultTable:
_______________________________________________________________________________________________________________________________
| Id | ResultJSON |
|____|_________________________________________________________________________________________________________________________|
| 1 | [{"JSONName":"Name","JSONValue":"John"}] |
| 2 | [{"JSONName":"Name","JSONValue":"Henry"},{"JSONName":"Age","JSONValue":"32"}] |
| 3 | [{"JSONName":"Age","JSONValue":"56"},{"JSONName":"Location","JSONValue":"US"}] |
| 4 | [{"JSONName":"Age","JSONValue":"24"},{"JSONName":"Name","JSONValue":"Andrew"},{"JSONName":"Location","JSONValue":null}] |
Current query:
INSERT INTO ResultTable
(
Id
,ResultJSON
)
SELECT
SourceTable.Id
,JSON_AGG(SourceTable.JSONName,SourceTable.JSONValue)
FROM SourceTable
INNER JOIN OtherTable ON SourceTable.Id=OtherTable.Id
Is it possible to do it with Teradata JSON functions? If not, what would be the most optimized query to do it?
You can remove the unwanted parts using a RegEx:
SELECT
SourceTable.Id
,RegExp_Replace(Cast(Json_Agg(SourceTable.JSONName AS "#A",SourceTable.JSONValue AS "#B") AS VARCHAR(32000)), '"#A":|,"#B"|^\[|\]$|}(?=,{")|(?<="},){')
FROM SourceTable
GROUP BY 1
The RegEx removes all of the follwing:
"#A":
,"#B"
a leading [
a trailing ]
} if it's followed by ,{"
{ if it's following "},
Edit:
Based on the comments this RegEx leaves superfluous opening braces. This seems to work better:
'"#A":|,"#B"|^[|]$|}(?=,)|(?<=,){'
Here is the query I got in the end:
INSERT INTO DB.RESULT_TABLE
(
ResultId
,ResultJSON
)
WITH RECURSIVE MergedTable (Id, mergedList, rnk)
AS
(
SELECT
Id
,TRIM('"' || JSONName ||'":'|| COALESCE('"' || JSONValue || '"','null')) AS mergedList
,rnk
FROM DB.SOURCE_TABLE
WHERE rnk = 1
UNION ALL
SELECT
SourceTable.Id
,MergedTable.mergedList || ',' || TRIM('"' || SourceTable.JSONName ||'":' || COALESCE('"' || SourceTable.JSONValue || '"','null')) AS mergedList
,SourceTable.rnk
FROM DB.SOURCE_TABLE SourceTable
INNER JOIN MergedTable MergedTable
ON MergedTable.rnk + 1 = SourceTable.rnk
AND SourceTable.Id = MergedTable.Id
)
SELECT
MergedTable.Id AS ResultId
,'{' || MergedTable.mergedList || '}' AS ResultJSON
FROM MergedTable
QUALIFY RANK() OVER (PARTITION BY ResultId ORDER BY rnk DESC) = 1
;

Oracle update query using partition

I have following sample data in Oracle v.12 database
ID | NAME | DML_TYPE | FND_FILESEQNO | FND_FILERBA
---------------------------------------------------------
1 | name1a | insert | 1 | 1
1 | name1b | update | 1 | 2
2 | name2a | insert | 2 | 1
2 | name2b | update | 2 | 2
....
....
....
I want following 2 transactions to happen
delete old records (FND_FILESEQNO + FND_FILERBA) partition by 'ID' column
update latest record DML_TYPE = 'insert'
So eventually, if I query this table, I should get following result...
ID | NAME | DML_TYPE | FND_FILESEQNO | FND_FILERBA
---------------------------------------------------------
1 | name1b | insert | 1 | 2
2 | name2b | insert | 2 | 2
Many thanks
Try This:-
MERGE INTO STACTOVER a
USING ( SELECT * FROM (
SELECT STACTOVER.*,Row_Number() OVER(PARTITION BY ID ORDER BY ID)rn
FROM STACTOVER)WHERE rn>1
)b
ON
(a.ID = b.ID)
WHEN MATCHED THEN
UPDATE SET a.dml_type = 'insert'
DELETE WHERE a.NAME != b.NAME ;

Do I need a recursive CTE to update a table that relies on itself?

I need to apologize for the title. I put a lot of thought into it but didn't get too far.
I have a table that looks like this:
+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------+--------+
| accountid | pricexxxxxid | accountid | pricelevelid | counts |
+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------+--------+
| 36B077D4-E765-4C70-BE18-2ECA871420D3 | 00000000-0000-0000-0000-000000000000 | 36B077D4-E765-4C70-BE18-2ECA871420D3 | F43C47CE-28C6-42E2-8399-92C58ED4BA9D | 1 |
| EBC18CBC-2D2E-44CB-B36A-0ADE9E2BDE9F | 00000000-0000-0000-0000-000000000000 | EBC18CBC-2D2E-44CB-B36A-0ADE9E2BDE9F | 3BEEA9D3-F26B-47E4-88FA-A2AA366980ED | 1 |
| 8DC8D0FC-3138-425A-A922-2F0CAC57E887 | 00000000-0000-0000-0000-000000000000 | 8DC8D0FC-3138-425A-A922-2F0CAC57E887 | F1B8AD5D-B008-4C3F-94A0-AD3F90C777D7 | 1 |
| 8F908A92-1327-4655-BAE4-C890D971A554 | 00000000-0000-0000-0000-000000000000 | 8F908A92-1327-4655-BAE4-C890D971A554 | 2E0EC67E-5F8F-4305-932E-BBF8DF83DBEC | 1 |
| 37221AAC-B885-4002-B7D9-591F8C14D019 | 00000000-0000-0000-0000-000000000000 | 37221AAC-B885-4002-B7D9-591F8C14D019 | F4A2A0CA-FDFF-4C21-AE92-D4583DC18DED | 1 |
| 66F406B4-0D9B-40B8-9A23-119EE74B00B7 | 00000000-0000-0000-0000-000000000000 | 66F406B4-0D9B-40B8-9A23-119EE74B00B7 | 204B8570-CEBA-4C72-9B72-8B9B14AF625E | 2 |
| D0168CE3-479E-439E-967C-4FF0D701291A | 00000000-0000-0000-0000-000000000000 | D0168CE3-479E-439E-967C-4FF0D701291A | 204B8570-CEBA-4C72-9B72-8B9B14AF625E | 2 |
| 57E5F6E5-0A8A-4E54-B793-2F6493DC1EA3 | 00000000-0000-0000-0000-000000000000 | 57E5F6E5-0A8A-4E54-B793-2F6493DC1EA3 | 893F9FD2-43C9-4355-AEFC-08A62BF2B066 | 3 |
+--------------------------------------+--------------------------------------+--------------------------------------+--------------------------------------+--------+
It is sorted by ascending counts.
I would like to update the pricexxxxids that are all 00000000-0000-0000-0000-000000000000 with their corresponding pricelevelid.
For example for accountid = 36B077D4-E765-4C70-BE18-2ECA871420D3 I would like the pricexxxxid to be F43C47CE-28C6-42E2-8399-92C58ED4BA9D.
After that is done, I would like all the records FOLLOWING this one where accountid = 36B077D4-E765-4C70-BE18-2ECA871420D3 to be deleted.
Another words in result I will end up with a distinct list of accountids with pricexxxxid to be assigned with the corresponding value from pricelevelid.
Thank you so much for your guidance.
for your first case do !
update table
set pricexxxxids=pricelevelid.
if i understand your second case correctly :(delete duplicates/select distinct)?
delete from
(
select *,rn=row_number()over(partition by accountid order by accountid) from table
)x
where rn>1
--select distinct * from table
edited
select * from
(
select *,rn=row_number()over(partition by accountid order by accountid) from table
)x
where x.rn=1
updated
SELECT accountid,pricelevelid FROM
(
(SELECT *,
Row_number() OVER ( partition BY accountid ORDER BY counts, pricelevelid ) AS Recency
FROM table
)x
WHERE x.Recency = 1

Find and update specific duplicates in MS SQL

given below table:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | NULL |
| 2 | Ashly | Baboon | 09898788909 | NULL |
| 3 | James | Vangohg | 04333989878 | NULL |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
I want to use MS SQL to find and update duplicate (based on name, last name and number) but only the earlier one(s). So desired result for above table is:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | DUPE |
| 2 | Ashly | Baboon | 09898788909 | DUPE |
| 3 | James | Vangohg | 04333989878 | DUPE |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
This query uses a CTE to apply a row number, where any number > 1 is a dupe of the row with the highest ID.
;WITH x AS
(
SELECT ID,NAME,[LAST NAME],PHONE,STATE,
ROW_NUMBER() OVER (PARTITION BY NAME,[LAST NAME],PHONE ORDER BY ID DESC)
FROM dbo.YourTable
)
UPDATE x SET STATE = CASE rn WHEN 1 THEN NULL ELSE 'DUPE' END;
Of course, I see no reason to actually update the table with this information; every time the table is touched, this data is stale and the query must be re-applied. Since you can derive this information at run-time, this should be part of a query, not constantly updated in the table. IMHO.
Try this statement.
LAST UPDATE:
update t1
set
t1.STATE = 'DUPE'
from
TableName t1
join
(
select name, last_name, phone, max(id) as id, count(id) as cnt
from
TableName
group by name, last_name, phone
having count(id) > 1
) t2 on ( t1.name = t2.name and t1.last_name = t2.last_name and t1.phone = t2.phone and t1.id < t2.id)
If my understanding of your requirements is correct, you want to update all of the STATE values to DUPE when there exists another row with a higher ID value that has the same NAME and LAST NAME. If so, use this:
update t set STATE = (case when sorted.RowNbr = 1 then null else 'DUPE' end)
from yourtable t
join (select
ID,
row_number() over
(partition by name, [last name], phone order by id desc) as RowNbr from yourtable)
sorted on sorted.ID = t.ID