Calculate Month Difference in Google BigQuery - google-bigquery

BigQuery does not allow you to select the daypart MONTH in DATEDIFF.
Is there any other way to do this in BigQuery.
I can get days difference using the following but not months.
SELECT
OrderID,
OrderDate,
STRING( YEAR ( OrderDate )) + '-' + STRING(MONTH ( OrderDate )) as order_month,
UserID,
FirstOrderDate
DATEDIFF( OrderDate, FirstOrderDate) as date_diff,
FROM [orders.orders]
WHERE FirstOrderDate > DATE_ADD(CURRENT_TIMESTAMP(), -1, 'YEAR')

With Standard SQL you can use date_diff:
#StandardSQL
select date_diff(current_date, date '2018-03-06', month)

With standard SQL date_diff could work, but if you get an error saying "DATE_DIFF does not support the MONTH date part at [n:m]code", that's because your it's timestamp rather than date. To solve this issue, first cast the timestamp to date, then use date_diff function.
For example:
DATE_DIFF(CAST(OrderDate AS DATE), CAST(FirstOrderDate AS DATE), month) AS DATE_DIF

How about this?
(12 * YEAR(t2) + MONTH(t2)) - (12 * YEAR(t1) + MONTH(t1))
+ IF (DAY(t2) >= DAY(t1), 0, -1)
Running it over a couple of examples, it looks like what you'd want:
SELECT
(12 * YEAR(t2) + MONTH(t2)) - (12 * YEAR(t1) + MONTH(t1))
+ IF (DAY(t2) >= DAY(t1), 0, -1)
FROM
(SELECT TIMESTAMP("2010-12-01") as t1, TIMESTAMP("2011-01-01") as t2), // 1
(SELECT TIMESTAMP("2010-12-02") as t1, TIMESTAMP("2011-01-01") as t2), // 0
(SELECT TIMESTAMP("2010-12-01") as t1, TIMESTAMP("2011-12-01") as t2), // 12
(SELECT TIMESTAMP("2010-10-21") as t1, TIMESTAMP("2015-01-10") as t2) // 50

Related

Select Table of Days For One Year SQLITE

I am trying to select a table of every date for the last year.
In SQL Server, I can run something like this:
SELECT TOP (DATEDIFF(DAY, DATEADD(YEAR, - 1, GETDATE()), GETDATE()) + 1)
Date = CAST(DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY a.object_id) - 1, DATEADD(YEAR, - 1, GETDATE())) AS DATE)
FROM sys.all_objects a
It returns 1 column with 366 rows containing the dates from 1 year ago until now.
I am looking for something equivalent in SQLITE.
You can do it with a recursive CTE:
WITH cte AS (
SELECT DATE(CURRENT_DATE, '-1 year') date
UNION ALL
SELECT DATE(date, '+1 day')
FROM cte
WHERE date < CURRENT_DATE
)
SELECT * FROM cte;
See the demo.
You can also do this using an inline tally table
WITH L1(n) AS (
VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
),
L2(n) AS (
SELECT 1 FROM L1 a CROSS JOIN L1 b
)
SELECT DATE(CURRENT_DATE, (-ROW_NUMBER() OVER (ORDER BY 1) + 1) || ' days') AS date
FROM L2
LIMIT julianday(CURRENT_DATE) - julianday(DATE(CURRENT_DATE, '-1 year')) + 1;
db<>fiddle
For newer versions of SQLite you may want to add NOT MATERIALIZED to the CTEs.

How do I make that difference from months using standardSQL (BigQuery)

I have the following query:
#standardSQL
SELECT distinct (grand_total/months) AS avg, ((grand_total/days)) AS
avg_day
FROM
(select count(searchint.id) as Total, (DATE_DIFF(DATE ({{DATE_END}}),
DATE ({{DATE_START}}), DAY)+1) AS days, ((12 * YEAR(TIMESTAMP({{DATE_END}})) +
MONTH(TIMESTAMP({{DATE_END}}))) - (12 * YEAR(TIMESTAMP({{DATE_START}}))
+ MONTH(TIMESTAMP({{DATE_START}}))) +1) AS months,
(select count(searchint.id) as Total
from `dbsearch`
where cast(replace(searchint.createdDate,'Z','')as DateTime) >=
cast({{DATE_START}} as DateTime)
and cast(replace(searchint.createdDate,'Z','')as DateTime) <=
cast(DATE_ADD(cast({{DATE_END}} as date), Interval 1 day ) as DateTime)) AS grand_total
from `dbsearch`
where cast(replace(searchint.createdDate,'Z','')as DateTime) >=
cast({{DATE_START}} as DateTime)
and cast(replace(searchint.createdDate,'Z','')as DateTime) <=
cast(DATE_ADD(cast({{DATE_END}} as date), Interval 1 day ) as DateTime)
group by date(cast(replace(searchint.createdDate,'Z','')as DateTime))
ORDER BY 2 DESC) AS groupby
However, when I try to run BigQuery it gives the following error:
Function not found: YEAR at [5:180]
I understand it's because I'm using standardSQL, but how do I make that difference from months using standardSQL?
To find difference in months between two dates you better to use DATE_DIFF()
DATE_DIFF(DATE_END, DATE_START, MONTH)
StandardSQL in BigQuery supports the ISO/ANSI-standard function for extracting date parts. This is extract():
You want:
extract(year from <datecol>)
extract(month from <datecol>)
This is explained in the documentation.

