How to Average column on bottom of query - sql

Ignore '?DATE1::?' it is just a prefix for users to input date range.
Select
STARTDATEKEY
round(avg(Minutes),2) as Time /*average for 1 day */
from Table
where To_Date(to_char(StartDate, 'DD-MON-YYYY')) >= To_Date('?DATE1::?','MM/DD/YYYY')
and To_Date(to_char(RESTOREDDATETIME, 'DD-MON-YYYY')) <= To_Date('?DATE2::?','MM/DD/YYYY')
and FLAG = 0
group by STARTDATEKEY
Out will be
I need help showing average for column Time on bottom of 20130110 52.67
note to editor/reviewer : I don't know if I should tag Oracle or SQL.

You can use the ROLLUP grouping function.
Should be something like this:
Select
STARTDATEKEY
round(avg(Minutes),2) as Time /*average for 1 day */
from Table
where To_Date(to_char(StartDate, 'DD-MON-YYYY')) >= To_Date('?DATE1::?','MM/DD/YYYY')
and To_Date(to_char(RESTOREDDATETIME, 'DD-MON-YYYY')) <= To_Date('?DATE2::?','MM/DD/YYYY')
and FLAG = 0
group by ROLLUP(STARTDATEKEY)
Here is a simplified sqlfiddle demo

Related

SQL if statement for date range

