ORACLE SQL: Look for last row in column then update data from another data without affecting older data - sql

i'm currently learning to code in Oracle SQL. Referring to example on photo i attached, I would like to my script to look for last date in Table A, if the date (Table A) is less than date in Table B, then insert only the latest date data from Table B to A without affecting older date data in Table A.
.
The reason is because Table B data is store by month, meaning that month Jan data will be purge out when going to Feb. So the purpose of Table A is to retain all the data i want from Table B.
And how do i embedded the script in table so that it autorun everyday?

Try this:
insert into TableA (
select * from TableB where date >(select max(date) from TableA)
);

If I understand correctly, in Oracle 12c+, you can use:
insert into a (date, sales)
select date, sales
from b
where b.date > (select max(a.date) from a)
order by date desc
fetch first 1 row only;
The order by and fetch ensure that only the most recent row is inserted.
In earlier versions, you can use a subquery:
insert into a (date, sales)
select date, sales
from (select b.*, row_number() over (order by date desc) as seqnum
from b
where b.date > (select max(a.date) from a)
) b
where seqnum = 1;
Note: If you run this code every day, you will just end up inserting every row of b into a. I assume you are aware of that.

Related

Finding Max(Date) BEFORE specified date in Redshift SQL

I have a table (Table A) in SQL (AWS Redshift) where I've isolated my beginning population that contains account id's and dates. I'd like to take the output from that table and LEFT join back to the "accounts" table to ONLY return the start date that precedes or comes directly before the date stored in the table from my output.
Table A (Beg Pop)
-------
select account_id,
min(start_date),
min(end_date)
from accounts
group by 1;
I want to return ONLY the date that precedes the date in my current table where account_id match. I'm looking for something like...
Table B
-------
select a.account_id,
a.start_date,
a.end_date,
b.start_date_prev,
b.end_date_prev
from accounts as a
left join accounts as b on a.account_id = b.account_id
where max(b.start_date) less than a.start_date;
Ultimately, I want to return everything from table a and only the dates where max(start_date) is less than the start_date from table A. I know aggregation is not allowed in the WHERE clause and I guess I can do a subquery but I only want the Max date BEFORE the dates in my output. Any suggestions are greatly appreciated.
I want to return ONLY the date that precedes the date in my current table where account_id match
If you want the previous date for a given row, use lag():
select a.*,
lag(start_date) over (partition by account_id order by start_date) as prev_start_date
from accounts a;
As I understand from the requirement is to display all rows from a base table with the preceeding data sorted based on a column and with some conditions
Please check following example which I took from article Select Next and Previous Rows with Current Row using SQL CTE Expression
WITH CTE as (
SELECT
ROW_NUMBER() OVER (PARTITION BY account_id ORDER BY start_date) as RN,
*
FROM accounts
)
SELECT
PreviousRow.*,
CurrentRow.*,
NextRow.*
FROM CTE as CurrentRow
LEFT JOIN CTE as PreviousRow ON
PreviousRow.RN = CurrentRow.RN - 1 and PreviousRow.account_id = CurrentRow.account_id
LEFT JOIN CTE as NextRow ON
NextRow.RN = CurrentRow.RN + 1 and NextRow.account_id = CurrentRow.account_id
ORDER BY CurrentRow.account_id, CurrentRow.start_date;
I tested with following sample data and it seems to be working
create table accounts(account_id int, start_date date, end_date date);
insert into accounts values (1,'20201001','20201003');
insert into accounts values (1,'20201002','20201005');
insert into accounts values (1,'20201007','20201008');
insert into accounts values (1,'20201011','20201013');
insert into accounts values (2,'20201001','20201002');
insert into accounts values (2,'20201015','20201016');
Output is as follows

SQL query to sum a column prior to date and show all entries after that date

I have a table where limits were sanctioned to the customer
I am trying to get the output as below picture i.e. total amount sanctioned till particular date
I am trying below code but this sums the total sanction amount
select gam.id, sum(SANCTION_AMOUNT) from gam
join (select ID,ACCOUNT_OPEN_DATE from gam where ACCOUNT_OPEN_DATE between'01-04-2019' and '30-04-2019' AND SCHEME_CODE IN ('SB','CCKLY')) ) action
on( gam.ACCOUNT_OPEN_DATE <=action.ACCOUNT_OPEN_DATE and gam.id=action.cust_id) group by gam.id;
In Oracle, this can be a way:
select id, sanction_amount, scheme_code, account_open_date,
sum(sanction_amount) over (partition BY ID order by account_open_date) as total_sanction_amount
from gam
order by account_open_date
Not sure your database is MySQL or Oracle, But this below script is workable in most of the database. Just adjust the table and column names accordingly.
You can check MySQL DEMO HERE
SELECT *,
(
SELECT SUM(sanction_Amount)
FROM Your_Table B
WHERE B.ID = A.ID
AND B.acc_open_date <= A.acc_open_date
) Total_sanction_Amount
FROM Your_Table A

