Select lines whose date-field is in a given month and year - postgresql

My SQL table looks like this:
id (int) | date (date) | text1 (varchar) | text2 (varchar)
I want to select the lines whose date suits a given month and year, regardless of the day.
Both month and year are given in the select-statement as integers.
So the missing thing is the where-clause. Perhaps extract() is the thing I'm looking for, but I don't know how to use it with the two integers, e.g. 2011 and 02.

You can use extract:
SELECT * FROM yourtable
WHERE EXTRACT(month FROM "date") = 2
AND EXTRACT(year FROM "date") = 2011
But in this case you could also do this:
SELECT * FROM yourtable
WHERE "date" >= '2011-02-01' AND "date" < '2011-03-01'

Related

ORDER BY MIN date

I need to fetch the number of employees per month, having a first work in a selected period. And I have to display only the month when the employee appears for the first time. My request works fine, but I need to order the result by date. Here is my request:
SELECT TO_CHAR(sub.minStartDate,'mm/YYYY') as date,
COUNT(DISTINCT sub.id) AS nombre
FROM (
SELECT MIN(sw.start_date) as minStartDate,
e.id
FROM employee e
INNER JOIN social_work sw ON e.id = sw.employee_id
GROUP BY e.id
HAVING MIN(sw.start_date) BETWEEN '2020-01-01' AND '2022-12-31'
) sub
GROUP BY date
ORDER BY date
And the result:
date | nombre
--------------
04/2021 | 2
05/2020 | 1
Excepted output:
date | nombre
--------------
05/2020 | 1
04/2021 | 2
I've tried to put sub.minStartDate in the ORDER BY clause but then I also have to put it in GROUP BY clause, what gives me this output :
date | nombre
--------------
05/2020 | 1
04/2021 | 1
04/2021 | 1
And it's not what I want.
You're ordering by date, which is the result of the TO_CHAR() function. The TO_CHAR() function returns a text, so your ORDER BY clause results in an alphanumeric sort.
Since you don't want to ORDER BY sub.minStartDate, you could try changing your format to put the least significant variable of the date (in this case, the month) to the right: TO_CHAR(sub.minStartDate, 'YYYY/mm').
If you can't change your format either, then you'll probably have to resort to grouping and ordering by minStartDate:
SELECT
TO_CHAR(sub.minStartDate,'mm/YYYY') as date,
TO_CHAR(sub.minStartDate,'YYYY/mm') sortingDate,
COUNT(DISTINCT sub.id) AS nombre
FROM
-- omitted for simplicity
GROUP BY date, sortingDate
ORDER BY sortingDate

Report - SQL group by week number and year

I have a table temperatures with columns mac_address varchar(255), tm datetime,
temperature float.
I'd like to create a report with 3 parameters: mac_address, week_number and year.
The report should show maximum temperature on certain mac_address in certain week_number (01, ... 50, ...) in certain year. There may be more than 1 rows for certain week_number and year...
The SQL Query for the dataset could be something like
select max(temperature), mac_address, tm
from temperatures
group by mac_address
having mac_address = #mac_address and week_number = #week_number and year = #year
Do you know how to construct the query correctly? Maybe I will need 3 more datasets.
For #mac_address parameter it is easy. I will
select distinct mac_address from temperatures
But how can I do it with #week_number and #year parameters? Is the only option to add the values for dropdown list manually?
The possible result may be:
When the user select from the parameters
mac_address 001, week_number 47 and year 2019
max_temperature | tm
27.8 t1
27.8 t2
27.8 t3
Now it returns 3 rows. Most of the time there will be only one row.
From what I understand from your question, you want to dynamically search by weeknumber, mac_address and year returning the highest temperature for each day matching in that range. A query like the following should do what you are after.
declare #macaddress varchar(255) = '2', #WeekNumber int = 36, #year int = 2019
Select
Date = tm,
Temperature = max(temperature)
from
Temps t
where
year(tm)=#year
and mac_address=#macaddress
and datepart(week,tm) = #WeekNumber
group by
tm
If you want the mac_address included in the results, simply add to the Select and Group By sections.
Here's the SQL fiddle with a test setup.
For a data set to build the year parameter you could use something like this, which will get you 10 years. You can expand as needed:
;WITH years AS (
SELECT YEAR(DATEADD(YY,-5,GETDATE())) AS yr
UNION ALL
SELECT yr + 1
FROM years
WHERE yr < YEAR(DATEADD(YY,5,GETDATE()))
)
SELECT *
FROM years
For the weeks parameter you could hard-code them or use something like:
;WITH weeks AS (
SELECT 1 AS wk
UNION ALL
SELECT wk + 1
FROM weeks
WHERE wk < 52
)
SELECT *
FROM weeks
In your main SQL data set you would want to use something like:
select max(temperature), mac_address, tm
from temperatures
where mac_address = #mac_address
and week_number = #week_number
and year = #year
group by mac_address, tm
Edit: remove tm from the SELECT and GROUP BY
select max(temperature), mac_address
from temperatures
where mac_address = #mac_address
and week_number = #week_number
and year = #year
group by mac_address

