How can I avoid using two iSNulls - sql

I am Trying to not use two isnulls since it is making my query extremely slow. what better ways are there to write the following?
[Example] =
CAST (isnull(ap.CustomDate2, (isnull(ap.CustomDate10,
(Select top 1 sts.times
From timetable sts
where sts.ShipmentStatusID IN (8000, 8089)
Order By sts.times DESC)))) AS date

You would be better off using a COALESCE here. Assuming you are indeed working in Sql Server and not MySql
CAST(
COALESCE(
ap.CustomerDate2,
ap.CustomerDate10,
(SELECT TOP 1 sts.times
FROM timetable sts
WHERE sts.ShipmentStatusID IN (8000, 8089)
ORDER BY sts.times DESC)
)
AS DATE) as Your_Column_Name

Related

Get the following record in query

If we have a table called Activity and has rows[ActivityCode and StartTime]
for example
ActivityCode-----StartTime<BR>
Lunch------------1200<BR>
MathClass--------1300<BR>
EnglishClass-----1500<BR>
EndOfSchool------1700<BR>
And now I want to make one SQL Query to display as follow:
ActivityCode-----StartTime-----EndTime<BR>
Lunch------------1200----------1300<BR>
MathClass--------1300----------1500<BR>
EnglishClass-----1500----------1700<BR>
EndOfSchool------1700----------1700<BR>
I am not sure how to do it. I tried to follow How to get a value from previous result row of a SELECT statement?. But it didn't work as I expected. Any help is appreciated.
You can use this query:
SELECT
Activity.ActivityCode,
Activity.StartTime,
Nz((Select Top 1 StartTime
From Activity As T
Where T.StartTime > Activity.StartTime
Order By StartTime Asc),
[StartTime]) AS EndTime,
CDate(TimeSerial(Val([EndTime])\100,Val([EndTime]) Mod 100,0)-
TimeSerial(Val([StartTime])\100,Val([StartTime]) Mod 100,0)) AS Duration
FROM
Activity;
Output:
I would use a subquery with aggregation:
select a.*,
(select nz(min(a2.starttime), a.endtime)
from activity as a2
where a2.starttime > a.starttime
) as endtime
from activity as a;
Normally in such an example, there would be an additional column identifying a "grouping" of some sort -- such as a person. If you have such a column, you would have an equality condition in the subquery as well as the inequality on time.
Also, there are much better ways to do this in almost any other database -- notably, the lead() function.

Teradata / Window functions - QUALIFY

I'm analyzing the code of my collegue.
Found this query:
SELECT
client_id
from lib.applications
QUALIFY Row_Number() Over(PARTITION BY client_id ORDER BY closed) = 1
WHERE closed=0 and application_date > '2016-01-01'
Logically, the query should return a list of clients with active (not closed) applications.
I can't uderstand, why he used QUALIFY etc.. here?
The request below is simplier and returns the same:
SELECT
client_id
from lib.applications
WHERE closed=0 and application_date > '2016-01-01'
Do you have any idea, for what reason QUALIFY could be used here?
QUALIFY is returning one row per client_id. The more colloquial way of writing the query would be:
SELECT DISTINCT client_id
FROM lib.applications
WHERE closed = 0 and application_date > '2016-01-01';
Perhaps the author of the query checked performance and found that QUALIFY is faster in this case (although I would doubt that). Perhaps the author was thinking of including other columns, in which case SELECT DISTINCT would not work.

Running cumulative return in sql

Looking to have a running cumulative return for a series of daily returns? I know this can be solved using exp and sum, but my return series is not calculated using LN.
Hoping to solve this without using loops, as they are very inefficient in sql.
Its important to make this run fast.
Dataset:
desired result
Is this what you want?
select t.*,
(select exp(sum(log(1 + return))) - 1
from table t2
where t2.date <= t.date
) as cumereturn
from table t;
The functions for exp() and log() may be different in the database you are using. In many databases, you can also use:
select t.*, exp(sum(log(1 + return) over (order by date)) - 1
from table t;
I don't think any database has a built in product() aggregation function. Alas.
converting (1+r)(1+r)(1+r) to
exp(log(1+r) + log(1+r) + log(1+r))
does not work because 1+r could be negative.
Negative log is undefined. i.e. the return is less than -100%

counting date and time for historical reporting

I am currently working on a query that will be used in junction with share-point to run reports. I have a query that I know will work with Oracle, but the company I am working for is running SQL Server 2005.
What the report will do is give the person the ability to select any date and time, and give the count for that specific operation. The problem is that there are large gaps in the time stamps (because it takes a little while for the product to get to the next operation). The date type is varchar, so i used substrings to parse out the year, month, day, and time. I have sample data available.
The people looking at the reports want the ability to say at this time and day how many units went through this operation.
I know this is is confusing, let me know if you need any clarification.
Here is the oracle syntax
SELECT T3.PAYMENT_DATE, T3."Hr", T3."Min",
(SELECT COUNT(*)
FROM INVOICE_ARCHIVE T4
WHERE TO_NUMBER(TO_CHAR(T4.PAYMENT_DATE, 'MM')) <= T3."Hr"
AND TO_NUMBER(TO_CHAR(T4.PAYMENT_DATE, 'DD')) <= T3."Min") AS "NUM"
FROM(SELECT T1.PAYMENT_DATE, T2."Hr", T2."Min"
FROM (SELECT (FLOOR((LEVEL + 359)/60)) AS "Hr",
MOD((LEVEL + 359), 60) AS "Min"
FROM dual CONNECT BY LEVEL <= 961) T2, INVOICE_ARCHIVE T1
ORDER BY T1.PAYMENT_DATE, T2."Hr", T2."Min") T3
The answer to your question is the datepart() function in SQL Server. This will allow you to extract minutes and hours from dates.
The harder part is the "connect by level" portion. How is this being used? You might need to use recursive CTEs to handle this.
With the little hint from spencer, the following may suffice for your query:
SELECT T3.PAYMENT_DATE, T3."Hr", T3."Min",
(SELECT COUNT(*)
FROM INVOICE_ARCHIVE T4
WHERE datepart(month, T4.PAYMENT_DATE) <= T3."Hr" AND
datepart(day, T4.PAYMENT_DATE, 'DD') <= T3."Min"
) AS "NUM"
FROM (SELECT T1.PAYMENT_DATE, T2."Hr", T2."Min"
FROM (SELECT top 961 (FLOOR((LEVEL + 359)/60)) AS "Hr",
MOD((LEVEL + 359), 60) AS "Min"
FROM (select top 961 row_number() over (order by (select NULL)) as level
from invoice_archive
) t
) T2 cross join
INVOICE_ARCHIVE T1
) T3
ORDER BY T3.PAYMENT_DATE, T3."Hr", T3."Min"
I made the following changes:
Changed the date arithmetic to use datepart() instead of to_char() .
Replaced the method for getting a list of numbers, by using row_number() instead of connect by level
Made the cross join explicit
Moved the order by to the outer query, since neither SQL Server nor Oracle guarantee the results of an order by in a subquery (and SQL Server does not allow it unless you have a "TOP" query)

SQL Average Inter-arrival Time, Time Between Dates

I have a table with sequential timestamps:
2011-03-17 10:31:19
2011-03-17 10:45:49
2011-03-17 10:47:49
...
I need to find the average time difference between each of these(there could be dozens) in seconds or whatever is easiest, I can work with it from there. So for example the above inter-arrival time for only the first two times would be 870 (14m 30s). For all three times it would be: (870 + 120)/2 = 445 (7m 25s).
A note, I am using postgreSQL 8.1.22 .
EDIT: The table I mention above is from a different query that is literally just a one-column list of timestamps
Not sure I understood your question completely, but this might be what you are looking for:
SELECT avg(difference)
FROM (
SELECT timestamp_col - lag(timestamp_col) over (order by timestamp_col) as difference
FROM your_table
) t
The inner query calculates the distance between each row and the preceding row. The result is an interval for each row in the table.
The outer query simply does an average over all differences.
i think u want to find avg(timestamptz).
my solution is avg(current - min value). but since result is interval, so add it to min value again.
SELECT avg(target_col - (select min(target_col) from your_table))
+ (select min(target_col) from your_table)
FROM your_table
If you cannot upgrade to a version of PG that supports window functions, you
may compute your table's sequential steps "the slow way."
Assuming your table is "tbl" and your timestamp column is "ts":
SELECT AVG(t1 - t0)
FROM (
-- All this silliness would be moot if we could use
-- `` lead(ts) over (order by ts) ''
SELECT tbl.ts AS t0,
next.ts AS t1
FROM tbl
CROSS JOIN
tbl next
WHERE next.ts = (
SELECT MIN(ts)
FROM tbl subquery
WHERE subquery.ts > tbl.ts
)
) derived;
But don't do that. Its performance will be terrible. Please do what
a_horse_with_no_name suggests, and use window functions.