Join Table B to Table A, where Table B is an audit history, and only want the most recent Table B entry that is before a date on Table A

SQL Server 2008 R2 (yup, we are past the extended support date)
Table A has a VendorID and a date. Each VendorID is present only one time.
A snippet of Table B is below. Table B can have the same VendorID multiple times, with various dates. (It shows a history of the VendorID status.)
How can I join Table B to Table A, such that I get the most recent entry for Table B, that is less than the date for that row in Table A?
Say if I wanted just "give me the most recent entry from Table B, by vendor ID, that is before data 'yyyy-mm-dd' - not so bad. I could use a window function, then just join it to Table A.
But I don't want to do this for a single date, the data would vary by the date in the row for table A.
-- Example for if I were grabbing the most recent entry from Table B, by VendorId, by a set date. Then I could just join the results, no problem.
select
sq.VendorId
,sq.PaymentType
from (
select
a.VendorId
,a.PaymentType
,row_number() over (partition by a.vendorid order by createdateutc
desc) as rn
from
ZpCustomers_Kim.dbo.VendorListPaymentTypeChangeAudit a --**Table B**
WHERE
CreateDateUTC < '2019-05-09'
) sq
where
sq.rn = 1
But if I want to, instead of using '2019-05-19', have the date depend on the date in the row for Table A, how could I do that?
I am not sure what your query has to do with the question. But you can do what you want with apply:
select a.*, b.*
from a outer apply
(select top (1) b.*
from b
where b.VendorID = a.VendorID and
b.date <= a.date
order by d.ate desc
) b;

How to select multiple rows in SQL Server while filling one column with the first value

Each of my rows have a date. I want the database to keep the good date. But I am in a situation where I want only the first date. But I still want all the other rows. So I would like to fill the date column with all the same date in my result.
For an example (Because I don't think I expressed myself well)
I have this:
name value date
a 10 5/13
b 14 2/13
c 20 1/13
a 11 7/13
a 5 8/13
b 8 9/13
I want it to become like this in the result:
name value date
a 26 5/13
b 22 5/13
c 20 5/13
I searched for this information but I only find the way to select the first row.
for now I'm doing
SELECT name, SUM(value), date FROM table
ORDER BY name
And I'm kind of clueless for what to do next.
Thanks :)
Databases don't have a concept of "first". Here is an attempt, but no guarantees unless you have a way of ordering to determine first:
select name, sum(value), const.date
from table cross join
(select top 1 date from table) const
group by name, const.date
If you only want to do this for a query, to provide this aggregated data for some specific client requirement, then #freshPrince's answer is appropriate. But if want to actually modify the data in the table itself, and prevent the issue from arising again, then you need to change the schema.
Create Table newTable(
name varChar(30) not null,
date datetime not null,
value decimal(10,2) not null default(0),
primary key (name, date) )
Insert newTable (name, date, value)
Select name, SUM(value), Min(date)
FROM currentTable
Group By Name
and delete the old table... then rename the new table to whatever...
You will also have to modify the process used to insert new rows so that instread of always inserting a new row, it updates the existing row for a specified name and date if it already exists...
Your question is slightly confusing since your desired result is showing a date that does not exists with either b or c but if that is the result that you want want you could use something similar to the following:
select name, sum(value) value, d.date
from yt
cross join
(
select min(date) date
from yt
where name = (select min(name)
from yt)
) d
group by name, d.date;
See SQL Fiddle with Demo
But it seems like you actually would want the min(date) for each name:
select name, sum(value) value, min(date)
from yt
group by name;
See SQL Fiddle with Demo.
If the order of the date should be the determined by the name then you could use:
select t.name, sum(value) value, d.date
from yt t
cross join
(
select top 1 name, date
from yt
order by name, date
) d
group by t.name, d.date;
See Demo

Update row only where max date

I have the following data
Date Week ID Tot_Seconds O_Seconds Week_ID
8/14/2011 12:00:00 AM 5823 22180 170043 26043 18
8/21/2011 12:00:00 AM 5824 22180 126471 0 18
I am trying to update a column in another table the value of O_Seconds,where the week and ID match, but i would only like to update where max(date) for each Week. The reason, is the table with the data source has dates by week, where the the table I will update is daily, and using the query I currently have, it updates for example 26043 for all days where id and week match, skewing my future queries where I will sum the values of those columns.
Is there any way to just update the max date?
Something like this
The derived table is used to get the 1st row per week/ID
UPDATE
O
SET
SomeCol = S.O_Second
FROM
OtherTable O
JOIN
(
SELECT
Week, ID, O_Second,
ROW_NUMBER() OVER (PARTITION BY Week, ID ORDER BY Date DESC) AS rn
FROM
ThisTable
) S ON O.Week = S.Week AND O.ID = S.ID
WHERE
S.rn = 1
For SQL Server 2000 and earlier you need an aggregate. See DBA.SE for more