Increase Date datatype by Number - sql

I am trying update a column called scheddate, which is a Date datatype, based on the value from another column, transleadtime.
transleadtime holds the number of minutes as a Number datatype.
What is the best way to add minutes to a date variable? Here is what I have tried so far:
'UPDATE scpomgr.schedrcpts sr
SET sr.scheddate = (SELECT sr.scheddate + MAX(n.transleadtime / 1440)
FROM scpomgr.network n
WHERE n.source = sr.loc);'

You can try use the dateadd function here. This function takes a specific value, and adds it to a specified date. You can add days, years, minutes, hours, and so on. In your case, you want to add minutes, and since you are adding to the already existing scheddate, you will use that as a parameter.
Here's what the syntax may look like:
UPDATE scpomgr.schedrcpts sr
SET sr.scheddate = dateadd(
minute,
(SELECT n.transleadtime FROM scpomgr.network n WHERE n.source = sr.loc),
(SELECT sr.scheddate)
);
This will add minutes (specified by the first parameter), to the sr.scheddate (specified by the third parameter). The minutes that will be added are the n.translead time (specified by the second parameter).
Right now, this makes the assumption that selecting the sr.scheddate and select n.transleadtime that you have will only return 1 value. If they return more, you may have to adjust your where statement or limit the result set.
I also took out the NVL function, but if you want to protect against null values I would put them in the second and/or third parameters. Definitely in the second, but if your scheddate column doesn't accept null values, then you won't need it.
UPDATE scpomgr.schedrcpts sr
SET sr.scheddate = dateadd(
minute,
NVL((SELECT n.transleadtime FROM scpomgr.network n WHERE n.source = sr.loc), 0),
(SELECT sr.scheddate)
);
I can't test this at the moment, so it may take some tweaking, but start there and let me know how we can improve it.
EDIT
If you're looking for the highest transleadtime, I do think the MAX function would be the simplest way. Try adjusting the subquery in the second parameter to:
SELECT MAX(n.transleadtime) FROM scpomgr.network n WHERE n.source = sr.loc

Related

Timestamp to date in SQL

