Unknown column error when trying to pair current row with next row in time-ordered table in SQL - sql

There is a table stockprice, which contains information about trades of one company's stock. It has two columns: timestamp and price. They represent the time when a trade happened and the price of the sale. The natural order of records in the table is random and is not sorted by timestamp.
You add another column (let's call it delta) where you intend to store the difference between the current transaction price and the price of the previous transaction time-wise.
Write a single SQL statement, which will calculate the price difference and fill the column delta with it in all rows.
I write the sql as below to run on mysql,and i can't move on, the following is the one i wrote till now to calculate the difference between the current transaction price and the price of the previous transaction time-wise, mysql give me the "Unknown column 'previous.price' in 'field list'" error since the first row's previous is nothing, can some expert have a idea to solve this?:
SELECT
`current`.timestamp,
`current`.price,
`current`.price - IFNULL(`previous`.price, 0) AS delta
FROM
stockprice AS `current`
LEFT JOIN
stockprice AS `next`
ON `next`.timestamp = (SELECT MIN(timestamp)
FROM stockprice
WHERE timestamp > `current`.timestamp)
My database like:
timestamp price
2011-10-27 00:00:00 12424
2011-10-24 00:00:00 15464
2011-10-25 00:00:00 543464
2011-10-23 00:00:00 58791

Decide whether you are dealing with next or previous timestamps:
SELECT `current`.timestamp,
`current`.price,
`current`.price - IFNULL(`previous`.price, 0) AS delta
FROM stockprice AS `current`
LEFT JOIN stockprice AS `previous`
ON `previous`.timestamp = (SELECT MAX(timestamp)
FROM stockprice
WHERE timestamp < `current`.timestamp)
Or avoiding the use of backticks:
SELECT C.timestamp,
C.price,
C.price - IFNULL(P.price, 0) AS delta
FROM stockprice AS C
LEFT JOIN stockprice AS P
ON P.timestamp = (SELECT MAX(S.timestamp)
FROM stockprice AS S
WHERE S.timestamp < C.timestamp)

"Unknown column 'previous.price' in 'field list'"
I don't see anything in this query that would cause that error. Are you sure this is the whole query you are running? This doesn't have anything to do with there not being a 'previous' record for the first record to join to. It means there's not a table (or alias) called previous with a column called price.

Related

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;

How to calculate difference between two rows in a date interval?

I'm trying to compare data from an Access 2010 database based on a date interval. Example I have items from various purchase orders and I want to maintain the history of these item's delivery to a warehouse. So my purchase order has a request for a quantity of 10 of a material, for example, and it can be partially delivered in many deliveries and I want to know how this delivery varied in a date interval. To fill the date field the criteria used is the following: if the item had an update in the QtyPending field, I copy the current row deactivating it with a booelan field, create a new entry with the current update date updating the QtyPending field, so the active record is the actual state of the item. So I have a table that holds informations about these items like that
PO POItem QtyPending Date Active
4500000123 10 10 01/09/2014 FALSE
4500000123 10 8 05/09/2014 TRUE
4500000122 30 5 03/09/2014 FALSE
4500000122 30 1 04/09/2014 TRUE
With this example, for the first item, it means that from date 01/09 to 04/09 the QtyPending field didn't suffer a variation, meaning that the supplier didn't make any delivery to me, but from 01/09 to 05/08 he delivered me a qty of 2 of a material. For the second one, from date 03/09 to 04/09 the supplier delivered me a qty of 4 of a material. So, if I were to be making a report query from 02/09/2014 to 04/09/2014, the expected output is like this:
PO POItem QtyDelivered
4500000123 10 0
4500000122 30 4
And a report from 31/08/2014 to 10/09/2014, would have this output
PO POItem QtyDelivered
4500000123 10 2
4500000122 30 4
I'm not coming up with a query to make this report. Can anyone help me?
There are many ways of solving this. The easiest one would be to simply make a query of all the necessary records between two dates, loop over them and insert into a temporary table the result. This temporary table can then be the source of your report. A lot of people will scream at you for not using a big query instead but getting the result that you want in the fastest and simplest way should be your priority.
Your problem with your schema is that you don't have the QtyDelivered stored for each record. If you would have it, it would be an easy thing to sum over it in order to get needed result. By not storing this value, you have transformed a simple and fast query into a much harder and slower one because you need to recalculate this value in some way or other and you must do this without forgetting the fact that it's possible to have more than two records.
For calculating this value, you can either use a sub-query to retrieve the value from the previous row or a Left join do to the same. Once you have this value, you can subtract these two to get the needed difference; allowing for the possibility of Null value if there is no previous row. Once you have these values, you can now sum over them to get the final result with a Group By. Notice that in order to perform these calculations, you need to have one or two more levels of subquery. The first query should be something like:
Select PO, POItem, QtyPending, (Select Top 1 QtyPending from MyTable T2 where T1.PO = T2.PO and T2.Date < T1.Date And (T2.Date between #Date1 and #Date2) Order by T2.Date Desc) as QtyPending2 from MyTable T1 Where T1.Date between #Date1 and #Date2) ...
With this as either another subquery or as a View, you can then compute the desired difference by comparing the values of QtyPending and QtyPending2; without forgetting that QtyPendin2 may be Null. The remaining steps are easy to do.
Notice that the above example is for SQL-Server, you might have to change it a little for Access. In any case, you can find here many examples on how to compare two rows under Access. As noted earlier, you can also use a Left Join instead of a subquery to compare your rows.
I came up with this query that solved the problem, it wasn't that simple
SELECT
ItmDtIni.PO
,ItmDtIni.POItem AS [PO Item]
,ROUND(ItmDtIni.QtyPending - ItmDtEnd.QtyPending, 3) AS [Qty Delivered]
,ROUND((ItmDtIni.QtyPending - ItmDtEnd.QtyPending) * ItmDtEnd.Price, 2) AS [Value delivered(US$)]
//Filtering subqueries to bring only the items in the date interval to make a self join
FROM (((SELECT
PO
,POItem
,QtyPending
,MIN(Date) AS MinDate
FROM Item
WHERE Date BETWEEN FORMAT(begin_date, 'dd/mm/yyyy') AND FORMAT(end_date, 'dd/mm/yyyy')
GROUP BY
PO
,POItem
,QtyPending) AS ItmDtIni
//Self join filtering to bring only items in the date interval with the previously filtered table
INNER JOIN (SELECT
PO
,POItem
,QtyPending
,Price
,MAX(Date) AS MaxDate
FROM Item
WHERE Date BETWEEN FORMAT(begin_date, 'dd/mm/yyyy') AND FORMAT(end_date, 'dd/mm/yyyy')
GROUP BY
PO
,POItem
,QtyPending
,Price) AS ItmDtEnd
ON ItmDtIni.PO = ItmDtEnd.PO
AND ItmDtIni.POItem = ItmDtEnd.POItem)
INNER JOIN PO
ON ItmDtEnd.PO = PO.Numero)
WHERE
//Showing only items that had a variation in the date interval
ROUND(ItmDtIni.QtyPending - ItmDtEnd.QtyPending, 3) <> 0
//Anchoring min date in the interval for each item found by the first subquery
AND ItmDtIni.MinDate = (SELECT MIN(Item.Date)
FROM Item
WHERE
ItmDtIni.PO = Item.PO
AND ItmDtIni.POItem = Item.POItem
AND Date BETWEEN FORMAT(begin_date, 'dd/mm/yyyy') AND FORMAT(end_date, 'dd/mm/yyyy'))
//Anchoring max date in the interval for each item found by the second subquery
AND ItmDtEnd.MaxDate = (SELECT MAX(Item.Date)
FROM Item
WHERE
ItmDtEnd.PO = Item.PO
AND ItmDtEnd.POItem = Item.POItem
AND Date BETWEEN FORMAT(begin_date, 'dd/mm/yyyy') AND FORMAT(end_date, 'dd/mm/yyyy'))

How to query date in oracle?

Assuming I have the following table in oracle:
id|orderdatetime (date type)|foodtype (string type)
1|2013-12-02T00:26:00 | burger
2|2013-12-02T00:20:00 | fries
...
(assume there are many dates and times)
Assuming someone happened to have a date in mind (i.e. "2010-12-02T00:25:00").
even though there is no database entry with that specific time in there...
is there some way to query the database such that I can get the row that has a date time that is closest to it without being ahead of the date in mind (ideally, it would be less than or equal to)?
(i.e. in this case, the sql query would return the row for "fries" and not "burger" because the time for burger is past the time the user had in mind despite the fact that the time for "burger" is closer.)
select x.* from (select id,orderdatetime,foods from orders
where orderdatetime <= YOURTIME order by orderdatetime desc)x
where rownum =1
Another would be:
select * from orders where orderdatetime = (select max(orderdatetime) from orders
where orderdatetime <= YOURTIME)

analyze range and if true tell me

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

join two tables to get tomorrow's price (and the price two days from "now")

I'm trying to do a JOIN query to analyze some stocks. In my first table called top10perday, I list 10 stocks per day that I have chosen to "buy" the next day and sell the following day:
date symbol
07-Aug-08 PM
07-Aug-08 HNZ
07-Aug-08 KFT
07-Aug-08 MET
...
08-Aug-08 WYE
08-Aug-08 XOM
08-Aug-08 SGP
08-Aug-08 JNJ
For instance, for record #1:
the date of the record is 07-Aug-08
I want to buy a share of PM stock on the next trading day after 07-Aug-08 (which is 08-Aug-08)
I want to sell that shar eof PM stock two trading days after 07-Aug-08), which turns out to be 11-Aug-08
My stock prices are in a table called prices, which looks like this:
date symbol price
07-Aug-08 PM 54.64
08-Aug-08 PM 55.21
11-Aug-08 PM 55.75
12-Aug-08 PM 55.95
... many more records with trading day, symbol, price
I want to do a JOIN so that my result set looks like this:
date symbol price-next-day price-two-days
07-Aug-08 PM 55.21 55.75
...
list one record per date and symbol in table1.
I have tried doing something like:
SELECT top10perday.date, top10perday.symbol, Min(prices.date) AS MinOfdate
FROM prices INNER JOIN top10perday ON prices.symbol = top10perday.symbol
GROUP BY top10perday.date, top10perday.symbol
HAVING (((Min(prices.date))>[date]));
I have tried many variations of this, but I'm clearly not on the right path, because the result set just includes 10 rows as of the earliest date shown in my top10perday table.
I am using Microsoft Access. Thanks in advance for your help! :-)
This syntax worked in Access 2003:
SELECT t10.Date, t10.Symbol, p1.date, p1.price, p2.date, p2.price
FROM
(top10perday AS t10
LEFT JOIN prices AS p1
ON t10.Symbol = p1.symbol)
INNER JOIN prices AS p2 ON t10.Symbol = p2.symbol
WHERE (
((p1.date)=((Select Min([date]) as md
from prices
where [date]>t10.[Date] and symbol = t10.symbol
))
) AND ((p2.date)=((Select Min([date]) as md
from prices
where [date]>p1.[Date] and symbol = t10.symbol)
))
);
the idea is to get the first (min) date that is greater than the date in the previous table (top10perday and the prices as p1)
This should just be a join between three copies of the prices table. The problem is that you need to join to the next trading day, and that's a slightly trickier problem, since it's not always the next day. So we end up with a more complex situation (particularly as some days are skipped beacuse of holidays).
If it weren't Access you could use row_number() to order your prices by date (using a different sequence per stock code).
WITH OrderedPrices AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date) AS RowNum
FROM Prices
)
SELECT orig.*, next_day.price, two_days.price
FROM OrderedPrices orig
JOIN
OrderedPrices next_day
ON next_day.symbol = orig.symbol AND next_day.RowNum = orig.RowNum + 1
JOIN
OrderedPrices two_days
ON two_days.symbol = orig.symbol AND two_days.RowNum = orig.RowNum + 2
;
But you're using Access, so I don't think you have ROW_NUMBER().
Instead, you could have a table which lists the dates, having a TradingDayNumber... then use that to facilitate your join.
SELECT orig.*, next_day.price, two_days.price
FROM Prices orig
JOIN
TradingDays d0
ON d1.date = orig.date
JOIN
TradingDays d1
ON d1.TradingDayNum = d0.TradingDayNum + 1
JOIN
TradingDays d2
ON d2.TradingDayNum = d0.TradingDayNum + 2
JOIN
Prices next_day
ON next_day.symbol = orig.symbol AND next_day.date = d1.date
JOIN
Prices two_days
ON two_days.symbol = orig.symbol AND two_days.date = d2.date
But obviously you'll need to construct your TradingDays table...
Rob
My guess is:
SELECT top10perday.date, top10perday.symbol, MIN(pnd.price) AS PriceNextDay, MIN(ptd.price) AS PriceTwoDays
FROM top10perday
LEFT OUTER JOIN prices AS pnd ON (pnd.symbol = top10perday.symbol AND pnd.date > top10perday.date)
LEFT OUTER JOIN prices AS ptd ON (ptd.symbol = top10perday.symbol AND ptd.date > pnd.date)
GROUP BY top10perday.date, top10perday.symbol
HAVING ((pnd.date = Min(pnd.date) AND ptd.date = Min(ptd.date));
It´s just a shoot in the dark but my reasoning is: List all stocks you want (top10perday) and for each stock get the price, if exists, with mininum date after its date to populate the PriceNextDay and the price with minimun date after the PriceNextDay to populate the PriceTwoDays. The performance may stinks. But test it and see if it works. Later we can try to improve it.
**EDIT**ed to include Rob Farley´s comment.
I'm not a guru on this transformation but I can point you at an idea. Try using Pivot on the date column for each symbol in your query from a date to a date. This should give you a table with many columns with the name of the date you're using, and the price on each day. Indeed it should do this for every stock symbol you have over a given time.
Based on what you're trying to graph though, I think it would be interesting for you to look at the VWSP not just the spot price on your trades if you're trying to plot the stock performance.