COALESCE for no rows returned - sql-server

I am using COALESCE to return first non-null values. In below query I am trying to get data for that day of the week which has latest data / or some data (Starting Sunday - Monday). So Let's say if Sunday, Tuesday, Monday has data it should return me Sunday data. If all days have data , it should return me Sunday (7) data. But below query does not return anything. May be because the value returned is zero rows instead of null ??
SELECT *
FROM
status_summary
WHERE COALESCE(("day_of_week"(Datetime) = 7),("day_of_week"(Datetime) = 6),
("day_of_week"(Datetime) = 5),("day_of_week"(Datetime) = 4),
("day_of_week"(Datetime) = 3),("day_of_week"(Datetime) = 2),
("day_of_week"(Datetime) = 1))
When i run individual query like below, it returns me data.
SELECT *
FROM
status_summary
WHERE COALESCE(("day_of_week"(Datetime) = 5))
OR
SELECT *
FROM
status_summary
WHERE COALESCE(("day_of_week"(Datetime) = 4))
The syntax is in presto (AWS Athena) but I don't mind sql syntax as well.
SQL : datename(day,MyDate) = 'Sunday'

You'll need to have the sub-select pick the day of week, something like:
SELECT *
FROM status_summary
WHERE day_of_week(Datetime) = (SELECT MAX(day_of_week(Datetime)) FROM status_summary)

Related

Calculate number of specific days between dates in Snowflake

I am looking for some guidance on finding number of occurrences of lets say Monday and Wednesday between two dates Date1 and Date2 inclusive of the two dates in Snowflake. Any Suggestions?
A standard practice is to build a calendar table: either as pernament table or inlined view.
CREATE TABLE calendar
AS
SELECT DATEADD(day, ROW_NUMBER() OVER(ORDER BY seq8()), '1999-12-31'::DATE) AS d,
DAYOFWEEK(d) AS day_of_week,
DAYNAME(d) AS day_name
-- month/quarter/year/...
FROM TABLE(GENERATOR(ROWCOUNT => 365*100));
Then:
SELECT c.day_name, COUNT(*) AS cnt
FROM calendar c
WHERE c.d BETWEEN '<date_1>' AND '<date_2>'
AND c.day_of_week IN (1,3)
GROUP BY c.day_name;
Notes: day of week depeneds on parameter WEEK_START.
Lukasz's table solution is quite neat, but I will try the JS version:
// not sure the best name to have here
create or replace function num_of_days_in_between(
day_nums varchar(255),
start_date varchar(10),
end_date varchar(10)
)
RETURNS string
LANGUAGE JAVASCRIPT
AS $$
// perform some validations first on parameters
var s = new Date(START_DATE);
var e = new Date(END_DATE);
var split = DAY_NUMS.split(",");
var count = 0;
var d = s;
// go through each day and check if the
// current day is in the days asked
while (d.getTime() <= e.getTime()) {
// split array contains strings, so we need to
// force getDay() value to be string as well,
// otherwise includes() will not find it
if(split.includes(d.getDay()+"")) {
count++;
}
// advance to the next day
d = new Date(d.getTime() + 86400000);
}
return count;
$$;
-- Monday and Wednesday
select num_of_days_in_between('1,3', '2021-10-01', '2021-11-01'); -- 9
-- Tuesday
select num_of_days_in_between('2', '2021-10-01', '2021-11-01'); -- 4
Note that in JS, days start from Sunday with index of 0, refer to Date.getDay().

Tracking performance of a stored procedure over time via Query Store - possible?

