analyze range and if true tell me - sql

I want to see if the price of a stock has changed by 5% this week. I have data that captures the price everyday. I can get the rows from the last 7 days by doing the following:
select price from data where date(capture_timestamp)>date(current_timestamp)-7;
But then how do I analyze that and see if the price has increased or decreased 5%? Is it possible to do all this with one sql statement? I would like to be able to then insert any results of it into a new table but I just want to focus on it printing out in the shell first.
Thanks.

It seems odd to have only one stock in a table called data. What you need to do is bring the two rows together for last week's and today's values, as in the following query:
select d.price
from data d cross join
data dprev
where cast(d.capture_timestamp as date = date(current_timestamp) and
cast(dprev.capture_timestamp as date) )= cast(current_timestamp as date)-7 and
d.price > dprev.price * 1.05
If the data table contains the stock ticker, the cross join would be an equijoin.

You may be able to use query from the following subquery for whatever calculations you want to do. This is assuming one record per day. The 7 preceding rows is literal.
SELECT ticker, price, capture_ts
,MIN(price) OVER (PARTITION BY ticker ORDER BY capture_ts ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS min_prev_7_records
,MAX(price) OVER (PARTITION BY ticker ORDER BY capture_ts ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) AS max_prev_7_records
FROM data

Related

Identifying if a column is in descending order

I am using Microsoft SQL Server 2005 Management Studio. I am a bit new so I hope I am not breaking any rules. My data is 15 columns and almost a million rows, however I am just giving you a sample to get assistance on one area where I am stuck.
In the above example as you can see the column 'lastlevel' values are decreasing. Also you can see that data in the 'Last_read' column date range is from today to 14 days prior (it was ran yesterday hence April 27, also pls. disregard that for 1st customer date 2021/04/14 is missing, it is an anomaly).
Column 'Shipto' provides the customer number and each customer has max 14 rows of data.
Please disregard column 'current_reading' and rn
If look at 'lastlevel' again you will notice that the values are going down consistently, however on April 18th, it goes from 0.73 to 0.74, showing an increase of 0.01.
What I want to do is that whenever there is an increase at all, I want that whole customer's all 14 rows be removed from the output i.e. I only want to see customers that have the prefect descending data and no increases.
Can you help?
WITH
deltas AS
(
-- For each [Shipto]; deduct the preceding row's value and record it as the [delta]
-- Note, each [Shipto]'s first row's delta with therefor be NULL
SELECT
*,
lastlevel - LAG(lastlevel) OVER (PARTITION BY Shipto ORDER BY Last_Read, lastlevel DESC) AS delta
FROM
yourTable
),
max_deltas AS
(
-- Get the maximum of the deltas per [Shipto]
SELECT
*,
MAX(delta) OVER (PARTITION BY Shipto) AS max_delta
FROM
deltas
)
-- Return only rows where the delta never exceeds 0 (thus, never ascending over any timestep)
SELECT
*
FROM
max_deltas
WHERE
max_delta <= 0
I've ordered by Last_Read, lastlevel DESC such that if two readings are on the same date, it is assumed that the highest value should be considered to have happened first.

How to implement a reset when (Teradata) using ANSI SQL only?

enter image description here
I need to write a query that count the number of times customers transactions exceed 250 Pounds. Adding cumulatively until the sum exceeds 250 then reset and start from the following row until it exceeds 250 and so on. This functionality can be carried out using Teradata keywords 'RESET WHEN' yet I am supposed to create a query that's only composed of ANSI SQL SYNTAX.
Can anyone help with that?
SUM(sales) OVER (
PARTITION BY region
ORDER BY day_of_calendar
RESET WHEN sales < /* preceding row */ SUM(sales) OVER (
PARTITION BY region
ORDER BY day_of_calendar
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING)
ROWS UNBOUNDED PRECEDING
)
1: https://i.stack.imgur.com/lu4Jp.png This is a sample of the input of customer
enter image description here
And that's the output.
Every time the customer's total spent exceeds 250, I should be summing from 0 once again and find the day at which the customer exceeded 250 USD.
Without your table definitions and just a screenshot of a very limited dataset it is hard to test my answer on your data - so I'm showing it first on the dataset supplied in the match_recognize tutorial on live SQL and then with your columns:
SELECT
*
FROM
ticker MATCH_RECOGNIZE (
PARTITION BY symbol
ORDER BY tstamp
MEASURES
nvl(SUM(up.price),0) AS tot
ALL ROWS PER MATCH
PATTERN ( up* ) DEFINE
up AS SUM(up.price) - up.price <= 100
);
So on your table this would be something like
SELECT
*
FROM
your_table MATCH_RECOGNIZE (
PARTITION BY region
ORDER BY day_of_calendar
MEASURES
nvl(SUM(up.sales),0) AS tot
ALL ROWS PER MATCH
PATTERN ( up* ) DEFINE
up AS SUM(up.sales) - up.sales <= 250
);

I want NAV price as per (Today date minus 1) date

I have two tables. One is NAV where product daily new price is updated. Second is TDK table where item wise stock is available.
Now I want to get a summery report as per buyer name where all product wise total will come and from table one latest price will come.
I have tried below query...
SELECT dbo.TDK.buyer, dbo.NAV.Product_Name, sum(dbo.TDK.TD_UNITS) as Units, sum(dbo.TDK.TD_AMT) as 'Amount',dbo.NAV.NAValue
FROM dbo.TDK INNER JOIN
dbo.NAV
ON dbo.TDK.Products = dbo.NAV.Product_Name
group by dbo.TDK.buyer, dbo.NAV.Product_Name, dbo.NAV.NAValue
Imnportant: Common columns in both tables...
Table one NAV has column as Products
Table two TDK has column as Product_Name
If I have NAValue 4 records for one product then this query shows 4 lines with same total.
What I need??
I want this query to show only one line with latest NAValue price.
I want display one more line with Units*NAValue (latest) as "Latest Market Value".
Please guide.
What field contains the quote date? I am assuming you have a DATIME field, quoteDate, in dbo.NAV table and my other assumption is that you only store the Date part (i.e. mid-night, time = 00:00:00).
SELECT
t.buyer,
n.Product_Name,
sum(t.TD_UNITS) as Units,
sum(t.TD_AMT) as 'Amount',
n.NAValue
FROM dbo.TDK t
INNER JOIN dbo.NAV n
ON t.Products = n.Product_Name
AND n.quoteDate > getdate()-2
group by t.buyer, n.Product_Name, n.NAValue, n.QuoteDate
GetDate() will give you the current date and time. Subtracting 2 would get it before yesterday but after the day before yesterday.
Also, add n.quoteDate in your select and group by. Even though you don't need it, in case that one day you have a day of bad data with double record in NAV table, one with midnight time and another with 6 PM time.
Your code looks like SQL Server. I think you just want APPLY:
SELECT t.buyer, n.Product_Name, t.TD_UNITS as Units, t.TD_AMT as Amount, n.NAValue
FROM dbo.TDK t CROSS APPLY
(SELECT TOP (1) n.*
FROM dbo.NAV n
WHERE t.Products = n.Product_Name
ORDER BY ?? DESC -- however you define "latest"
) n;

Display a rolling 12 weeks chart in SSRS report

I am calling the data query in ssrs like this:
SELECT * FROM [DATABASE].[dbo].[mytable]
So, the current week is the last week from the query (e.g. 3/31 - 4/4) and each number represents the week before until we have reached the 12 weeks prior to this week and display in a point chart.
How can I accomplish grouping all the visits for all locations by weeks and adding it to the chart?
I suggest updating your SQL query to Group by a descending Dense_Rank of DatePart(Week,ARRIVED_DATE). In this example, I have one column for Visits because I couldn't tell which columns you were using to get your Visit count:
-- load some test data
if object_id('tempdb..#MyTable') is not null
drop table #MyTable
create table #MyTable(ARRIVED_DATE datetime,Visits int)
while (select count(*) from #MyTable) < 1000
begin
insert into #MyTable values
(dateadd(day,round(rand()*100,0),'2014-01-01'),round(rand()*1000,0))
end
-- Sum Visits by WeekNumber relative to today's WeekNumber
select
dense_rank() over(order by datepart(week,ARRIVED_DATE) desc) [Week],
sum(Visits) Visits
from #MyTable
where datepart(week,ARRIVED_DATE) >= datepart(week,getdate()) - 11
group by datepart(week,ARRIVED_DATE)
order by datepart(week,ARRIVED_DATE)
Let me know if I can provide any more detail to help you out.
You are going to want to do the grouping of the visits within SQL. You should be able to add a calculated column to your table which is something like WorkWeek and it should be calculated on the days difference from a certain day such as Sunday. This column will then by your X value rather than the date field you were using.
Here is a good article that goes into first day of week: First Day of Week

sql to calculate daily totals minues the previous day's totals

I have a table that has a date, item, and quantity.
I need a sql query to return the totals per day, but the total is the quantity minus the previous day totals. The quantity accumulates as the month goes on. So the 1st could have 5 the 2nd have 12 and the 3rd has 20.
So the 1st adds 5
2nd adds 7 to make 12
3rd adds 8 to make 20.
I've done something like this in the past, but can not find it or remember. I know i'll need a correlated sub-query.
TIA
--
Edit 1
I'm using Microsoft Access.
Date is a datetime field,
item is a text, and
quantity is number
--
Edit 2
Ok this is what i have
SELECT oos.report_date, oos.tech, oos.total_cpe, oos_2.total_cpe
FROM oos INNER JOIN (
SELECT oos_2.tech, Sum(oos_2.total_cpe) AS total_cpe
FROM oos_2
WHERE (((oos_2.report_date)<#10/10/2010#))
GROUP BY oos_2.tech
) oos_2 ON oos.tech = oos_2.tech;
How do i get the oos.report_date into where i says #10/10/2010#. I thought I could just stick it in there like mysql, but no luck. I'm gonna continue researching.
Sum them by adding one to the date and making the value negative, thus taking yesterday's total from today's:
SELECT report_date, tech, Sum(total_cpe) AS total_cpe
FROM (
SELECT oos.report_date, oos.tech, oos.total_cpe
FROM oos
UNION ALL
SELECT oos.report_date+1, oos.tech, 0-oos.total_cpe
FROM oos
)
WHERE (report_date < #10/10/2010#)
GROUP BY report_date, tech
ORDER BY report_date, tech
Ok, I figured it out.
SELECT o.report_date, o.tech, o.total_cpe,
o.total_cpe - (
SELECT IIf(Sum(oos.total_cpe) is null, 0,Sum(oos.total_cpe)) AS total_cpe
FROM oos
WHERE (((oos.tech)=o.tech) AND ((oos.report_date)<o.report_date))
) AS total
FROM oos o;