Can DATE_PART be used in HAVING clause? - sql

When the following SQL query is executed, it seems that the HAVING clause doesn't take any effect.
SELECT
day_of_week,
fc,
gl,
CASE WHEN COUNT(inbound_allocation_factors) IS null THEN 0 ELSE count(inbound_allocation_factors) END AS num_of_factors,
DATE(request_datetime) AS date
FROM
allocationworkflow_with_gl
GROUP BY day_of_week,fc,gl,date
HAVING day_of_week = DATE_PART(dw,MAX(request_datetime))
request_datetime is a timestamp, and day_of_week is integer from 0 to 6 indicating Sunday to Saturday. By the way, I'm using Redshift. Could anyone help me? Many thanks!

Your problem is not datepart(). Your problem is the day_of_week with no aggregation. You can validate this by doing:
HAVING DATE_PART(dw, MAX(request_datetime)) = 1
I'm not sure what you really want to do, but this answers your immediate question.

Related

I want to put 0 instead of negative values from DATEDIFF

The table with the following structure is considered:
MEDICINE: (name, price, quantity, expiration_date );
I did
SELECT Name,
DATEDIFF(expiration_date, CURRENT_DATE)
AS days
FROM MEDICINE;
I got negative results from datediff, but I want to put 0 instead of the negative values. How can I make this? Any help?
Try this:
SELECT Name
, CASE
WHEN DATEDIFF(expiration_date, CURRENT_DATE) < 0 THEN 0
ELSE DATEDIFF(expiration_date, CURRENT_DATE)
END AS days
FROM MEDICINE;
Unfortunately you have to repeat the expression, but the engine should be smart enough to only calculate it once.
You can use GREATEST() in combination with a - because DATEDIFF() doesn't exist in PostgreSQL:
SELECT Name,
GREATEST(expiration_date - CURRENT_DATE, 0)
AS days
FROM MEDICINE;
This should work for you.
GREATEST(0, DATEDIFF(expiration_date, CURRENT_DATE))
Read about these conditional operators here. Spend some time reading about the suite of functions and operators in your SQL language: it's time well spent.
You can do it using SQL case.
This should work:
SELECT Name,
CASE WHEN DATEDIFF(expiration_date, CURRENT_DATE) > 0 THEN DATEDIFF(expiration_date, CURRENT_DATE)
ELSE 0
END
AS days
FROM MEDICINE;
You can read more about it here: https://www.w3schools.com/sql/sql_case.asp

Not getting actual minutes in SQL DateDiff

I searched in different places and found below queries. I am using the following queries to get the actual minutes difference in SQL. The dates I provide are the same day. I need difference in minutes only but SQL is returning 35 instead of 5 minutes in the first query. And the second query return milliseconds.
SELECT DATEDIFF(MINUTE,GETDATE(), CONVERT(datetime,'2016-08-11 16:04:24'))%3600/60 AS MinuteDiff
SELECT datediff(minute,GETDATE(), CONVERT(datetime,'2016-08-11 16:04:24')) as MinutesDiff
What is missing. Please help.
I need to put a condition that if time is less than 20 minutes then
do this
else
do this
Updated:
The issue occurs when i use GetDate(). When I use a fix date it works fine
You need to place the GETDATE() after your datetime value, other wise in your case you will get the minutes in negative value.
SELECT DATEDIFF(MINUTE,CONVERT(datetime,'2016-08-11 16:04:24'), GETDATE()) AS MinuteDiff
The current GETDATE() is 2016-08-11 17:05:39.053, so it returns 61.
Then based on the value, using IF ... ELSE ... you can do your expected operation:
IF DATEDIFF(MINUTE,CONVERT(datetime,'2016-08-11 16:04:24'), GETDATE()) < 20
PRINT 'With in 20 mins'
ELSE
PRINT 'More than 20 mins'
Here is a working example of what your after...although you probably need to switch out the date components as appropriate for your usage.
select
case
when
(SELECT datediff(minute,GETDATE(), CONVERT(datetime,'2016-08-11 06:00:00'))) < 20 then
(select 'do this')
else
(select 'do something else')
end as answer
If you want minute span between two datetime, then your second one is enough.
SELECT datediff(n, CONVERT(datetime,'2016-08-11 16:04:24'),GETDATE()) as MinutesDiff
you can use CASE for your further
select
case when
datediff(n, CONVERT(datetime,'2016-08-11 16:04:24'),GETDATE()) < 20 then
`your code`
else
`your else code`
end minte
Hey sorry for the initial poor explanation.
I use something like the following frequently this will return a INT and decide if it's then you can do the logic on it, equal to, not equal less than greater than etc.
If it is true it will return a 1 or it is false a 0. You can get it to return columns or set it to a string.
Hope it helps
select
Case
When DateDiff(minute,[column],Getdate()) > 20 then 1 else 0
end as [alias]

Invalid Operation On An ANSI DATETIME (Subtracting one timestamp from another in Teradata)

