Oracle group by clause in order of the data - sql

I am trying to group the data below in a particular order that I have received it in my PL/SQL procedure. A custom table type FOIL_MAP is populated in my procedure and currently contains the data as shown below:
https://i.stack.imgur.com/ovZEQ.png
I wrote the query:
select Foil_Keys, count(Foil_Keys) FCNT from Table(FOIL_MAP) group by Foil_Keys;
I got the Output:
https://i.stack.imgur.com/Xe6z7.png
Is there any way to make the group by clause to return the data in the exact order that it was given in! Like this image shown below?
https://i.stack.imgur.com/e06Lj.png

select Foil_Keys, count(Foil_Keys) FCNT from Table(FOIL_MAP) group by Foil_Keys
order by foil_keys desc

...to return the data in the exact order that it was given in...
No, I'm sorry but no.
You want to return the data in the order it was inserted into the table. The SQL standard does not specify any order when returning the rows. The database can return the data in any order and that's OK; the order may even change in time. Now, if you want any particular order you need to use ORDER BY.
Alternative Solution with Extra Column
Anyway, if you want to return the data in the order it was inserted, then you'll need to add an extra column in the table to represent the date/time of the data insertion. If you do that, you could order by that column.
If a timestamp column is not good enough due to tiny granularity of your inserts (so there could be collissions in values) then you can use a sequence.
alter table foil_map add (my_order decimal(12) not null);
create sequence insert_order_seq;
and when inserting into the table:
insert into foil_map (col1, col2, ..., my_order)
values (val1, val2, ..., insert_order_seq.nextval);
and your query would become:
select foil_keys, count(foil_keys) fcnt
from foil_map
group by foil_keys
order by max(my_order);

Related

Insert Column with same value

I am running a query on the table "performance" and I want to insert a column with the same value for all the rows without using alter, update etc.
I wrote a case statement and it works but is there a more refined way?
here is a short query:
SELECT id, name, class,
CASE
WHEN id IS NOT NULL THEN 'Actuals'
ELSE 'Forecast'
END AS type
FROM performance
Basically I need all the values to be labeled "Actuals".
There are many other datasets for which I will use different labels and then append all of them
Just to be clear - don't need to update the table performance itself
use common table expression for your case.
It will add new column in your existing data and you may use this for your further process.
For your point it is not adding nor inserting anything in your existing db structure.
with CTE as (
SELECT id, name, class,
CASE WHEN id IS NOT NULL THEN 'Actuals' ELSE 'Forecast' END AS type
FROM table_performance
)
select * from CTE ----- It give you all the columns from [table] and add another column as you needed.
OR
You may create a view for same, if this condition is fixed.

Add timestamp to existing table

