update with the latest date - sql

I have a table as shown below:
I need to update them into the latest last_order_date, which the table can be shown as below:
I have 20000 plus records, I need a query to update them at once.
Thank you for spending your time to look at it.

Using join on max calculating subquery
UPDATE t
SET t.last_order_date =a.maxDate
FROM tableName t
INNER JOIN
( SELECT cust_id ,MAX(last_order_date) As maxDate
FROM tableName GROUP BY cust_id ) a
ON a.cust_id =t.cust_id

This should work for you:
UPDATE [table_name]
SET last_order_date = (SELECT Max([b].last_order_date)
FROM [table_name] [b]
WHERE [b].cust_id = [table_name].cust_id);

You could calculate the maximum dates in a CTE using a window MAX(), then reference the CTE in the main (UPDATE) statement:
WITH maxdates AS (
SELECT
last_order_date,
actual_last_order_date = MAX(last_order_date) OVER (PARTITION BY cust_id)
FROM atable
)
UPDATE maxdates
SET last_order_date = actual_last_order_date
;
However, duplicating this piece of information like this doesn't seem to make much sense. You should probably consider storing last_order_date in a table where cust_id is the primary key (probably some customers table). Or even abandon storing it in a table and calculate it dynamically every time: 20,000 rows isn't really that much. (Unless you have serious expectations for that number to grow rapidly and soon.)

Related

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

Trying to get the greatest value from a customer on a given day

What I need to do: if a customer makes more than one transaction in a day, I need to display the greatest value (and ignore any other values).
The query is pretty big, but the code I inserted below is the focus of the issue. I’m not getting the results I need. The subselect ideally should be reducing the number of rows the query generates since I don’t need all the transactions, just the greatest one, however my code isn’t cutting it. I’m getting the exact same number of rows with or without the subselect.
Note: I don’t actually have a t. in the actual query, there’s just a dozen or so other fields being pulled in. I added the t.* just to simplify the code example.*
SELECT
t.*,
(SELECT TOP (1)
t1.CustomerGUID
t1.Value
t1.Date
FROM #temp t1
WHERE t1.CustomerGUID = t.CustomerGUID
AND t1.Date = t.Date
ORDER BY t1.Value DESC) AS “Value”
FROM #temp t
Is there an obvious flaw in my code or is there a better way to achieve the result of getting the greatest value transaction per day per customer?
Thanks
you may want to do as follows:
SELECT
t1.CustomerGUID,
t1.Date,
MAX(t1.Value) AS Value
FROM #temp t1
GROUP BY
t1.CustomerGUID,
t1.Date
You can use row_number() as shown below.
SELECT
*
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerGUID ORDER BY Date Desc) AS SrNo FROM <YourTable>
)
<YourTable>
WHERE
SrNo = 1
Sample data will be more helpful.
Try this window function:
MAX(value) OVER(PARTITION BY date,customer ORDER BY value DESC)
Its faster and more efficient.
Probably many other ways to do it, but this one is simple and works
select t.*
from (
select
convert(varchar(8), r.date,112) one_day
,max(r.Value) max_sale
from #temp r
group by convert(varchar(8), r.date,112)
) e
inner join #temp t on t.value = e.max_sale and convert(varchar(8), t.date,112) = e.one_day
if you have 2 people who spend the exact same amount that's also max, you'll get 2 records for that day.
the convert(varchar(8), r.date,112) will perform as desired on date, datetime and datetime2 data types. If you're date is a varchar,char,nchar or nvarchar you'll want to examine the data to find out if you left(t.date,10) or left(t.date,8) it.
If i've understood your requirement correctly you have stated"greatest value transaction per day per customer". That suggests to me you don't want 1 row per customer in the output but a row per day per customer.
To achieve this you can group on the day like this
Select t.customerid, datepart(day,t.date) as Daydate,
max(t.value) as value from #temp t group by
t.customerid, datepart(day,t.date);

How can I overwrite a column from a column in another table without a join?