I would like to create a WHERE condition to return results where only 1 day has passed between two timestamps. I tried this:
SELECT * FROM RDMAVWSANDBOX.VwNIMEventFct
INNER JOIN VwNIMUserDim ON VwNIMUserDim.NIM_USER_ID = VwNIMEventFct.NIM_USER_ID
INNER JOIN rdmatblsandbox.TmpNIMSalesForceDB ON TmpNIMSalesForceDB.EMAIL = VwNIMUserDim.USER_EMAIL_ADDRESS
WHERE (CONTRACT_EFFECTIVE_DATE - EVENT_TIMESTAMP) =1
But the result was an error message "Invalid Operation On An ANSI DATETIME value".
I guess that, looking at the code now, Teradata has no way of knowing whether the "1" in "= 1" is a day, hour or year.
How would I select data where only 1 day has passed between CONTRACT_EFFECTIVE_DATE and EVENT_TIMESTAMP?
Same again for 2 days, and 3 days etc?
If both columns are DATEs you can use =1which means one day.
For Timestamps you need to tell what kind of interval you want:
WHERE (CONTRACT_EFFECTIVE_DATE - EVENT_TIMESTAMP) DAY = INTERVAL '1' DAY
But i'm not shure if this is what you really want, what's your definition of 1 day?
Edit:
Based on your comment the best way should be:
WHERE CAST(CONTRACT_EFFECTIVE_DATE AS DATE) - CAST(EVENT_TIMESTAMP AS DATE) = 1
This avoids dealing with INTERVAL arithmetic :-)
Not sure about Teradata, but I think most versions of SQL have built-in date math functions. In MSSQL for instance you could do this:
...
WHERE DATEDIFF(DAY, CONTRACT_EFFECTIVE_DATE, EVENT_TIMESTAMP) = 1
Or if you wanted to make sure 24 hours had passed you could do:
...
WHERE DATEDIFF(HOUR, CONTRACT_EFFECTIVE_DATE, EVENT_TIMESTAMP) = 1
Other SQL's have their own versions of this, and you may have to use 'D' or 'DD' instead of 'DAY' or something (and maybe 'HH' instead of 'HOUR' likewise).

Postgresql query between date ranges

I am trying to query my postgresql db to return results where a date is in certain month and year. In other words I would like all the values for a month-year.
The only way i've been able to do it so far is like this:
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN '2014-02-01' AND '2014-02-28'
Problem with this is that I have to calculate the first date and last date before querying the table. Is there a simpler way to do this?
Thanks
With dates (and times) many things become simpler if you use >= start AND < end.
For example:
SELECT
user_id
FROM
user_logs
WHERE
login_date >= '2014-02-01'
AND login_date < '2014-03-01'
In this case you still need to calculate the start date of the month you need, but that should be straight forward in any number of ways.
The end date is also simplified; just add exactly one month. No messing about with 28th, 30th, 31st, etc.
This structure also has the advantage of being able to maintain use of indexes.
Many people may suggest a form such as the following, but they do not use indexes:
WHERE
DATEPART('year', login_date) = 2014
AND DATEPART('month', login_date) = 2
This involves calculating the conditions for every single row in the table (a scan) and not using index to find the range of rows that will match (a range-seek).
From PostreSQL 9.2 Range Types are supported. So you can write this like:
SELECT user_id
FROM user_logs
WHERE '[2014-02-01, 2014-03-01]'::daterange #> login_date
this should be more efficient than the string comparison
Just in case somebody land here... since 8.1 you can simply use:
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN SYMMETRIC '2014-02-01' AND '2014-02-28'
From the docs:
BETWEEN SYMMETRIC is the same as BETWEEN except there is no
requirement that the argument to the left of AND be less than or equal
to the argument on the right. If it is not, those two arguments are
automatically swapped, so that a nonempty range is always implied.
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'
Between keyword works exceptionally for a date. it assumes the time is at 00:00:00 (i.e. midnight) for dates.
Read the documentation.
http://www.postgresql.org/docs/9.1/static/functions-datetime.html
I used a query like that:
WHERE
(
date_trunc('day',table1.date_eval) = '2015-02-09'
)
or
WHERE(date_trunc('day',table1.date_eval) >='2015-02-09'AND date_trunc('day',table1.date_eval) <'2015-02-09')

Calculating Percentage when Row can contain 0

I have previously asked the following question: Calculating percentage within the SQL
Now i was lucky enough to get a great answer however in my question i did not take into account that my rows could contain zero.
The questions row where simple:
select
Number_of_Calls,
Number_of_Answered,
((Number_of_answered/Number_Of_Calls)*100) as answer_percent,
Date
from table Where Date BETWEEN '2012-09-10' AND '2012-09-11'
However Number_of_answered could be zero (if our company did not answer the calls) so if i want the full number in percentage how do i take 0 into account?
By the way. The database that we use is an Oracle database with PL SQL
The nullif function can be used to return null if the divisor is zero. When SQL encounters a null divisor it forces the entire equation to return null, preventing your error from occurring.
select
Number_of_Calls,
Number_of_Answered,
((Number_of_answered/nullif(Number_Of_Calls,0))*100) as answer_percent,
Date
from table Where Date BETWEEN '2012-09-10' AND '2012-09-11'
If you would like to exclude null percentages use the following SQL:
select * from(select
Number_of_Calls,
Number_of_Answered,
((Number_of_answered/nullif(Number_Of_Calls,0))*100) as answer_percent,
Date
from table Where Date BETWEEN '2012-09-10' AND '2012-09-11') alias
where answer_percent is not null;
Case when Number_Of_Calls = 0
THEN 0 --or your desired value, maybe 100
else (Number_of_answered/Number_Of_Calls)*100
END as answer_percent
i think you mean "Number_Of_Calls" could be zero (thus raising a zero_divide error?) if so do
case Number_Of_Calls when 0 then 0 else ((Number_of_answered/Number_Of_Calls)*100) as answer_percent
As far as I understood you from your comment you want a rate of answered calls over a period of time, including days when 100% calls were unanswered.
I guess the simpliest approach would be
select sum(number_of_answered) / sum (number_of_calls)
from table
where date between interval_start and interval_end
in this case.