How do I get the second last date in proc sql? - sql

I'm writing a query in SQL to get the First, Last and Second last Transaction date for Customers. I have added the first and last using the Min() and Max() functions, how can I add the second last date in my query?
select distinct Shoppers, Min(Date) as First_Txn, Max(Date) as Last_Txn,
sum(revenue_sale) as Revenue, sum(units) as Units, count(distinct invoice) as Invoices,
from myTable
where Date between 20220101 and 20220131
group by 1;

Related

SQL List previous sales of dates in the current month

On the sql side, as seen in the table below, I want to subtract the sale of the day before today's date and have it printed in a separate column.
example; Subtract the sale on 2022-04-17 from the sale on 2022-04-18 and write it in the side column.
subtract the sales from the previous day until you find the last date in the table in a loop.
You can try to use LEAD window function with CASE WHEN expression
SELECT *,
CASE WHEN LEAD(n_Sales) OVER(PARTITION BY CustomerId,ProductId ORDER BY Date DESC) IS NULL
THEN Sales ELSE
Sales - LEAD(n_Sales) OVER(PARTITION BY CustomerId,ProductId ORDER BY Date DESC)
END
FROM T

SQL Query Help Finding Highest Order Value From Each Day

I have two tables, Customer and Order.
In the Order table, I have a column called date_time that stores the date and time of an order. I also have the CustomerID.
I want to get the customers ID for the orders with the highest value from that day.
This is the query to retrieve the order with the highest amount in each day:
SELECT
MAX(order_amount) AS "Highest Day Amount",
to_char(date_time, 'dd/mm/yyyy') AS "ORDER DATE"
FROM
orders
GROUP BY
to_char(date_time, 'dd/mm/yyyy');
I need to use to_char because the date_time column contains both the date and time (for example: 19/05/2021 17:50) and if I don't use the to_char because I have more than one order in each day, it will consider the date to be different, because of the time component, and it will list two orders on that day instead of 1 order with the highest total.
And then I want to fetch the customer id from those orders, however I'm not sure how to do that.
I want to get the customers ID for the orders with the highest value from that day.
You should not need to_char(), but how you truncate to the date depends on the database. The key idea is that you want to use a window function:
SELECT o.*
FROM (SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY to_char(date_time, 'YYYY-MM-DD') ORDER BY order_amount DESC) as seqnum
FROM orders o
) o
WHERE seqnum = 1;
This returns the entire row with the highest order amount. You can format the result set how you want.
In Oracle, you can do this with aggregation. I would recommend:
select trunc(date_time), max(order_amount),
max(customer_id) keep (dense_rank first order by order_amount desc) as customer_id
from orders o
group by trunc(date_time);
The keep syntax is Oracle's (rather verbose) way of implementing a "first" aggregation function.
You only need to add your customers IDcto the select and the group by
SELECT MAX(order_amount) as "Highest Day Amount", to_char(date_time, 'dd/mm/yyyy') AS "ORDER DATE", customerID
FROM orders GROUP BY to_char(date_time, 'dd/mm/yyyy'), customerID
If you want more details from customers, you will need to join this table to customers table

Is there a way to count how many strings in a specific column are seen for the 1st time?

**Is there a way to count how many strings in a specific column are seen for
Since the value in the column 2 gets repeated sometimes due to the fact that some clients make several transactions in different times (the client can make a transaction in the 1st month then later in the next year).
Is there a way for me to count how many IDs are completely new per month through a group by (never seen before)?
Please let me know if you need more context.
Thanks!
A simple way is two levels of aggregation. The inner level gets the first date for each customer. The outer summarizes by year and month:
select year(min_date), month(min_date), count(*) as num_firsts
from (select customerid, min(date) as min_date
from t
group by customerid
) c
group by year(min_date), month(min_date)
order by year(min_date), month(min_date);
Note that date/time functions depends on the database you are using, so the syntax for getting the year/month from the date may differ in your database.
You can do the following which will assign a rank to each of the transactions which are unique for that particular customer_id (rank 1 therefore will mean that it is the first order for that customer_id)
The above is included in an inline view and the inline view is then queried to give you the month and the count of the customer id for that month ONLY if their rank = 1.
I have tested on Oracle and works as expected.
SELECT DISTINCT
EXTRACT(MONTH FROM date_of_transaction) AS month,
COUNT(customer_id)
FROM
(
SELECT
date_of_transaction,
customer_id,
RANK() OVER(PARTITION BY customer_id
ORDER BY
date_of_transaction ASC
) AS rank
FROM
table_1
)
WHERE
rank = 1
GROUP BY
EXTRACT(MONTH FROM date_of_transaction)
ORDER BY
EXTRACT(MONTH FROM date_of_transaction) ASC;
Firstly you should generate associate every ID with year and month which are completely new then count, while grouping by year and month:
SELECT count(*) as new_customers, extract(year from t1.date) as year,
extract(month from t1.date) as month FROM table t1
WHERE not exists (SELECT 1 FROM table t2 WHERE t1.id==t2.id AND t2.date<t1.date)
GROUP BY year, month;
Your results will contain, new customer count, year and month

Oracle SQL Accumulated value for the date

I have a table with 3 columns: id, date and amount, but I would like to get accumulated SUM for each date (Last column).
Do you have an easy solution how to add this column?
I am trying with this:
SELECT date, sum(amount) as accumulated
FROM table group by date
WHERE max(date);
Should I user OVER() for this?
Use a window function to the total for each day:
SELECT date,
amount,
sum(amount) over (partition by date) as accumulated
FROM the_table;
However this will only work, if your dates all have the same time part (in Oracle a DATE column also contains a time). To make sure you ignore the time part, use trunc() to make sure all time parts are normalized to 00:00:00
SELECT date,
amount,
sum(amount) over (partition by trunc(date)) as accumulated
FROM the_table;
Use This:
SELECT T.ID, T.DATE, T.AMOUNT, (SELECT SUM(S.AMOUNT) FROM TABLE S WHERE S.DATE=T.DATE) ACCUMULATED
from
table T
This will give you the records from the table with a sum for all records for the date.

Select per month

I've got the following table:
purchases(id, item, user, price, time);
The time field is a timestamp.
I need a query that would return one row per month and that row would contain the sum of price for each item in that month.
Try this:
SELECT MONTH(`time`) AS month, SUM(price) AS price
FROM your_table
GROUP BY MONTH(`time`)
If you have more than one year's data you may also want to include the year in your group by:
SELECT YEAR(`time`) AS year, MONTH(`time`) AS month, SUM(price) AS price
FROM your_table
GROUP BY YEAR(`time`), MONTH(`time`)
what about GROUP BY YEAR(DATE(time)) ASC, MONTH(DATE(time)) ASC?