I want to simply overwrite values in a column of a table with values from a column in another table.
I have a table based off from another table without a unique identifier in one of the columns, so I don't want to use joins, but just update the values since the rows are in the same order. How do I do that? So far I have tried two different approaches where Approach A only put the value from the first row into every row of the updated table whereas Approach B does not work at all.
Approach A:
Update Transactions
SET Transactions.Amount = Transactions_raw.Amount
FROM Transactions_raw
Approach B:
UPDATE Transactions
SET Amount = (SELECT Amount FROM Transactions_raw)
You need some kind of join to match the tables -- even if on an artificial key:
update t
set Amount = tr.Amount
from (select t.*, row_number() over (order by (select null)) as seqnum
from Transactions t
) t join
(select tr.*, row_number() over (order by (select null)) as seqnum
from Transactions_raw tr
) tr
on t.seqnum = tr.seqnum;
Your assumption that the rows are in the same order may mislead you. If you do select statement without order by and see the same order in both tables, this is not what you want rely on. This so called order is not guaranteed. Instead, you have to have some rule for ordering. When you have this rule, which you can place in order by, then you can add ID column to both tables according to this order.
You can calculate ID value using statement:
update Transactions
set Id = row_number() over(order by ...)
Then you can use regular inner join.

Complex Aggregations in SQL

All I want to do is get a data set that shows me how many orders were placed and how many calls were made for each order. I also need the date of the calls and the date of the order, in the same table. The table is 10M+ rows, so aggregation of the result set is essential for analysis. The only analysis I want to do is the sum of calls/the total orders, and to be able to see how many support_tickets were generated from orders within an order range, up to a call_date. Very simple, but surprisingly complex to code up. Here is my attempt. I have also tried to change the below into a union, but still get wrong aggregate results.
-- The Query:-
SELECT
category_name
count(order_code)
order_date
sum(support_ticket_call)
call_date
FROM
(Select distinct name, order_code, order_date from table1) b
left join
(select count(call_ids), call_date FROM table2) b
on b.order_ID_code = a.order_id_code
group by category_name, order_date, call_date
Whenever there are no support_ticket_calls, the call_date is NULL, as you would expect. The count of orders is like 60,000 though, which is different from the usual 12 or so in the rest of the result set. I know something is wrong with this query, but It's driving me insane trying to solve it, literally all day so far.
It's a little difficult to answer this question without sample data and expected results, but the comment was getting too long.
You have several problems with your current query. First you need to join on the date fields by using on criteria. You also need to add group by to those queries that use aggregation. Finally, where does support_ticket_call come from? Can I presume it's the alias for the count(call_ids)?
Something like this should get you close:
SELECT
a.name as category_name,
count(a.order_code),
sum(b.support_ticket_call),
a.order_date as call_date
FROM
(Select distinct name, order_code, order_date
from table1) a
left join
(select count(call_ids) as support_ticket_call, call_date
from table2 group by call_date) b on a.order_date = b.call_date
group by a.name, a.order_date

How to add a column with specific values to an existing database table

I needed an advice regarding a SQL statement that has to run with DB2 and Oracle.
Some time ago a database table has been set up without an ID column. Adding the ID column is not the problem but I absolutely need to fill it with the row number of each row.
I found out, that rank() would be perfect but here I'm not able to select for specific values because then I always get the value '1'.
When I set up an intermediate table as described below, I output all data, that I need
WITH MY_TEMP_TABLE AS
(
SELECT RANK() OVER (ORDER BY CODE ASC) MY_ROW, CODE, LAND
FROM SECOND_TABLE
)
SELECT *
FROM SECOND_TABLE
INNER JOIN MY_TEMP_TABLE ON SECOND_TABLE.CODE=MY_TEMP_TABLE.CODE
How is it possible to update the ID column in the database table (here: SECOND_TABLE) with the values in MY_ROW?
Thanks a lot...
Use row_number() instead of rank():
WITH MY_TEMP_TABLE AS
(
SELECT row_number() OVER (ORDER BY CODE ASC) MY_ROW, CODE, LAND
FROM SECOND_TABLE
)
SELECT *
FROM SECOND_TABLE
INNER JOIN MY_TEMP_TABLE ON SECOND_TABLE.CODE=MY_TEMP_TABLE.CODE