I'm trying to set the minutes and seconds to 00 in a date, I use formatdatetime(date, 'Y-MM-dd HH:00:00') and it works fine with normal dates, but trying with formatdatetime('2017-01-01 12:27:27', 'Y-MM-dd HH:00:00') the result is 2016-01-01 12:00:00 instead of 2017-01-01 12:00:00.
Why?
Here is some sample code:
CREATE TABLE test_table (
timestamp DATETIME(3) NOT NULL
);
INSERT INTO test_table
VALUES
('2017-01-01 12:27:27'),
('2017-01-02 12:27:27'),
('2017-01-03 12:27:27');
SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00')
FROM test_table;
Result is:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00')
2016-01-01 12:00:00
2017-01-02 12:00:00
2017-01-03 12:00:00
Why this behaviour?
I tried with H2 1.4.192/JDK 1.7.0_80 and H2 1.4.195/JRE 1.8.0_74.
Output from SELECT timestamp FROM test_table is normal:
TIMESTAMP ▼
2017-01-01 12:27:27.0
2017-01-02 12:27:27.0
2017-01-03 12:27:27.0
EDIT:
I've found the problem, it seems to be the locale:
Output from SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00 z', 'it', 'GMT') FROM test_table:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00 z', 'it')
2016-01-01 12:00:00 CET
2017-01-02 12:00:00 CET
2017-01-03 12:00:00 CET
Output from SELECT FORMATDATETIME(timestamp, 'Y-MM-dd HH:00:00 z', 'en', 'GMT') FROM test_table:
FORMATDATETIME(TIMESTAMP, 'Y-MM-dd HH:00:00 z', 'en')
2017-01-01 12:00:00 CET
2017-01-02 12:00:00 CET
2017-01-03 12:00:00 CET
With it locale it subtract one year at 01/01/2017, while with en locale it doesn't. Can someone explain me why this occurs? Shouldn't locale change only data rapresentation?
Ok issue solved, it was my misunderstanding on date formatting:
H2 uses, as suggested by hendrik in his comment, Java SimpleDateFormat to format dates. Following SimpleDateFormat formats, 'Y' (uppercase) stands for week year (the year to whom the week belongs).
Now 01/01/2017 was a Sunday. In the Italian locale (used on my machine), Sunday is considered the last day of the week (so the week belongs to the past year, 2016), while in the international standard (and in the en locale too), Sunday is the first day of week, then belonging to 2017.
Related
I have this SQL statement to retrieve ONLY the last day of stock quotes. But I am missing the data if the data falls on a non-end of month data.
This is my SQL.
select symbol, trade_date, close_price from soa_pse_stock_quotes_history where symbol = '2GO'
group by symbol, trade_date, close_price
having max(trade_date::date) = (date_trunc('month', trade_date::date) + interval '1 month - 1 day')::date
order by trade_date desc limit 100 ;
I am missing quotes for July and Apr because Jul data is July 29, the last business day of the month. The same for April.
What is the correct SQL to fetch the last quote for each end of the month?
Result:
2GO 2022-08-31 00:00:00 7.28
2GO 2022-06-30 00:00:00 6.82
2GO 2022-05-31 00:00:00 7.1
2GO 2022-03-31 00:00:00 7.31
2GO 2022-02-28 00:00:00 7.5
2GO 2021-12-31 00:00:00 7.61
2GO 2021-09-30 00:00:00 8.14
2GO 2021-08-31 00:00:00 8.06
2GO 2021-06-30 00:00:00 8.48
2GO 2021-05-31 00:00:00 8.34
2GO 2021-04-30 00:00:00 8.4
2GO 2021-03-31 00:00:00 8.5
2GO 2020-09-30 00:00:00 8.42
2GO 2020-06-30 00:00:00 9.63
Create a subquery that finds the max date for a symbol by month using GROUP BY symbol, date_trunc('month', trade_date)). Then join this to the table to get the closing price.
CREATE TABLE stock_table (
symbol varchar,
close_price numeric,
trade_date date
);
INSERT INTO stock_table
VALUES ('2GO', 7.0, '02/26/2022'),
('2GO', 7.1, '02/28/2022'),
('2GO', 7.4, '03/31/2022'),
('2GO', 7.2, '04/28/2022'),
('2GO', 7.3, '04/29/2022');
SELECT
st.symbol,
st.trade_date,
st.close_price
FROM
stock_table AS st
JOIN (
SELECT
symbol,
max(trade_date) AS max_date
FROM
stock_table
WHERE
symbol = '2GO'
GROUP BY
symbol,
date_trunc('month', trade_date)) AS m_date
ON st.symbol = m_date.symbol
AND st.trade_date = m_date.max_date;
symbol | trade_date | close_price
--------+------------+-------------
2GO | 02/28/2022 | 7.1
2GO | 03/31/2022 | 7.4
2GO | 04/29/2022 | 7.3
I have this query:
select to_timestamp('May 11 2022 9:16AM', 'Month DD YYYY HH:MI')
Returns: 2022-05-11 09:16:00.000 -0300
The expression 'Month DD YYYY HH:MI' is the result of some trial and error.
I can't tell if what I have is 'right'? Expected something more like: 2022-05-11 09:16:00
What is ...00.000 -0300 this part?
How can I get a timestamp from May 11 2022 9:16AM?
Per the docs Data Type Formatting Functions to_timestamp:
to_timestamp ( text, text ) → timestamp with time zone
Converts string to time stamp according to the given format. (See also to_timestamp(double precision) in Table 9.32.)
to_timestamp('05 Dec 2000', 'DD Mon YYYY') → 2000-12-05 00:00:00-05
So what you are seeing is a timestamptz value, e.g a timestamp with time zone information. If you want to eliminate the time zone then:
select to_timestamp('May 11 2022 9:16AM', 'Month DD YYYY HH:MI')::timestamp;
to_timestamp
---------------------
2022-05-11 09:16:00
I have a SQL table (postgreSQL/TimescaleDB) with hourly values, eg:
Timestamp Value
...
2021-02-17 13:00:00 2
2021-02-17 14:00:00 4
...
2021-02-18 13:00:00 3
2021-02-18 14:00:00 3
...
I want to get the average values for each hour mapped to today's date in a specific timespan, so something like that:
select avg(value)
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by *hourpart of timestamp*
result today (2021-10-08) should be:
...
Timestamp Value
2021-10-08 13:00:00 2.5
2021-10-08 14:00:00 3.5
...
If I do the same select tomorrow (2021-10-09) result should change to:
...
Timestamp Value
2021-10-09 13:00:00 2.5
2021-10-09 14:00:00 3.5
...
I resolved the problem by myself:
Solution:
SELECT EXTRACT(HOUR FROM table."Timestamp") as hour,
avg(table."Value") as average
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by hour
order by hour;
You have to write your query like this:
select avg(value)
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by substring(TimeStamp,1,10), substring(TimeStamp,11,9)
My fiscal year begins on April 1 and I need to include 1 full year of historical data plus current fiscal year as of today. In DAX this looks like:
DATESBETWEEN(Calendar_Date
,IF(MONTH(TODAY()) < 4
,DATE(YEAR(TODAY())-2, 4, 1)
,DATE(YEAR(TODAY())-1, 4, 1)
)
,DATE(TODAY())
)
I need to create this same range as a filter in a T-SQL query, preferably in the "WHERE" clause, but I am totally new to sql and have been unsuccessful in finding a solution online. Any help from more experienced people would be much appreciated!
If you just want to find these values and use as a where filter this is fairly straightforward date arithmetic, the logic for which you already have in your DAX code:
declare #dates table(d date);
insert into #dates values
('20190101')
,('20190601')
,('20200213')
,('20201011')
,('20190101')
,(getdate())
;
select d
,dateadd(month,3,dateadd(year,datediff(year,0,dateadd(month,-4,d))-1,0)) as TraditionalMethod
,case when month(d) < 4
then datetime2fromparts(year(d)-2,4,1,0,0,0,0,0)
else datetime2fromparts(year(d)-1,4,1,0,0,0,0,0)
end as YourDAXTranslated
from #dates;
Which outputs:
d
TraditionalMethod
YourDAXTranslated
2019-01-01
2017-04-01 00:00:00.000
2017-04-01 00:00:00
2019-06-01
2018-04-01 00:00:00.000
2018-04-01 00:00:00
2020-02-13
2018-04-01 00:00:00.000
2018-04-01 00:00:00
2020-10-11
2019-04-01 00:00:00.000
2019-04-01 00:00:00
2019-01-01
2017-04-01 00:00:00.000
2017-04-01 00:00:00
2021-07-22
2020-04-01 00:00:00.000
2020-04-01 00:00:00
However, I would suggest that you may be better served by creating a Dates Table to which you apply filters and from which you join to your transactional data to return the values you require. In an appropriately configured environment this will make full use of available indexes and should provide very good performance.
A very basic tally table approach to generate such a Dates Table is as follows, which returns all dates and their fiscal year start dates for 2015-01-01 to 2042-05-18:
with t as (select t from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as t(t))
,d as (select dateadd(day,row_number() over (order by (select null))-1,'20150101') as d from t,t t2,t t3,t t4)
select d as DateValue
,case when month(d) < 4
then datetime2fromparts(year(d)-1,4,1,0,0,0,0,0)
else datetime2fromparts(year(d),4,1,0,0,0,0,0)
end as FinancialYearStart
from d
order by DateValue;
I have the time and the values in the data base. I need to calculate for a given month the average during each hour i.e.
YYYY-mm-dd (the day can be omitted)
2021-01-01 00:00:00 value=avg(values from 00:00:00 until 00:59:59 for every day of this month at this hour interval)
2021-01-01 01:00:00 value=avg(values from 01:00:00 until 01:59:59 idem as above)
...
2021-01-01 23:00:00 value=avg(values from 23:00:00 until 23:59:59)
2021-02-01 00:00:00 value=avg(values from 00:00:00 until 00:59:59)
2021-02-01 01:00:00 value=avg(values from 01:00:00 until 01:59:59)
...
2021-02-01 23:00:00 value=avg(values from 23:00:00 until 23:59:59)
...
You can use date_trunc('hour', datestamp) in a GROUP BY statement, something like this.
SELECT DATE_TRUNC('hour', datestamp) hour_beginning, AVG(value) average_value
FROM mytable
WHERE datestamp >= '2021-01-01'
AND datestamp < '2021-02-01'
GROUP BY DATE_TRUNC('hour', datestamp)
ORDER BY DATE_TRUNC('hour', datestamp)
To generalize, in place of DATE_TRUNC you can use any injective function.
You could use
to_char(datestamp, 'YYYY-MM-01 HH24:00:00')
to get one result row per hour for every month in your date range.
SELECT to_char(datestamp, 'YYYY-MM-01 HH24:00:00') hour,
AVG(value) average_value
FROM mytable
GROUP BY to_char(datestamp, 'YYYY-MM-01 HH24:00:00')
ORDER BY to_char(datestamp, 'YYYY-MM-01 HH24:00:00')