Hi I was needing help with the syntax to add a condition where the current date is retrieved if today is after the 5th of each month but if its between the 1st to the 5th then it should retrieve the month before this month. Is it something you can help with please? Below is how my query is structured.
Select *
FROM table1
left join table2
on e.ENTITY_NBR = d.entity_nbr
and cast(getdate() as date) between MONTH_BEGIN_DATE and MONTH_END_DATE
Select *,
CASE WHEN day(GETDATE()) > 5 THEN GETDATE()
ELSE DATEADD(month,-1,getdate()) END as date
FROM table1
left join table2
on e.ENTITY_NBR = d.entity_nbr
and cast(getdate() as date) between MONTH_BEGIN_DATE and MONTH_END_DATE
Based on a vague description of your problem this is the best I can write.
If you simply want to include todays date (or the same date from last month if it's currently the 5th or earlier in the current month), then this can be done in your SELECT clause:
select
case
when datepart(day,getdate()) <= 5
then dateadd(month,-1,getdate())
else getdate()
end
If you want to actually use this date to compare to some field in your dataset, then you can include this same case expression in your WHERE clause.
where the current date is retrieved if today is after the 5th of each month but if its between the 1st to the 5th then it should retrieve the month before this month.
Based on this description, you want something like this:
select *
from table1 e left join
table2 d
on e.ENTITY_NBR = d.entity_nbr and
(day(getdate() > 5 and datediff(month, d.date_col, getdate()) = 0 or
day(getdate() <= 5 and datediff(month, d.date_col, getdate()) = 1)
)

OR for two different columns

I am trying to select specific rows from an Oracle DB.
The table has the following structure:
Order
Date
Status
1
01.01.2018
10
2
01.01.2018
15
I would like to extract all rows where
Status = < 85 or
the order date is in this week
Unfortunately, column Status is declared as a text column.
How would you build a SQL to extract these specific rows?
Hmmm . . . I don't know what you mean by "this week". Perhaps:
where status <= '85' or
orderdate >= trunc(sysdate, 'IW')
This does a string comparison on the status, so '9' would not be matched, and uses the ISO definition of week for the current week.
If you want a numeric comparison for status, then:
where to_number(status) <= 85 or
orderdate >= trunc(sysdate, 'IW')
Maybe try the CAST function like
select* from yourtable where cast(Status as INT) <=85 AND
to_char(to_date(date,'MM/DD/YYYY'),'WW')=to_char(to_date(sysdate,'MM/DD/YYYY'),'WW')

How can I get a user's activity count for today and this month in a single SELECT query

In my table I have:
Activity : Date
---------------
doSomething1 : June 1, 2020
doSomething2 : June 14, 2020
I want to be able to make a query so that I can get the following result (assuming today is June 1, 2020):
Today : ThisMonth
1 : 2
I looked at group by but I wasn't sure how to do that without a lot of additional code and I think there's very likely a much simpler solution that I'm missing. Something that will just return a single row with two results. Is this possible and if so how?
you can write subqueries to get data in single row,
Select today , month
from
(
( query to get today's count ) as today,
( query to get month's count ) as month
) t;
yes, u can do group by on dates to get todays nd months count.
Hope this will give u some perception to go on.
Is this what you want?
select array_agg(activity) filter (where date = current_date) as today,
array_agg(activity) filter (where date <> current_date) as rest_of_month
from t
where date_trunc('month', date) = current_date;
This uses arrays so it can handle more than one activity in either category.
Assume you want to query based on a particular date -
select count(case when d.date = :p_query_date then 0 end) day_count
,count(0) month_count
from d -- your table name
where d.date between date_trunc('month', :p_query_date)
and date_trunc('month', :p_query_date + interval '1 month') - interval '1 day'
The above query assumes you have index defined on d.date column. If you have index defined on date_trunc('month', date), the query condition can be simplified to:
date_trunc('month', d.date) = date_trunc('month', :p_query_date)

SQL select unique elements and compare them on two periods

Lets say we have a table that looks like this:
I want to be able to see how many URL records are there during period1 and period2.
where period 1 is "date > '2016-01-01' and date < '2017-01-01' "
and period 2 is "date > '2014-01-1' and date < '2015-01-01' "
Here is what visualization of my expectations :
I can easily do this with one single period using following query:
SELECT URL, COUNT(URL) as Period1
FROM table WHERE date < '2017-01-01'
AND date > '2016-01-01' GROUP BY URL
But how do I add second column with Period2?
Any thoughts would be much appreciated. Sorry if I explained myself incorrectly.
Just change the dates in below query and it will count the hits per period
SELECT [URL]
,SUM(CASE WHEN (date >= '12/22/2015' And date <='12/23/2015') THEN 1 Else 0 END)
,SUM(CASE WHEN (date > '12/30/2015' And date < '12/31/2015') THEN 1 Else 0 END)
FROM LogFilesv2_Dataset.DE_Visits
Group by URL
for BigQuery Standard SQL
#standardSQL
SELECT
URL AS uri,
COUNTIF(date BETWEEN '2016-01-01' AND '2016-12-31') AS Period1,
COUNTIF(date BETWEEN '2014-01-01' AND '2014-12-31') AS Period2
FROM `LogFilesv2_Dataset.DE_Visits`
GROUP BY URL
Not sure which database you are using. But for Oracle database you can try using scalar sub-queries like this.
select url,(select count(*) from test where url=t.url and date_col <= sysdate and date_col > sysdate-20) period1,(select count(*) from test where url=t.url and date_col <= sysdate and date_col > sysdate-40) period2
from test t group by url;
You can replace date range appropriately in the query above.
It is always helpful to provide SQL scripts to create the table and populate the data.

oracle case or decode? - how to handle no recs

How can I make sure in this case statement that if I get now rows selected that I set that my result=1?
I want a value of 1 if I have no records or a count of 0. I would also want a null date to be sysdate by default.
Here is what I have so far. It works with (sysdate-1), but when I tested it with (sysdate-0) or =sysdate (today's date), I
was getting no records. So I want to be able to handle null values too.
How can I change this query to do that? or would I use something like DECODE?
select
to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') as mydt,
case when count(*) = 0 then 1 else 0 end result
from Table1
where
to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') >= trunc(sysdate)-1
GROUP BY
to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD')
Here is my table desc. Perhaps, I should go off of timestamp instead?
There is also a value of counts which may help change this query or not. So what i'm looking for is coming up
with a value of 1 or 0 with a timestamp if that's possible.
SQL> desc Table1
Name Null? Type
----------------------------------------- -------- ----------------------------
YEAR NUMBER
QUARTER NUMBER
MONTH NUMBER
DAY NUMBER
HOUR NUMBER
TIMESTAMP NUMBER
CNT_N NUMBER
ACTN_N NUMBER
ADDR_C VARCHAR2(255)
You will never get a count(*) of zero with a group by. If there are no rows, you won't get any groups and if there are rows then any group you get will show the number of rows.
If you have 3 rows for January 1st and another 3 for January 3rd, you will get :
2011/01/01 3
2011/01/03 3
You won't get a row for January 2nd. Are you wanting to generate that row ? Is there a maximum number of rows that you want returned ?
I think you can do modify your query like below to assign the sysdate to null values
select
nvl(to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') ,sysdate) as mydt
from Table1
where
nvl(to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') ,sysdate)
>= trunc(sysdate)-1
GROUP BY nvl(to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') ,sysdate)
but your second requirement is not very much understood.... please clarify what exectly you want with count(*)
if you want to assign 1 for null date count then you can add following line in select statment
case
when nvl(to_date(year||'/'||month||'/'||day, 'YYYY/MM/DD') ,sysdate) = sysdate then
1
else
count(*)-- or 0 ???!!!!!
It looks like you need to generate the date(s) and then see how may records match each one. Assuming you don't have any data in the future you can do something like:
select trunc(sysdate) + level - (:range + 1) as dt
from dual
connect by level <= (:range + 1);
which with :range set to 1 gives two dates:
DT
---------
19-JUL-11
20-JUL-11
You can then have outer join to that list of dates:
with tmp_dt as (
select trunc(sysdate) + level - (:range + 1) as dt
from dual
connect by level <= (:range + 1)
)
select td.dt as mydt,
case when count(t.year) = 0 then 1 else 0 end as result
from tmp_dt td
left join table1 t on t.year = extract(year from td.dt)
and t.month = extract(month from td.dt)
and t.day = extract(day from td.dt)
group by td.dt
order by td.dt;
If I only have any data in the table for 19-Jul-11, I get:
MYDT RESULT
--------- ----------
19-JUL-11 0
20-JUL-11 1
If you do have data in the future this won't show it; range is how many days to look in the past. If you know there's a limit of, say, seven days you can use connect by level <= (:range + 1) + 7 or have a second variable, but it rather depends on what you want to see.
I've swapped the join around a bit to avoid doing a date conversion for every row in the table, extracting the relevant part of the generated date instead. I hope you have a reason for storing the date components in separate fields rather than as a date.
If you're only looking for data from today, just change the date generator:
with tmp_dt as (select trunc(sysdate) as dt from dual)
select td.dt as mydt,
case when count(t.year) = 0 then 1 else 0 end result
from tmp_dt td
left join table1 t on t.year = extract(year from td.dt)
and t.month = extract(month from td.dt)
and t.day = extract(day from td.dt)
group by td.dt;
If you always want yesterday, it would be select trunc(sysdate) - 1 as dt from dual, etc.
May be you can encapsulate your whole query within the NVL function
like this
SELECT NVL(TO_CHAR((select to_date(year || '/' || month || '/' || day,
'YYYY/MM/DD') as mydt
from Table1
where to_date(year || '/' || month || '/' || day,
'YYYY/MM/DD') >= trunc(sysdate) - 1
GROUP BY to_date(year || '/' || month || '/' || day,
'YYYY/MM/DD')),
'DD/MM/YYYY HH:MI:SS AM'),
'1')
FROM DUAL
I have removed the case statement from the query
Instead , what this query will do is, in case your query does return any value, it will do so without interference. However, in case the query returns NOTHING, then the NVL function will take over and return 1
I have used the TO_CHAR function to maintain the datatype of both the arguments in the NVL function. Both the date returned and the value for NVL are character based
Hope it helps