I have a SQL Server table with just 3 columns, one of which is of type varbinary. The data in this column is actually a Json document which among other properties contains information about when the data was last modified. Unfortunately the SQL table itself does not contain information about when its rows were modified.
Now when doing sorting and filtering of the data I of course don't want fetch all rows in order to find e.g. the latest 100 entries.
So my question is: does SQL Server somehow remember when a row was added/modified? I have tried adding a timestamp and this is applied to all existing rows but this is applied randomly I think, because the sorting doesn't work. I don't need a datetime or anything, I just want to be able sort the records based on when they were last modified.
Thanks
For those looking to insert a tamestamp column of type DateTime into an existing DB table, you can do this like so:
ALTER TABLE TestTable
ADD DateInserted DATETIME NOT NULL DEFAULT (GETDATE());
The existing records will automatically get the value equal to the date/time of the moment when column is added.
New records will get up-to-date value upon insertion.
SQL Server will not track historically when a row was inserted or modified so you need to rely on the JSON data to figure that out yourself. You are going to need a new column to make this efficient to query. Once you have your new column you have some options:
Loop through all your records populating the new column with the relevant value from the JSON data.
If your version of SQL Server is recent enough, you can query the JSON data directly. Populate this column using a query like this:
UPDATE MyTable
SET MyNewColumn = JSON_VALUE(JsonDataColumn, '$.Customer.DateCreated')
The downside of this method is that you need to maintain this
Make SQL Server compute the value from the JSON automatically, for example:
ALTER TABLE MyTable
ADD MyNewColumn AS JSON_VALUE(JsonDataColumn, '$.Customer.DateCreated')
And, create an index to make it efficient:
CREATE INDEX IX_MyTable_MyNewColumn
ON MyTable(MyNewColumn)
Use a new column CreatedDate and store datetime every time you make an Insert.
You could use GetDate() for inserting date in the column.
A UpdatedDate column can be used for updates.
in order to find e.g. the latest 100 entries.
Timestamp is indeed what you need.
It's ever-increasing value, it's updated automatically, so you are always able to find all last modified/inserted rows.
Here is an example:
create table dbo.test1 (id int);
insert into dbo.test1 values(1), (2), (3);
alter table dbo.test1 add ts timestamp;
update dbo.test1
set id = 10
where id = 2
select top 1 *
from dbo.test1
order by ts desc;
--id ts
--10 0x000000001FCFABD2
insert into dbo.test1 (id)
values (100);
select top 1 *
from dbo.test1
order by ts desc;
--id ts
--100 0x000000001FCFABD3
As you see, you always get the last modified/inserted row.
For your purpose just use
select top 100 *
...
order by ts desc;
Thanks. Apparently I didn't look hard enough before I posted this question. The question has been asked a couple of times before and the answer is: Nope! There is no easy solution to this.
SQL Server does not keep track of when a record was created or modified, which was somehow what I was looking for. So I will go for the next best solution, which is probably to create a datetime column, retrieve the modified date from the Json document and then update the record. Or rather, the 1,4 million records:-(

How to insert generated id into a results table

I have the following query
SELECT q.pol_id
FROM quot q
,fgn_clm_hist fch
WHERE q.quot_id = fch.quot_id
UNION
SELECT q.pol_id
FROM tdb2wccu.quot q
WHERE q.nr_prr_ls_yr_cov IS NOT NULL
For every row in that result set, I want to create a new row in another table (call it table1) and update pol_id in the quot table (from the above result set) with the generated primary key from the inserted row in table1.
table1 has two columns. id and timestamp.
I'm using db2 10.1.
I've tried numerous things and have been unsuccessful for quite a while. Thanks!
Simple solution: create a new table for the result set of your query, which has an identity column in it. Then, after running your query, update the pol_id field with the newly generated ID in your result table.
Alteratively, you can do it more manually by using the the ROW_NUMBER() OLAP function, which I often found convenient for creating IDs. For this it is convenient to use a stored procedure which does the following:
get the maximum old id from Table1 and write it into a variable old_max_id.
after generating the result set, write the row-numbers into the table1, maybe by something like
INSERT INTO TABLE1
SELECT ROW_NUMBER() OVER (PARTITION BY <primary-key> ORDER BY <whatever-you-want>)
+ OLD_MAX_ID
, CURRENT TIMESTAMP
FROM (<here comes your SQL query>)
Either write the result set into a table or return a cursor to it. Here you should either use the same ROW_NUMBER statement as above or directly use the ID from Table1.

Select last value in a specific column? (PostgreSQL)

Running into some issues when trying to retrieve the last value in a specific column, from a table and assign it into a variable.
Looking for the last int in a column "id" that is a primary key basically.
So I have a variable like "lastValue" in a select statement like :
select last(id) into lastValue from test_table
Not sure on an exact, or best way to accomplish this.
(on mobile, please forgive formatting)
A typical way to solve this is with order by and limit:
select id
from test_table
order by id desc
limit 1;
Of course, in this case, you could simply use:
select max(id)
from test_table;
But the first method allows you to choose whichever variables you want from the row with the maximum value.

Generating incremental numeric column values during INSERT SELECT statement

I need to copy some data from one table to another in Oracle, while generating incremental values for a numeric column in the new table. This is a once-only exercise with a trivial number of rows (100).
I have an adequate solution to this problem but I'm curious to know if there is a more elegant way.
I'm doing it with a temporary sequence, like so:
CREATE SEQUENCE temp_seq
START WITH 1;
INSERT INTO new_table (new_col, copied_col1, copied_col2)
SELECT temp_seq.NEXTVAL, o.*
FROM (SELECT old_col1, old_col2
FROM old_table,
ORDER BY old_col1) o;
DROP SEQUENCE temp_seq;
Is there way to do with without creating the sequence or any other temporary object? Specifically, can this be done with a self-contained INSERT SELECT statement?
Please consider a trigger to be a non-option.
MORE INFO: I would like to control the order that the new rows are inserted, and it won't be the same order they were created in the old table (note I've added the ORDER BY clause above). But I still want my new sequential column to start from 1.
There are similar questions, but I believe the specifics of my question are original to SO.
You can use ROWNUM. This pseudo-column numbers the rows in your result:
Insert Into new_table (new_col, copied_col1, copied_col2)
Select Rownum, old_col1, old_col2
From old_table;
If you want your records to be sorted, you need to use a sub-query:
Insert Into new_table (new_col, copied_col1, copied_col2)
Select Rownum, old_col1, old_col2
From (
Select old_col1, old_col2
From old_table
Order By old_col1
);
Why don't you define the column new_col as primary_key or unique and mark it as autoincrement?
This way each insert will get the next higher "count".
I'm not pretty familiar with oracle, but i would bet there is a built in autoincrement function.