I'm working on some queries, using the Query Store objects (query_store_runtime_stats, query_store_plan, query_store_query) that will track the performance of any stored procedure over time.
I have the following query to create the #RuntimeStats table:
Declare #LookbackDayCount int = 14
SELECT
ObjectName = ISNULL(Object_Name(q.object_id), 'None')
,RunDate = convert(date, first_execution_time)
,Total_LogicalReads = ROUND(CONVERT(FLOAT, SUM(rs.avg_logical_io_reads * rs.count_executions)) * 8, 2)
,Total_CPU = ROUND(CONVERT(FLOAT, SUM(rs.avg_cpu_time * rs.count_executions)) * 8, 2)
,Total_Duration = ROUND(CONVERT(FLOAT, SUM(rs.avg_duration * rs.count_executions)) * 8, 2)
Into #RuntimeStats
FROM sys.query_store_runtime_stats rs
JOIN sys.query_store_plan p ON p.plan_id = rs.plan_id
JOIN sys.query_store_query q ON q.query_id = p.query_id
WHERE
rs.first_execution_time between dateadd(dd, #LookbackDayCount * -1, getdate()) and getdate()
GROUP BY
ISNULL(Object_Name(q.object_id), '')
,q.object_id
,convert(date, first_execution_time)
This query is not getting the data I expect. It only has what looks like a full set of object names for the most recent day. As you go back in time, it only retains the most highly used objects. So, this simple query:
Select RunDate, TotalObjects = count(ObjectName )
From #RuntimeStats
Group by RunDate
Order by rundate desc
...returns data like this:
RunDate Total
2021-07-28 796
2021-07-27 27
2021-07-26 27
2021-07-25 14
2021-07-24 14
2021-07-23 15
2021-07-22 15
2021-07-21 14
2021-07-20 14
2021-07-19 14
2021-07-18 13
In other words, it looks like it has a full set of data for the most recent day, but then loses older data, for almost all objects.
Any thoughts on what could be causing this? I don't care about the query text (any data from query_store_query_text), I just care about raw performance data (Logical Reads, CPU, etc) for the stored procedure.

select * from where table=Today's Date in SQL Server Management Studio

I have a query where I need to use the today's date in the where clause.
The original query is:
select *
from hist
where checkdt = '8/18/2017'
and status = 'R'
and PSPAY is not null
But I need to replace the date with a get date function.
select *
from hist
where checkdt = Today's Date
and status = 'R'
and PSPAY is not null
I have used the GetDate() and curdate() but it doesn't work.
You should use:
select h.*
from hist h
where checkdt = cast(getdate() as date) and
status = 'R' and
PSPAY is not null;
In SQL Server, the cast() can still make use of an index, so this is the best approach.

Apply Different WHERE clause depending on value of one field

i'm trying to build a query in which I need to apply 2 different where clauses, depending on the value of Current Month. In this case, I need to show data from the last 2 years, only of the months before the current month:
Example 1:
Current Date is: 01-01-2017
Need to show data from:
01/2015; 02/2015; 03/2015; 04/2015; 05/2015; 06/2015;
07/2015; 08/2015; 09/2015; 10/2015; 11/2015; 12/2015;
01/2016; 02/2016; 03/2016; 04/2016; 05/2016; 06/2016;
07/2016; 08/2016; 09/2016; 10/2016; 11/2016; 12/2016.
Example 2:
Current Date is: 01-03-2017
Need to show data from: 01/2016; 02/2016; 01/2017; 02/2017.
So I built the following query:
SELECT *
FROM TABLE1
WHERE
CASE MONTH(GETDATE())
WHEN 1
THEN YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE())
ELSE YEAR(Data)>=YEAR(GETDATE())-1 and YEAR(data)<=YEAR(data) and MONTH(data)<MONTH(GETDATE())
END
I'm getting an error.
Can you please help me?
Thank you.
Your syntax is incorrect for sure. THEN is not a logical expression - it is supposed to return value. So you can't write logical expression in THEN/ELSE blocks as you have attempted to. Instead you might try something like:
WHERE
#date >= CASE WHEN a=b THEN '20150101' ELSE '20160202' END
Another thing is: conversions and functions in predicate are very bad for performance. When working with dates you might want to prepare filter predicate before the query when possible, e.g.:
declare
#date_begin date,
#date_end date
set #date_end = DATEADD(..., #arg_date)
set #date_begin = DATEADD(YEAR, -2, #date_end)
select ...
where date between #date_begin and #date_end
in your case it could be something like:
declare
#arg_date DATE = GETDATE(),
#date_begin DATE,
#date_end DATE,
#max_month INT
set #max_month = MONTH(#date)
if #max_month = 1
begin
set #date_end = DATEADD(dd, 1-DATEPART(dy, #arg_date), #arg_date) /* first day of year */
set #date_begin = dateadd(YY, -2, #date_end)
end
else
begin
set #date_end = #arg_date
set #date_begin = dateadd(YY, -1, DATEADD(dd, 1-DATEPART(dy, #date_end), #date_end)) /* first day of year_begin */
end
SELECT *
FROM TABLE1 t
WHERE t.date >= #date_begin and t.date < #date_end
AND (#max_month = 1 OR MONTH(t.date) < #max_month)
another (a better) way is to prepare #periods table variable, put each (date_begin, date_end) pair you need into it and join with TABLE1 - you'll get rid of all function calls from within WHERE clause.
You should realize: you know exactly which periods of each year you need in the result set. There is nothing to compute from stored TABLE1->date column. Just filter it with precomputed date intervals. Don't convert or modify date column - it is already ready to use. Merely apply appropriate filters. MONTH(date) <= 3 is date <= 20170331. Don't torture left part - prepare appropriate right part of such predicates.
The easiest way would be something like:
SELECT *
FROM TABLE1
WHERE
(YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE()) AND MONTH(GETDATE()) = 1)
OR (YEAR(Data)>=YEAR(GETDATE())-1 and MONTH(data)<MONTH(GETDATE()) and MONTH(GETDATE()) <> 1)
(Note I removed the superfluous and YEAR(data)<=YEAR(data).).
Personally I prefer (and I think it's generally advised) AND/OR logic to a CASE in a WHERE clause.
The error with your CASE statement is caused by the fact that CASE returns an atomic value. It cannot be used in the same way as if in procedural languages.
You can't swap in additional statements to your where clause using case statements. Instead, you need to resolve the case to an equality:
select *
from Table1
where case month(getdate()) -- You want to avoid using functions on fields in your WHERE claises, as this can reduce performance.
when 1 then case when Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
then 1 -- Data rows the meet the criteria will return 1.
else 0 -- Data rows that do not will return 0.
end
else case when (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
then 1
else 0
end
end = 1 -- Then limit the results to only those rows that returned a 1.
In your specific instance however, this can be simplified to a standard or:
select *
from Table1
where (month(getdate()) = 1
and Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
)
or (month(getdate()) <> 1
and (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
)
Note the use of brackets above to separate out the logical tests. Where a Data row meets either one of those criteria it will be returned in your query.

How to query DATETIME field using only date in Microsoft SQL Server?

I have a table TEST with a DATETIME field, like this:
ID NAME DATE
1 TESTING 2014-03-19 20:05:20.000
What I need a query returning this row and every row with date 03/19/2014, no matter what the time is. I tried using
select * from test where date = '03/19/2014';
But it returns no rows. The only way to make it work that I found is to also provide the time portion of the date:
select * from test where date = '03/19/2014 20:03:02.000';
use range, or DateDiff function
select * from test
where date between '03/19/2014' and '03/19/2014 23:59:59'
or
select * from test
where datediff(day, date, '03/19/2014') = 0
Other options are:
If you have control over the database schema, and you don't need the
time data, take it out.
or, if you must keep it, add a computed column attribute that has the time portion of the date value stripped off...
Alter table Test
Add DateOnly As
DateAdd(day, datediff(day, 0, date), 0)
or, in more recent versions of SQL Server...
Alter table Test
Add DateOnly As
Cast(DateAdd(day, datediff(day, 0, date), 0) as Date)
then, you can write your query as simply:
select * from test
where DateOnly = '03/19/2014'
Simple answer;
select * from test where cast ([date] as date) = '03/19/2014';
I am using MySQL 5.6 and there is a DATE function to extract only the date part from date time. So the simple solution to the question is -
select * from test where DATE(date) = '2014-03-19';
http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html
This works for me for MS SQL server:
select * from test
where
year(date) = 2015
and month(date) = 10
and day(date)= 28 ;
select * from test
where date between '03/19/2014' and '03/19/2014 23:59:59'
This is a realy bad answer. For two reasons.
1.
What happens with times like 23.59.59.700 etc.
There are times larger than 23:59:59 and the next day.
2.
The behaviour depends on the datatype.
The query behaves differently for datetime/date/datetime2 types.
Testing with 23:59:59.999 makes it even worse because depending on the datetype you get different roundings.
select convert (varchar(40),convert(date , '2014-03-19 23:59:59.999'))
select convert (varchar(40),convert(datetime , '2014-03-19 23:59:59.999'))
select convert (varchar(40),convert(datetime2 , '2014-03-19 23:59:59.999'))
-- For date the value is 'chopped'.
-- For datetime the value is rounded up to the next date. (Nearest value).
-- For datetime2 the value is precise.
use this
select * from TableName where DateTimeField > date() and DateTimeField < date() + 1
Try this
select * from test where Convert(varchar, date,111)= '03/19/2014'
you can try this
select * from test where DATEADD(dd, 0, DATEDIFF(dd, 0, date)) = '03/19/2014';
There is a problem with dates and languages and the way to avoid it is asking for dates with this format YYYYMMDD.
This way below should be the fastest according to the link below. I checked in SQL Server 2012 and I agree with the link.
select * from test where date >= '20141903' AND date < DATEADD(DAY, 1, '20141903');
Bad habits to kick : mis-handling date / range queries
You can use this approach which truncates the time part:
select * from test
where convert(datetime,'03/19/2014',102) = DATEADD(dd, DATEDIFF(dd, 0, date), 0)
-- Reverse the date format
-- this false:
select * from test where date = '28/10/2015'
-- this true:
select * from test where date = '2015/10/28'
Simply use this in your WHERE clause.
The "SubmitDate" portion below is the column name, so insert your own.
This will return only the "Year" portion of the results, omitting the mins etc.
Where datepart(year, SubmitDate) = '2017'
select *, cast ([col1] as date) <name of the column> from test where date = 'mm/dd/yyyy'
"col1" is name of the column with date and time
<name of the column> here you can change name as desired
select *
from invoice
where TRUNC(created_date) <=TRUNC(to_date('04-MAR-18 15:00:00','dd-mon-yy hh24:mi:ss'));
Test this query.
SELECT *,DATE(chat_reg_date) AS is_date,TIME(chat_reg_time) AS is_time FROM chat WHERE chat_inbox_key='$chat_key'
ORDER BY is_date DESC, is_time DESC
select * from invoice where TRANS_DATE_D>= to_date ('20170831115959','YYYYMMDDHH24MISS')
and TRANS_DATE_D<= to_date ('20171031115959','YYYYMMDDHH24MISS');
SELECT * FROM test where DATEPART(year,[TIMESTAMP]) = '2018' and DATEPART(day,[TIMESTAMP]) = '16' and DATEPART(month,[TIMESTAMP]) = '11'
use trunc(column).
select * from test t where trunc(t.date) = TO_DATE('2018/06/08', 'YYYY/MM/DD')

Resources