Date time varchar conversion - tsql

I've looked through other answers. For some reason they don't seem to fix my problem. This is the sql code:
SELECT *
FROM invoices
WHERE InvoiceDate BETWEEN CONVERT(datetime,'2012-00-00',120) AND CONVERT(datetime,'2013-00-00',120 )
ORDER BY InvoiceDate DESC
I keep getting the following error message:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

SELECT *
FROM invoices
WHERE InvoiceDate >= '2012-01-01' AND InvoiceDate < '2013-01-01'
ORDER BY InvoiceDate DESC

You have the following: CONVERT(datetime,'2012-00-00',120). You can't make a date that doesn't have a day or month.

Using a named parameter:
DECLARE #year INT;
SET #year = 2012;
SELECT *
FROM invoices
WHERE InvoiceDate >= DateFromParts(#year,1,1) AND InvoiceDate < DateFromParts(#year+1,1,1)
ORDER BY InvoiceDate DESC;
If DateFromParts is not availanbe (pre-2012 MSSQL) the date can be created like this
WHERE InvoiceDate >= DateAdd(Year,#year-1900,0) AND InvoiceDate < DateAdd(Year,#year-1899,0)

Related

Fetch records of current month using PostgreSQL query

Suppose I have following data in a table
id createdAt
1 2021-02-26T06:29:03.482Z
2 2021-02-27T06:29:03.482Z
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
I want data of current month. ie, if I generate report in march, I need to fetch results of march, so we need only current month data from table.
wanted output is
id createdAt
3 2021-03-14T06:29:03.482Z
4 2021-03-17T06:29:03.482Z
Anyone please help. Thank you.
You can use date_trunc():
select *
from the_table
where date_trunc('month', createdat) = date_trunc('month', current_timestamp);
date_trunc('month', ...) returns the first day of the month.
However, the above is not able to make use of an index on createdat. To improve performance, use a range query:
select *
from the_table
where createdat >= date_trunc('month', current_timestamp)
and createdat < date_trunc('month', current_timestamp) + interval '1 month'
The expression date_trunc('month', current_timestamp) + interval '1 month' returns the start of the next month (that's way this is compared with <)
You can compare the month and year of a date with the current one. But the index by field will not be used, you can build a separate index by year and month for this.
select *
from your_table
where extract(YEAR FROM createdAt) = extract(YEAR FROM now())
and extract(MONTH FROM createdAt) = extract(MONTH FROM now())

DATE ADD function in PostgreSQL

I currently have the following code in Microsoft SQL Server to get users that viewed on two days in a row.
WITH uservideoviewvideo (date, user_id) AS (
SELECT DISTINCT date, user_id
FROM clickstream_videos
WHERE event_name ='video_play'
and user_id IS NOT NULL
)
SELECT currentday.date AS date,
COUNT(currentday.user_id) AS users_view_videos,
COUNT(nextday.user_id) AS users_view_next_day
FROM userviewvideo currentday
LEFT JOIN userviewvideo nextday
ON currentday.user_id = nextday.user_id AND DATEADD(DAY, 1,
currentday.date) = nextday.date
GROUP BY currentday.date
I am trying to get the DATEADD function to work in PostgreSQL but I've been unable to figure out how to get this to work. Any suggestions?
I don't think PostgreSQL really has a DATEADD function. Instead, just do:
+ INTERVAL '1 day'
SQL Server:
Add 1 day to the current date November 21, 2012
SELECT DATEADD(day, 1, GETDATE()); # 2012-11-22 17:22:01.423
PostgreSQL:
Add 1 day to the current date November 21, 2012
SELECT CURRENT_DATE + INTERVAL '1 day'; # 2012-11-22 17:22:01
SELECT CURRENT_DATE + 1; # 2012-11-22 17:22:01
http://www.sqlines.com/postgresql/how-to/dateadd
EDIT:
It might be useful if you're using a dynamic length of time to create a string and then cast it as an interval like:
+ (col_days || ' days')::interval
You can use date + 1 to do the equivalent of dateadd(), but I do not think that your query does what you want to do.
You should use window functions, instead:
with plays as (
select distinct date, user_id
from clickstream_videos
where event_name = 'video_play'
and user_id is not null
), nextdaywatch as (
select date, user_id,
case
when lead(date) over (partition by user_id
order by date) = date + 1 then 1
else 0
end as user_view_next_day
from plays
)
select date,
count(*) as users_view_videos,
sum(user_view_next_day) as users_view_next_day
from nextdaywatch
group by date
order by date;

Concatenate Date and Time

I m trying to concatenate Date and Time using the below line but i m getting an error. Any help?
Time column type: Time (0)
CONVERT(date, getdate()) + ' ' + CONVERT(time(0), [Time]) AS Date_Time
The data types date and varchar are incompatible in the add operator.
There are a number of ways to do that - one of them is to convert both parts to DateTime which supports the add (+) operator:
SELECT CAST(CAST(GetDate() As Date) As DateTime) + (CAST([Time] As DateTime) As Date_Time
The casting of GetDate() to Date and back to DateTime resets the time portion to midnight.
I use the below and it is working:
CAST(CONVERT(date, getdate()) AS nvarchar) + ' ' + CAST(CONVERT(time(0), [Time]) AS nvarchar) AS Date_Time
Thanks to the rules for data type precedence you are trying to convert ' ' to a data type compatible with date and time, hence the error.
The next problem is that a date does not have a time component, hence to combine the two you need to use a datetime or similar data type.
declare #Time as Time = '12:30:00';
select #Time as Time,
-- Get today's date as a date .
Cast( GetDate() as Date ) as Today,
-- Get today's date and convert it to a datetime so that the time can be added.
Cast( Cast( GetDate() as Date ) as DateTime ) + Cast( #Time as DateTime ) as DateAndTime;
Note that time values need to be converted to datetime (or another compatible type) before adding the values. Curiously, SQL Server 2008 didn't require that step.

How to identify invalid dates in postgres table field?

I have a table in PostgreSQL that has two date fields ( start and end ). There are many invalid dates both date fields like 0988-08-11,4987-09-11 etc.. Is there a simple query to identify them? The data type of the field is DATE. Thanks in advance.
Values in a date column ARE valid per definition. The year 0988 = 988 is a valid historic date as well as the year 4987 which is far in the future.
To filter out dates which are too historic or too far in the future you simply make this query:
SELECT
date_col
FROM
table
WHERE
date_col < /* <MINIMUM DATE> */
OR date_col > /* <MAXIMUM DATE> */
For date ranges (your minimum and maximum date) you could use the daterange functionality:
https://www.postgresql.org/docs/current/static/rangetypes.html
https://www.postgresql.org/docs/current/static/functions-range.html
Example table:
start_date end_date
2015-01-01 2017-01-01 -- valid
200-01-01 900-01-01 -- completely too early
3000-01-01 4000-01-01 -- completely too late
0200-01-01 2000-01-01 -- begin too early
2000-01-01 4000-01-01 -- end too late
200-01-01 4000-01-01 -- begin too early, end too late
Query:
SELECT
start_date,
end_date
FROM
dates
WHERE
daterange('1900-01-01', '2100-01-01') #> daterange(start_date, end_date)
Result:
start_date end_date
2015-01-01 2017-01-01
demo:db<>fiddle
Those are valid dates, but if you have business rules that state they are not valid for your purpose, you can delete them based on those rules:
For example, if you don't want any dates prior to 1900 or after 2999, this statement would delete the records with those dates:
DELETE FROM mytable
WHERE
start_date < '1900-01-01'::DATE OR
start_date >= '2999-01-01'::DATE OR
end_date < '1900-01-01'::DATE OR
end_date >= '2999-01-01'::DATE;
If you want to replace the dates with the lowest/highest acceptable dates instead of deleting the entire record, you could do something like this:
UPDATE mytable
SET
start_date = least('2999-01-01'::DATE, greatest('1900-01-01'::DATE, start_date)),
end_date = least('2999-01-01'::DATE, greatest('1900-01-01'::DATE, end_date))
WHERE
start_date < '1900-01-01'::DATE OR
start_date >= '2999-01-01'::DATE OR
end_date < '1900-01-01'::DATE OR
end_date >= '2999-01-01'::DATE;

Postgres: Update date and retain time from timestamp

I have a field1 with timestamp, datatype and values format is 2016-02-23 12:01:30.
I'm running the query:
UPDATE <table> set field1 = '2015-12-31'::timestamp::date where .....
The output changes to:
2015-12-31 00:00:00
It converts the time to all zero's. How to change the date and retain the timestamp?
Try this:
UPDATE mytable
SET field1 = '2015-12-31'::timestamp +
EXTRACT(HOUR FROM field1) * INTERVAL '1 HOUR' +
EXTRACT(MINUTE FROM field1) * INTERVAL '1 MINUTE' +
EXTRACT(SECOND FROM field1) * INTERVAL '1 SECOND'
WHERE ...
Demo here
There's another way, using the DateTime type.
So if you want to set a table's Date to today, you can use this:
UPDATE table SET column = current_date::date + column::time;
Switch current_date with "2019-02-23" and it should work as well.
Simply add the new date and the existing time. Here it is:
UPDATE mytable
SET field1 = '2015-12-31'::date + field1::time with time zone
WHERE ...;
or even cleaner cut:
UPDATE mytable
SET field1 = field1 - field1::date + '2015-12-31'::date
WHERE ...;
The subtraction of timestamps yields an interval. The resulting interval is can the be added to the desired date to give the desired date with the prior time.
with ats (old_tz) as (select now() )
select old_tz, '2015-12-31'::timestamptz + (old_tz - date_trunc('day', old_tz)) new_tz
from ats;
OOPS. Didn't realize how old this post was until after posting, but still believe it may valuable to future viewers. So I'll just leave it.