Here is what I did:
Select count(check_id)
From Checks
Where timestamp::date > '2012-07-31'
Group by 1
Is it right to do it like I did or is there a better way? Should/could I have used the DateDIFF function in my WHERE clause? Something like: DATEDIFF(day, timestamp, '2012/07/31') > 0
Also, I need to figure out how I'd calculate the total rate of acceptance for this
time period? Can anyone provide their expertise with this?
Is it right to do it like I did or is there a better way?
Using a cast like that is a perfectly valid way to convert a timestamp to a date (I don't understand the reference to the non-existing datediff though - why would adding anything to a timestamp change it)
However, the cast has one drawback: if there is an index on the column "timestamp" it won't be used.
But as you just want a range after a certain date, there is no reason to cast the column to begin with.
The following will achieve the same thing as your query, but can make use of an index on the column "timestamp" in case there is one and using it is considered beneficial by the optimizer.
Select count(distinct check_id)
From Checks
Where "timestamp" > date '2012-07-31' + 1
Note the + 1 which selects the day after, otherwise the query would include rows that are on that date but after midnight.
I removed the unnecessary group by from your query.
If you want to get a count per day, then you will need to include the day in the SELECT list. In that case casting is a good way to do it:
Select "timestamp"::date, count(distinct check_id)
From Checks
Where "timestamp" > date '2012-07-31' + 1
group by "timestamp"::date

SQL script to find previous value, not necessarily previous row

is there a way in SQL to find a previous value, not necessarily in the previous row, within the same SELECT statement?
See picture below. I'd like to add another column, ELAPSED, that calculates the time difference between TIMERSTART, but only when DEVICEID is the same, and I_TYPE is viewDisplayed. e.g. subtract 1 from 2, store difference in 3, store 0 in 4 because i_type is not viewDisplayed, subtract 2 from 5, store difference in 6, and so on.
It has to be a statement, I can't use a stored procedure in this case.
SELECT DEVICEID, I_TYPE, TIMERSTART,
O AS ELAPSED -- CASE WHEN <CONDITION> THEN TIMEDIFF() ELSE 0 END AS ELAPSED
FROM CLIENT_USAGE
ORDER BY TIMERSTART ASC
I'm using SAP HANA DB, but it works pretty much like the latest version of MS-SQL. So, if you know how to make it work in SQL, I can make it work in HANA.
You can make a subquery to find the last time entered previous to the row in question.
select deviceid, i_type, timerstart, (timerstart - timerlast) as elapsed.
from CLIENT_USAGE CU
join ( select top 1 timerstart as timerlast
from CLIENT_USAGE C
where (C.i_type = CU.i_type) and
(C.deviceid = CU.deviceid) and (C.timerstart < CU.timerstart)
order by C.timerstart desc
) as temp1
on temp1.i_type = CU.i_type
order by timerstart asc
This is a rough sketch of what the sql should look like I do not know what your primary key is on this table if it is i_type or i_type and deviceid. But this should help with how to atleast calculate the field. I do not think it would be necessary to store the value unless this table is very large or the hardware being used is very slow. It can be calculated rather easily each time this query is run.
SAP HANA supports window functions:
select DEVICEID,
TIMERSTART,
lag(TIMERSTART) over (partition by DEVICEID order by TIMERSTART) as previous_start
from CLIENT_USAGE
Then you can wrap this in parentheses and manipulate the data to your hearts' content

How to show rows where date is equal to every 7 days from a specific day

I'd like to show every row where date_added equals '2015-02-18' and every seven days after, so '2015-02-25' and '2015-03-04' etc..
here's what I have so far
select * from table
where ((to_char(date_added, 'j')) /
((select to_char(d,'j') from (select date '2015-02-18' d from dual)))) = 1
That gets me the first desired date, however I'm stuck as to how to express it to show the next 7 days as a step additive function.
Any help is appreciated. Thank you.
One way to do this is with mod():
select *
from table
where mod(date_added - date '2015-02-18', 7) = 0;
Note: this assumes that the dates have no time component. If they do, then use trunc() to get rid of it.
I like Gordon's "mod()" solution but he's missing part of the requested solution.
In this case, I have a "calendar" table that includes a series of dates:
http://www.perpendulum.com/2012/06/calendar-table-script-for-oracle/
select *
from calendar
where date_time_start >= to_date('01-Jan-2013')
and mod(trunc(date_time_start) - to_date('01-Jan-2013'), 7) = 0;
Per the original question, you want records where the dates are equal to a given date and every seven days thereafter.

Access query won't work when dates have times

I have a query stated:
select *
from tblClient
where IntakeDate = #5/31/2011#
I know for a fact there are 8 records that have that date. But none of records with that date are pulled by this query. Those 8 records have times as well as "short date" (e.g. "5/31/2011 1:42:00 PM")
As a test I set the date to exactly 5/31/2011 for one record, and the query will work for that one record. Clearly the time value is interfering with this query.
I do not want to change all the date data to a strict 'short date' format and would like to work with it as-is. Can anyone give me some idea how I can make this work?
Create a condition that encompasses a single day's time range:
select *
from tblClient
where IntakeDate >= #5/31/2011# AND < #6/1/2011#
[You could use the DateValue() function on your column, but that would prevent any index being used.]
The DateValue function truncates the time off the date
select *
from tblClient
where DateValue(IntakeDate) = #5/31/2011#

select * from table where datetime in month (without breaking index)

I have a bunch of timestamped rows (using the 'datetime' data type)
I want to select all the rows that have a timestamp that is within a particular month.
The column is indexed so I can't do MONTH(timestamp) = 3 because that'll make this index unuseable.
If I have year and month variables (in perl), is there a horrific bit of SQL I can use like:
timestamp BETWEEN DATE($year, $month, 0) AND DATE($year, $month, 31);
But nicer, and actually works?
I would actually go with the idea you proposed ; maybe with a small difference :
select *
from your_table
where date_field >= '2010-01-01'
and date_field < '2010-02-01'
(Of course, up to you the use $year and $month properly)
Note the < '2010-02-01' part : you might have to consider this, if you have dates that include the time.
For instance, if you have a line with a date like '2010-01-31 12:53:12', you probably want to have that line selected -- and, by default, '2010-01-31' means '2010-01-31 00:00:00'.
Maybe that doesn't look 'nice' to the eye ; but it'll work ; and use the index... It's the kind of solution I generaly use when I have that kind of problem.
This is substantively Pascal MARTIN's answer, but avoids having to know explicitly what the next year/month is (so you don't have to increment year and wrap around the $month, when $month == 12):
my $sth = $mysql_dbh->prepare(<<__EOSQL);
SELECT ...
FROM tbl
WHERE ts >= ? AND ts < (? + INTERVAL 1 MONTH)
__EOSQL
my $yyyymm = $year . '-' . sprintf('%02d', $month);
$sth->execute($yyyymm, $yyyymm);
For bonus fugly points, you could also do this:
... WHERE ts BETWEEN ? AND (? + INTERVAL 1 MONTH - INTERVAL 1 SECOND)
That - INTERVAL 1 SECOND will coerce the upper boundary from a DATE into a DATETIME/TIMESTAMP type set to the last second of a day, which is, as Pascal indicated, what you want on the upper bound.
If you need the same month of every year the index you have will not help you and no amount of SQL syntax trickery will help you
On the other hand if you need a month of a particular year then any query with date ranges should do it
Another alternative is to add an extra column to the table that stores the month, precomputed. That would just be a simple int column, and is trivial to index. Unless you're dealing with a kajillion rows, the extra space for an unsigned tiny int is neglible (one byte + db overhead per row).
It'd require a bit of extra work to keep synched with the timestamp column, but that's what triggers are for.
How about WHERE MONTH(`date`) = '$month' AND YEAR(`date`) = '$year'