SQL call Max row number from a temp table - sql

In the temp table there are only two columns available. I would like to get the most recent ID for each load, as shown in the picture below.
I have tried this but it doesn't give me the answer I need.
select max(rn_plus_1),a.load, a.id from( select a.load,
a.id,
ROW_NUMBER() over(order by a.id desc) rn from max_num a group by load
, id) a

TEMP_TABLE lacks a sequential primary key or any other indicator for order of insertion. So it is not possible to get the latest ID for a LOAD using the columns of the table itself.
However, there is one option: ORA_ROWSCN(). This is a pseudo-column which identifies the System Change Number for the transaction which changed the table. So we can reconstruct the order of insertion by sorting the table on ORA_ROWSCN.
There are some caveats:
By default the SCN applies to the block level. Consequently all the rows in a block have the same SCN. It's a good enough approximation for wide tables but hopeless for a two-column toy like TEMP_TABLE. We can track SCN at the row level but only if the table is created with ROWDEPENDENCIES. The default is NOROWDEPENDENCIES. Unfortunately, we cannot use ALTER TABLE here. You will need to drop and recreate the table (*) to enable ROWDEPENDENCIES.
The SCN applies to the transaction. This means the solution will only work if each row in TEMP_TABLE is inserted in a separate transaction.
Obviously this is only possible if TEMP_TABLE is an actual table and not a view or some other construct.
Given all these criteria are satisfied here is a query which will give you the result set you want:
select load, id
from ( select load
, id
, row_number() over (partition by load order by ora_rowscn desc) as rn
from temp_table
)
where rn = 1
There is a demo on db<>fiddle. Also, the same demo except TEMP_TABLE defined with NOROWDEPENDENCIES, which produces the wrong result.
(*) If you need to keep the data in TEMP_TABLE the steps are:
rename TEMP_TABLE to whatever;
create table TEMP_TABLE as select * from whatever rowdependencies;
drop table whatever;
However, the SCN will be the same for the existing rows. If that matters you'll have to insert each row one at a time, in the order you wish to preserve, and commit after each insert.

Related

How to delete one random row at a time in Oracle database

I am working on a project where I need to delete a random row from an Oracle database. Which query should I use for that?
Well obviously it's a DELETE statement. It's the random part which is tricky.
Oracle has a PL/SQL package to handle randomness, DBMS_RANDOM. If the table is small or performance is not critical this will work:
delete from your_table
where id = ( select id from
( select id from your_table
order by dbms_random.value)
where rownum = 1)
/
The innermost query sorts the table in a random order. The sub-query selects the top row from that set, and that's the row which gets deleted.
Alternatively, if you know how many records you have...
delete from your_table
where id = ( select round(dbms_random.value(1,10000))
from dual )

SQL Eliminate Duplicates with NO ID

I have a table with the following Columns...
Node, Date_Time, Market, Price
I would like to delete all but 1 record for each Node, Date time.
SELECT Node, Date_Time, MAX(Price)
FROM Hourly_Data
Group BY Node, Date_Time
That gets the results I would like to see but cant figure out how to remove the other records.
Note - There is no ID for this table
Here are steps that are rather workaround than a simple one-command which will work in any relational database:
Create new table that looks just like the one you already have
Insert the data computed by your group-by query to newly created table
Drop the old table
Rename new table to the name the old one used to have
Just remember that locking takes place and you need to have some maintenance time to perform this action.
There are simpler ways to achieve this, but they are DBMS specific.
here is an easy sql-server method that creates a Row Number within a cte and deletes from it. I believe this method also works for most RDBMS that support window functions and Common Table Expressions.
;WITH cte AS (
SELECT
*
,RowNum = ROW_NUMBER() OVER (PARTITION BY Node, Date_Time ORDER BY Price DESC)
FROM
Hourly_Data
)
DELETE
FROM
cte
WHERE
RowNum > 1

Retrieving data based on a sorted set of primary keys

