I tried two queries:
SELECT CASE WHEN CAST(CURRENT_TIMESTAMP() AS DATE) = CURRENT_DATE() THEN 1 ELSE 0 END;
and
SELECT CASE WHEN DATE(CURRENT_TIMESTAMP()) = CURRENT_DATE() THEN 1 ELSE 0 END;
The first query fails in Legacy SQL but not in Standard SQL, while the second query works. (Standard SQL is currently not covered by SLA.)
There are two problems with first query in Legacy SQL:
CAST(... AS DATE) in Legacy SQL only works on strings, while CURRENT_TIMESTAMP returns TIMESTAMP type
CURRENT_DATE in Legacy SQL is misleadingly returns STRING, not DATE :(
Both of these problems are indeed fixed with Standard SQL
Legacy SQL has limited support for DATE. For more information, see Civil time in legacy SQL
So, if you need to be in Legacy SQL - you should use second query in your case with DATE() function
Related
I have a Sql server table which contains below Date values(4th october)
Now Below query is not showing any result
select
*
from [dbo].[TB_AUDIT] TBA
where TBA.ActionDate >= '10/01/2018' and TBA.ActionDate <= '10/04/2018' which is not correct.
But If I write
select
*
from [dbo].[TB_AUDIT] TBA
where TBA.ActionDate >= '10/01/2018' and TBA.ActionDate <= '10/05/2018' it is returning me all results.
What I am doing wrong.
There are two problems with this query. The first, is that it's using a localized string. To me, it looks like it's asking for rows between January and April. The unambiguous date format is YYYYMMDD. YYYY-MM-DD by itself may not work in SQL server as it's still affected by the language. The ODBC date literal, {d'YYYY-MM-DD'} also works unambiguously.
Second, the date parameters have no time which defaults to 00:00. The stored dates though have a time element which means they are outside the search range, even if the date parameter was recognized.
The query should change to :
select
*
from [dbo].[TB_AUDIT] TBA
where
cast(TBA.ActionDate as date) between '20181001' and '20181004'
or
cast(TBA.ActionDate as date) between {d'2018-10-01'} and {d'2018-10-04'}
Normally, applying a function to a field prevents the server from using any indexes. SQL Server is smart enough though to convert this to a query that covers the entire date, essentially similar to
where
TBA.ActionDate >='2018:10:01T00:00' and TBA.ActionDate <'2018-10-05T00:00:00'
When you don't specify a time component for a DATETIME, SQL Server defaults it to midnight. So in your first query, you're asking for all results <='2018-10-04T00:00:00.000'. All of the data points in your table are greater than '2018-10-04T00:00:00.000', so nothing is returned.
You want
TBA.ActionDate >= '2018-10-01T00:00:00.000' and TBA.ActionDate < '2018-10-05T00:00:00.000'`
Use properly formatted dates!
select *
from [dbo].[TB_AUDIT] TBA
where TBA.ActionDate >= '2018-10-01' and TBA.ActionDate <= '2018-10-04'
YYYY-MM-DD isn't just a good idea. It is the ISO standard for date formats, recognized by most databases.
when you just filter by the date, it is with regard to the time as per the standard.
I am converting Oracle queries to a SQL Server equivalent, some have been easier than others, right now I am stuck on a query that is containing this in a where clause
TRUNC(TO_NUMBER(TO_DATE(SYSDATE) - MyTable.DOBDATE) / 365, 0)
I've read that Convert is SQL Server's equivalent to ORACLE's TRUNC,
I know the SYSDATE will be GetDate() but I am lost on this part of the query
TRUNC(TO_NUMBER(TO_DATE(SYSDATE)
What would be SQL Server's equivalent to this ?
EDIT
in short how do I take this Oracle statement
TRUNC(TO_NUMBER(TO_DATE(SYSDATE) - MyTable.DOBDATE) / 365, 0)
and convert to its SQL Server equivalent
The equivalent would be:
select datediff(day, MyTable.DOBDate, getdate()) / 365
Note that SQL Server does integer division, so the result is an integer. No need for an additional function.
The to_number() is redundant in Oracle, I think. Neither set of code exactly calculates the age in years, because neither takes leap years into account.
Legacy SQL
I'm using GBQ's legacy SQL to query tables dynamically using the TABLE_QUERY function. I dynamically generate the table name to query based on CURRENT_TIMESTAMP. For example, I select devices from the past 14 days of hit data in tables that are partitioned by quarter (ie. mydataset.hit_data_[1-4]).
Standard SQL
I need to convert the timezones to PST. GBQ Standard SQL has TIME ZONE conversions. Switching to Standard SQL, I am able to convert timezones using the GBQ Standard SQL. But if I now try to use a TABLE_QUERY in the same query, to do what I was doing in the Legacy SQL version, I get:
Error: Table-valued functions are not supported
Using both
Is there a way to have the best of both worlds? I would like to query mydataset.hit_data_3 and mydataset.hit_data_4 based on the current timestamp in Q4, if the previous 14 days overlap into Q3.
SELECT
device
FROM
TABLE_QUERY(mydataset, 'table_id = CONCAT(\"hit_data_\", STRING(QUARTER(TIMESTAMP(CURRENT_TIMESTAMP, "America/Los_Angeles")))) OR table_id = CONCAT(\"hit_data_\", STRING(QUARTER(DATE_ADD(TIMESTAMP(CURRENT_TIMESTAMP, "America/Los_Angeles"), INTERVAL -14 DAY)))) ')
WHERE
DATE(date_time) BETWEEN DATE(DATE_ADD(TIMESTAMP(CURRENT_TIMESTAMP, 'America/Los_Angeles'), INTERVAL -14 DAY))
AND DATE(CURRENT_DATE())
;
It looks ugly, but in GBQ it should be valid.
Standard SQL doesn't support TABLE_QUERY or TABLE_DATE_RANGE functions. Instead it supports wildcard tables with a special pseudo column _TABLE_SUFFIX:
You should be able to rewrite your query with a WHERE clause on _TABLE_SUFFIX pseudo column
https://cloud.google.com/bigquery/docs/querying-wildcard-tables
with BigQuery Standard SQL you should use _TABLE_SUFFIX pseudo column that allows you to chose table(s) to query from
Below is direction to go
SELECT *
FROM `mydataset.hit_data_*`
WHERE (_TABLE_SUFFIX = STRING(QUARTER(TIMESTAMP(CURRENT_TIMESTAMP, "America/Los_Angeles")))
OR _TABLE_SUFFIX = STRING(QUARTER(DATE_ADD(TIMESTAMP(CURRENT_TIMESTAMP, "America/Los_Angeles"), INTERVAL -14 DAY)))
)
AND DATE(date_time) BETWEEN
DATE(DATE_ADD(TIMESTAMP(CURRENT_TIMESTAMP, 'America/Los_Angeles'), INTERVAL -14 DAY))
AND DATE(CURRENT_DATE())
Note: you need to make sure you are using functions supported by Standard SQL
For example instead of
QUARTER(TIMESTAMP(...))
you should use
EXTRACT(QUARTER FROM TIMESTAMP(...))
I have a query in which I want to select data from a column where the data is a date. The problem is that the data is a mix of text and dates.
This bit of SQL only returns the longest text field:
SELECT MAX(field_value)
Where the date does occur, it is always in the format xx/xx/xxxx
I'm trying to select the most recent date.
I'm using MS SQL.
Can anyone help?
Try this using ISDATE and CONVERT:
SELECT MAX(CONVERT(DateTime, MaybeDate))
FROM (
SELECT MaybeDate
FROM MyTable
WHERE ISDATE(MaybeDate) = 1) T
You could also use MAX(CAST(MaybeDate AS DateTime)). I got in the (maybe bad?) habit of using CONVERT years ago and have stuck with it.
To do this without a conversion error:
select max(case when isdate(col) = 1 then cast(col as date) end) -- or use convert()
from . . .
The SQL statement does not specify the order of operations. So, even including a where clause in a subquery will not guarantee that only dates get converted. In fact, the SQL Server optimizer is "smart" enough to do the conversion when the data is brought in and then do the filtering afterwards.
The only operation that guarantees sequencing of operations is the case statement, and there are even exceptions to that.
Another solution would be using PATINDEX in WHERE clause.
SELECT PATINDEX('[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]', field_value)
Problem with this approach is you really are not sure if something is date (e.g. 99/99/9999 is not date).
And problem with IS_DATE is it depends on configuration (e.g. DATEFORMAT).
So, use an appropriate option.
Is there a way to write a query equivalent to
select * from log_table where dt >= 'nov-27-2009' and dt < 'nov-28-2009';
but where you could specify only 1 date and say you want the results for that entire day until the next one.
I'm just making this up, but something of the form:
select * from log_table where dt = 'nov-27-2009':+1;
I do not believe there is one method that is portable to all RDBMSes.
A check in one of my references (SQL Cookbook) shows that no one RDBMS solves the problem quite the same way. I would recommend checking out Chapter 8 of that book, which covers all of the different methods for DB2, Oracle, PostgreSQL, MySQL.
I've had to deal with this issue in SQLite, though, and SQL Cookbook doesn't address that RDBMS, so I'll mention a bit about it here. SQLite doesn't have a date/time data type; you have to create your own by storing all date/time data as TEXT and ensure that your application enforces its formatting. SQLite does have a set of date/time conversion functions that allow you to add nominal date/times while maintaining the data as strings. If you need to add two time durations (HH:MM:SS) to each other, though, based upon data that you've stored in text columns that you are treating as date/time data, you'll have to write your own functions (search for "Defining SQLite User Functions") and attach them to the database at runtime via a call to sqlite3_create_function(). If you want an example of some user functions that add time values, let me know.
For MS SQL Server, check out DATEPART.
/* dy = Day of Year */
select * from log_table where datepart(dy, dt) = datepart(dy, '2009-nov-27');
With SQL Server, you could
Select * From table
Where dt >= DateAdd(day, DateDiff(day, 0, #ParamDate), 0)
And dt < DateAdd(day, DateDiff(day, 0, #ParamDate), 1)
As long as you are dealing with the date data type for the respective data type, the following will work:
t.date_column + 1
...will add one day to the given date. But I have yet to find a db that allows for implicit data type conversion into a date.
SELECT '12-10-2009' + 1
...will fail on SQL Server because SQL Server only performs the implicit conversion when comparing to a datetime data type column. So you need to use:
SELECT CONVERT(DATETIME, '12-10-2009') + 1
For Oracle, you'd have to use the TO_DATE function; MySQL would use something like STR_TO_DATE, etc.
Have a column that just has the date part (time is 00:00:00.000) and then you can add a where clause: WHERE dt = '2009-11-27'