How to aggregate/partition window data by dynamic group?

A question like this may have already been asked & answered, but I'm having trouble finding anything (it's tough to know what exactly to search for / how to phrase this).
If I have a table of values by date:
select *
from (values
(date '2018-05-11', 'lorem'),
(date '2018-05-10', 'ipsum'),
(date '2018-05-07', 'dolor'),
(date '2018-05-05', 'hello'),
(date '2018-05-04', 'world'),
(date '2018-04-30', 'foo'),
(date '2018-04-15', 'bar')
) as v(date, name)
order by date desc
How can I aggregate the values by date groups (e.g. "5 days") — grouping dynamically by the first value onwards (e.g. May 11-7, 6-1, Apr 30-26, etc.), not statically (e.g. modulo 5 days)?
Desired result:
min_date | max_date | names
-----------+------------+--------------------
2018-05-07 | 2018-05-11 | lorem, ipsum, dolor
2018-05-04 | 2018-05-05 | hello, world
2018-04-30 | 2018-04-30 | foo
2018-04-15 | 2018-04-15 | bar
————
I believe I need to first derive the max date to group each row under, which would be , e.g. 2018-05-11, 2018-05-05, etc.
I've tried two conceptual approaches for doing that, but neither work.
———
The first approach is to build up this rolling max date, but this isn't valid (column "groupbydate" does not exist):
select *,
case
when date > (lag(groupByDate) over w) - interval '5 days' then (lag(groupByDate) over w)
else date
end as groupByDate
from input
window w as (order by date desc)
————
The second approach is to "find" the max/"group by" for each row, but I'm not sure how to differentiate the current table row's date from the current window row's `date:
select *,
max(date) filter (where date < input.date + interval '5 days') over w
from input
window w as (order by date desc)
I think I can implement the second approach using a subquery, but I'm curious: is it possible to achieve this using window functions? Thank you!
EDIT: The second approach is wrong. It can find a different "group by" date for different dates that should be in the same group.
EDIT: Actually, this is wrong! This can find a different "group by" date for different dates that should be in the same group.
Here's how I achieved this with a subquery:
select date, name, (
select max(date)
from input as i2
where date < input.date + interval '5 days'
) as date_group
from input
And plugging into this outer query gets me my desired results:
select min_date, max_date, names
from (
select date_group, min(date) as min_date, max(date) as max_date, string_agg(name, ', ') as names
from groups -- results of above query, e.g. using CTE
group by date_group
order by date_group desc
) as x
Still curious if there's a way to do this with windowing functions. Thanks!

how to show the months between two dates in db2

I have a table db2admin.shdl_dtl in which there are two columns for the date-
startdate
enddate
from these two date columns I want to show months between two dates
i.e. startdate = '2015-01-05' and enddate = '2015-04-20' then output of the query should come like this-
Output- jan, feb, mar, apr
with cte (diffmonths,monthdiff) as
(select date(startdate ) as diffmonths,0 from sysibm.sysdummy1
union all
select date(diffmonths) + 1 month as diffmonths,month(diffmonths) from cte
where diffmonths<=(date(enddate)) )
select * from cte where MONTHDIFF >0

A table with infinite rows?

I have a table posts:
Column | Type | Modifiers
-------------------+--------------------------+----------------------------------------------------
body | text | not null
from | character varying(2000) | not null
date | timestamp with time zone | not null
and I'd like to count how many rows a user has in one day, one row for every day in a given month.
In oracle I would "generate" a table with as many days the current month has, and then join the "date" column with the "generated" date.
Something like
> select *
2 from (select sysdate + level l from dual connect by level < 10)
3 /
L
----------
2013-06-07
2013-06-08
2013-06-09
2013-06-10
2013-06-11
2013-06-12
2013-06-13
2013-06-14
2013-06-15
9 rows selected.
Is there something similar in postgres?
http://diethardsteiner.blogspot.com/2012/03/postgresql-auto-generating-sample.html
I found this with just one google hit. U might try using it.
Incase the author removes or web page gets wiped out.
WITH date_series AS (
SELECT
DATE(GENERATE_SERIES(DATE '2012-01-01', DATE '2012-01-10','1 day')) AS generateddate
)
SELECT
generateddate
, EXTRACT(DAY FROM generateddate) AS day
, EXTRACT(MONTH FROM generateddate) AS month
, EXTRACT(QUARTER FROM generateddate) AS quarter
, EXTRACT(YEAR FROM generateddate) AS year
FROM
date_series;