I have a set of primary keys. The set is sorted in the way the records are going to be displayed.
I want to retrive the records from the database in the same order as in the sorted set.
Currently I am doing like this:
cursor getdata is
select snr, -- snr is the primary key
field1,
field2,
field3
from MyTable,
(select COLUMN_VALUE snr, rownum sort_key from TABLE(varray_of_snr)) snr_tab
where MyTable.snr = snr_tab.snr
order by snr_tab.sort_key;
The problem is that Oracle doesn't have to read the rows in the inner select in the same order as they are in the varray. There is no guarantee that Oracle won't read the rows in reverse order from the varray in the inner select.
Is there a simple way to guarantee that the sort order is preserved?
To my knowledge, the ORDER of any data-set is never guaranteed unless an ORDER BY is specified.
If the order of the array is arbitrary, I'd recommend including a row_id field that is populated when you store the data. rownum should only be used instead if you can infer the ordering and use an ORDER BY clause.
This is what I did:
I created a global temporary table, temp_snr_sort with the columns snr and sort_id.
I then used the global temporary table to add a sort_id to my snr:s.
-- Load the array with sort information into temp_snr_tab
for i in 1..varray_of_snr.last loop
insert into temp_snr_tab values (varray_of_snr(i), i);
end loop;
-- Get the data correctly sorted
open getdata for
select field1,
field2,
field3
from MyTable,
temp_snr_tab snr_tab
where MyTable.snr = snr_tab.snr
order by snr_tab.sort_id;
UPDATED: Ok, an ideea (probably flawed :) )
CREATE OR REPLACE TYPE snr_type as OBJECT (
id number ,
srn number)
CREATE OR REPLACE TYPE varray_of_snr AS VARRAY(10000) OF snr_type;
then create your varary putting in id your order
then order the main sql by id.

Deleting Duplicate Records from a Table

I Have a table called Table1 which has 48 records. Out of which only 24 should be there in that table. For some reason I got duplicate records inserted into it. How do I delete the duplicate records from that table.
Here's something you might try if SQL Server version is 2005 or later.
WITH cte AS
(
SELECT {list-of-columns-in-table},
row_number() over (PARTITION BY {list-of-key-columns} ORDER BY {rule-to-determine-row-to-keep}) as sequence
FROM myTable
)
DELETE FROM cte
WHERE sequence > 1
This uses a common table expression (CTE) and adds a sequence column. {list-of-columns-in-table} is just as it states. Not all columns are needed, but I won't explain here.
The {list-of-key-columns] is the columns that you use to define what is a duplicate.
{rule-to-determine-row-to-keep} is a sequence so that the first row is the row to keep. For example, if you want to keep the oldest row, you would use a date column for sequence.
Here's an example of the query with real columns.
WITH cte AS
(
SELECT ID, CourseName, DateAdded,
row_number() over (PARTITION BY CourseName ORDER BY DateAdded) as sequence
FROM Courses
)
DELETE FROM cte
WHERE sequence > 1
This example removes duplicate rows based on the CoursName value and keeps the oldest basesd on the DateAdded value.
http://support.microsoft.com/kb/139444
This section is the key. The primary point you should take away. ;)
This article discusses how to locate
and remove duplicate primary keys from
a table. However, you should closely
examine the process which allowed the
duplicates to happen in order to
prevent a recurrence.
Identify your records by grouping data by your logical keys, since you obviously haven't defined them, and applying a HAVING COUNT(*) > 1 statement at the end. The article goes into this in depth.
This is an easier way
Select * Into #TempTable FROM YourTable
Truncate Table YourTable
Insert into YourTable Select Distinct * from #TempTable
Drop Table #TempTable

My tricky SQL Update query not working so well

I am trying to update a table in my database with another row from another table. I have two parameters one being the ID and another being the row number (as you can select which row you want from the GUI)
this part of the code works fine, this returns one column of a single row.
(SELECT txtPageContent
FROM (select *, Row_Number() OVER (ORDER BY ArchiveDate asc) as rowid
from ARC_Content Where ContentID = #ContentID) as test
Where rowid = #rowID)
its just when i try to add the update/set it won't work. I am probably missing something
UPDATE TBL_Content
Set TBL_Content.txtPageContent = (select txtPageContent
FROM (select *, Row_Number() OVER (ORDER BY ArchiveDate asc) as rowid
from ARC_Content Where ContentID = #ContentID) as test
Where rowid = #rowID)
Thanks for the help! (i have tried top 1 with no avail)
I see a few issues with your update. First, I don't see any joining or selection criteria for the table that you're updating. That means that every row in the table will be updated with this new value. Is that really what you want?
Second, the row number between what is on the GUI and what you get back in the database may not match. Even if you reproduce the query used to create your list in the GUI (which is dangerous anyway, since it involves keeping the update and the select code always in sync), it's possible that someone could insert or delete or update a row between the time that you fill your list box and send that row number to the server for the update. It's MUCH better to use PKs (probably IDs in your case) to determine which row to use for updating.
That said, I think that the following will work for you (untested):
;WITH cte AS (
SELECT
txtPageContent,
ROW_NUMBER() OVER (ORDER BY ArchiveDate ASC) AS rowid
FROM
ARC_Content
WHERE
ContentID = #ContentID)
UPDATE
TC
SET
txtPageContent = cte.txtPageContent
FROM
TBL_Content TC
INNER JOIN cte ON
rowid = #rowID