I have a Sales table showing product number, sales value, and sales volume per week. I need to build a report to display these values and volumes along with the equivalent values from the previous week. I also have a Weeks table which gives me the previous week number for the current week (for instance if current week is 2013-01, then the previous week value is 2012-52).
I therefore assumed it would be simple enough to join to another instance of Sales on product number and previous week number from the Weeks table. However Teradata is not letting me do this, initially it threw an error of Improper column reference in the search condition of a joined table and when I re-ordered the query to reference Weeks before the second instance of Sales it now tries to run but gives me a No more spool space error, so I assume my approach is incorrect. My SQL is as follows:
select s.Week_Number,
s.Product_Number,
s.Sales_Value,
s.Sales_Volume,
s_lw.Sales_Value,
s_lw.Sales_Volume
from SALES s
inner join WEEKS w
on s.Week_Number = w.Week_Number
left join SALES s_lw
on s.Product_Number = s_lw.Product_Number
and s_lw.Week_Number = w.Last_week_Number
Could anyone please suggest what I'm doing wrong here? It seems like this should be achievable.
I would suggest using a Window Aggregate Function to accomplish this with a single pass of the SALES table:
SELECT DISTINCT
s.Week_Number,
s.Product_Number,
s.Sales_Value,
s.Sales_Volume,
MAX(s.Sales_Value) OVER (PARTITION BY s.Product_Number
ORDER BY s.Week_Number DESC
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS LW_Sales_Value,
MAX(s.Sales_Volume) OVER (PARTITION BY s.Product_Number
ORDER BY s.Week_Number DESC
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS LW_Sales_Volume
FROM SALES s;
Related
I am trying to do a count by month of the total number of items (serialnumber) that appears in inventory.
This usually can be easily solved with distinct, however, I only want to count if it is the first occurrence that it appears (first insert).
This query gets me most of the way there.
select date_trunc (‘month’,date) as Date,productid, count(distinct serialnumber) from inventory
where date_trunc(‘month’,date)>= ‘2016-01-01’ and productID in ('1','2') and status = ‘INSERT’
group by date_trunc(‘month’,date), productid
order by date_trunc(‘month’,date) desc
But I realize I am double/triple/quadruple counting some serial numbers because an item can reappear in our inventory multiple times over the course of its lifecycle.
The query above covers these scenarios since the serial numbers appear once:
Shows up as new
Shows up as used
Below are the use cases where I realize I may be double/triple/quadruple counting:
Shows up as new then comes back around as used (no limit to how many times it can appear used)
Shows up used then comes back again as used (no limit to how many times it can appear used)
Here's an example I ran into.
(Note: I have added the condition column to better illustrate this). But the particular serial number has been in inventory three times (first as new, then as used twice)
Date
ProductID
Count
Condition
7-1-21
1
1
u
11-1-18
1
1
u
2-1-17
1
1
n
In my current query results, each insert gets counted (once in Feb 2017, once in Nov 2018 and once in July 2021).
How can I amend my query to make sure I'm only counting the very first instance (insert) a particular serial number appears in the inventory table?
In the subquery calculate first insert date only of each product/item using min aggregate function. Then count the items on that result:
select Date, productid, count(serialnumber)
from (
select min(date_trunc(‘month’,date)) as Date, productid, serialnumber
from inventory
where date_trunc(‘month’,date) >= ‘2016-01-01’
and productID in ('1','2')
and status = ‘INSERT’
group by productid, serialnumber
) x
group by Date, productid
order by Date desc;
I made really simple example table with columns date and credit, so we can sum all credit to get account saldo of the account. I can sum all credit values to get saldo, but that is not what I want. I want to calculate average saldo, so in order to do that I need to use RangeDate table with date of every day and query with this logic:
SELECT DRA.date, SUM(ACB.credit)
FROM AccountBalance ACB
JOIN DateRange DRA ON ACB.date <= DRA.date
GROUP BY DRA.date
http://sqlfiddle.com/#!18/88afa/10
the problem is when using this program on a larger range of dates, like whole year for example.
Instruction is telling SQL Engine to sum up all rows of credit before the current date including credit of the current row date (where the cursor is in that moment (JOIN... ACB.date <= DRA.date)), in order to get accounts credit for that day.
This is inefficient and slow for big tables because that sum already exists in the row 1 level before, and I would like to tell SQL Engine to take that sum and only add the one row of credit that it is in.
Somone told me that I should use LAG function, but i need an example first.
I think you simply need an analyitc function -
SELECT DRA.date,
SUM(ACB.saldo) OVER (ORDER BY DRA.date)
FROM DateRange DRA
LEFT JOIN AccountBalance ACB ON ACB.date = DRA.date;
Demo.
I have a table in Oracle database whith projected sales per week and would like to sum the next 3 weeks for each week. Here is an example of the table for one product and what I would like to achieve in the last column.
I tried the Sum(Proj Sales) over (partition by Product order by Date), but I am not sure how to configure the Sum Over to get what I am looking for.
Any assistance will be much appreciated.
You can use analytic functions. Assuming that the next three weeks are the current row and the next two:
select t.*,
sum(proj_sales) over (partition by product
order by date
rows between current row and 2 following
) as next_three_weeks
from t;
My source data includes Transaction ID, Date, Amount. I need a one week trailing average which moves on a daily basis and averaging amount per transaction. Problem is, that sometimes there is no transactions in particuliar date, and I need avg per transaction, no per day, and trailing average moves by day, not by week.In this particular case I can't use OVER with rows preceding. I'm stack with it :(
Data looks like this:
https://gist.github.com/avitominoz/a252e9f1ab3b1d02aa700252839428dd
There are two methods to doing this. One uses generate_series() to get all the results. The second uses a lateral join.
with minmax as (
select min(trade_date) as mintd, max(trade_date) as maxtd
from sales
)
select days.dte, s.values,
avg(values) over (order by days.dte
rows between 6 preceding and current row
) as avg_7day
from generate_series(mintd, maxtd, interval '1 day') days(dte) left join
sales s
on s.trade_dte = days.dte;
Note: this ignores the values on missing days rather than treating them as 0. If you want 0, then use avg(coalesce(values, 0)).
I am working with SQL queries and I have a table with months and prices and I am performing a Moving Average. My code is as follows:
SELECT month, prices,
round(AVG(SUM(prices)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND CURRENT ROW),2)
AS MA
FROM tblma
GROUP BY month
ORDER BY month;
Although to me it seems right obviously I am making a mistake I don't see.
My retuned error is: 00979. 00000 - "not a GROUP BY expression"
My original data has the following format:
ID | MONTH | PRICE
1 | 11 | 20.36
2 | 12 | 11.05
Basically I would like to add the Moving Average column at the right.
This is probably what you want, the Moving Average over the Summmed prices:
SELECT month, SUM(prices),
round(AVG(SUM(prices)) OVER
(ORDER BY month ROWS BETWEEN 1 PRECEDING AND CURRENT ROW),2)
AS MA
FROM tblma
GROUP BY month
ORDER BY month;
The problem is that you are trying to select prices but without an aggregate expression, or grouping by the price. If you remove the prices and just do SELECT month, round(AVG(SUM(prices)) something will be returned. The reason that you cannot select prices as well is if you have more than one price for the same month then you haven't specified how to deal with this.
Also, round(AVG(SUM)) will just return the rounded SUM of the values. It will first sum everything up, and then take the average of that number, which will be the number itself.