BigQuery Where Date is Less Than or Equal to 3 Days Minus Current Date

I'm trying to create a query to only return data where date is minus 3 days from the current date. I've tried:
date <= DATE_ADD(CURRENT_DATE(), -3, 'DAY')
But this returns Error: Expected INTERVAL expression
See WHERE clause in below example
#standardSQL
WITH yourTable AS (
SELECT i, date
FROM UNNEST(GENERATE_DATE_ARRAY('2017-04-15', '2017-04-28')) AS date WITH OFFSET AS i
)
SELECT *
FROM yourTable
WHERE date <= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)
-- ORDER BY date
Btw, in case if you are still with Legacy SQL - see below example
#legacySQL
SELECT *
FROM -- yourTable
(SELECT 1 AS id, DATE('2017-04-20') AS date),
(SELECT 2 AS id, DATE('2017-04-21') AS date),
(SELECT 3 AS id, DATE('2017-04-22') AS date),
(SELECT 4 AS id, DATE('2017-04-23') AS date),
(SELECT 5 AS id, DATE('2017-04-24') AS date),
(SELECT 6 AS id, DATE('2017-04-25') AS date)
WHERE TIMESTAMP(date) <= DATE_ADD(TIMESTAMP(CURRENT_DATE()), -3, 'DAY')
-- ORDER BY date
This works with a string formatted date.
DATE(TIMESTAMP(date)) <= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)
Just tested this and seems to work.
I added this :
and DATE(TIMESTAMP(datevalue)) >= DATE_SUB(CURRENT_DATE(), INTERVAL 21 DAY)
and managed to get all records greater than last 21 days worth. Only thing I changed from #ericbrownaustin 's code was changed the 'date' in the first piece of code in the second set of parenthesis.

How to get the date for two saturdays ago

I have the following query which displays a table with date:
SELECT *
FROM [Db].[dbo].[btotals]
ORDER BY [Date] DESC
Which displays:
Date
06/07/2014
05/31/2014
05/24/2014
05/17/2014
05/10/2014
05/03/2014
If I pick SELECT TOP 1 will give me the first row. How can I modify my query so I get the week prior to last week? In this case the 5/31/14 row?
If your dates are always a week apart, and you just want the second row you can use ROW_NUMBER():
SELECT Date
FROM ( SELECT Date,
RowNumber = ROW_NUMBER() OVER(ORDER BY Date DESC)
FROM [Db].[dbo].[btotals]
) AS d
WHERE d.RowNumber = 2;
Otherwise you can use the following to get the saturday of 2 weeks ago:
SELECT DATEADD(DAY, -((DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7) - 7, CAST(GETDATE() AS DATE));
Then select your first date that is on or after that:
SELECT TOP 1 Date
FROM [Db].[dbo].[btotals]
WHERE Date >= DATEADD(DAY, -((DATEPART(WEEKDAY, GETDATE()) + ##DATEFIRST) % 7) - 7, CAST(GETDATE() AS DATE))
ORDER BY Date;
This should also work, if you are trying to select the second date, Though Gareth's approach of using ROW_NUNMBER is a better one.
SELECT TOP 1 *
FROM (
SELECT TOP 2 *
FROM [Db].[dbo].[btotals]
ORDER BY [Date] DESC
) as X
ORDER BY Date ASC
Another approach:
SELECT TOP 1 *
FROM [Db].[dbo].[btotals]
WHERE [Date] < (SELECT MAX([Date]) FROM [Db].[dbo].[btotals])
ORDER BY [Date] DESC

Comparing only Year and Month

I'm using this to compare Year and month, but it failing when month is less than current month even though the year is greater than current year
SELECT * FROM DUMMY_TABLE WHERE
YEAR(PREV_ELIG_REV_DT) >= YEAR(CURRENT TIMESTAMP)
AND MONTH(PREV_ELIG_REV_DT) >= MONTH(CURRENT TIMESTAMP)
You could add and extra condition to match the situation when the YEAR is equal..
SELECT *
FROM DUMMY_TABLE
WHERE
YEAR(PREV_ELIG_REV_DT) > YEAR(CURRENT TIMESTAMP)
OR ( YEAR(PREV_ELIG_REV_DT) = YEAR(CURRENT TIMESTAMP)
AND MONTH(PREV_ELIG_REV_DT) >= MONTH(CURRENT TIMESTAMP))
UPDATE
As #Clockwork-Muse said, an alternative approach that may yield better performance would be to get the beginning of the current month and compare against that:
SELECT *
FROM DUMMY_TABLE
WHERE
PREV_ELIG_REV_DT >= (CURRENT DATE - (DAY(CURRENT DATE)-1) DAYS)
try this
SELECT * FROM DUMMY_TABLE
WHERE
YEAR(PREV_ELIG_REV_DT)*100 + MONTH(PREV_ELIG_REV_DT)
>= YEAR(CURRENT TIMESTAMP) * 100 + MONTH(CURRENT TIMESTAMP)