DATEPART function
Syntax:
DATEPART(datepart , date)
This function returns an integer representing the specified datepart of the specified date.
The above list of available values of datepart argument is added by the following
Datepart | Abbreviations |
---|---|
Weekday | dw |
Note that the value returned by the DATEPART function in this case (weekday) depends on the value set by SET DATEFIRST parameter, which sets the first day of the week. Default value is Sunday = 1 if language setting is English.
Let us turn back to above example. Under suggestions that the departure/landing times are measured with an accuracy of one minute, we can define duration of flight in minutes as minimal integer units stored. So, departure time of the trip no.1123 in minutes is
SELECT DATEPART(hh, time_out)*60 + DATEPART(mi, time_out)
FROM Trip
WHERE trip_no = 1123;
[[ column ]] |
---|
[[ value ]] |
SELECT DATEPART(hh, time_in)*60 + DATEPART(mi, time_in)
FROM Trip
WHERE trip_no = 1123;
[[ column ]] |
---|
[[ value ]] |
Now we need to compare whether the landing time exceeds the departure time. If so, we must subtract the second time value from the first time value; otherwise, 1440 minutes (one day = 60*24) need to be added to the remainder.
SELECT CASE
WHEN time_dep >= time_arr
THEN time_arr - time_dep + 1440
ELSE time_arr - time_dep
END dur
FROM (SELECT DATEPART(hh, time_out)*60 + DATEPART(mi, time_out) time_dep,
DATEPART(hh, time_in)*60 + DATEPART(mi, time_in) time_arr
FROM Trip
WHERE trip_no = 1123
) tm;
[[ column ]] |
---|
[[ value ]] |
Here, we use subquery to avoid repetition of cumbersome constructions in the CASE operator. Despite of tedious form, the result is absolute correct in view of above remarks.
Example 7.1.4
Only a date but not a time is stored in the Pass_in_trip table. This is because any trip is executed only once a day. To solve this task, we need to combine the time from the Trip table with the date from the Pass_in_trip table.
SELECT DISTINCT pt.trip_no, DATEADD(mi, DATEPART(hh,time_out)*60 +
DATEPART(mi,time_out), date) [time]
FROM Pass_in_trip pt JOIN
Trip t ON pt.trip_no = t.trip_no
WHERE t.trip_no = 1123;
[[ column ]] |
---|
[[ value ]] |
If you’ll run the above query, the following result will be obtained
Trip_no | Time |
---|---|
1123 | 2003-04-05 16:20:00.000 |
1123 | 2003-04-08 16:20:00.000 |
DISTINCT is used here to eliminate duplicates if any. It should be noted that trip number and day is duplicated in Pass_in_trip table for each passenger of the same trip.
In some cases it is possible to replace DATEPART function with more simple functions. Here they are:
DAY(date) — integer representation of day of the specified date. This function is equivalent to function DATEPART (dd, date).
MONTH(date) — integer representation of month of the specified date. This function is equivalent to function DATEPART (mm, date).
YEAR(date) — integer representation of year of the specified date. This function is equivalent to function DATEPART (yy, date).
Suggested exercises: 43, 75, 110,119,143
MySQL
In the MySQL dialect, each date component can be extracted from a date value with the correspondent function. Suppose we must query the Airport database to get minutes of department time of the flights that departs between 1 and 2 p.m.
Solution 1
select time_out, MINUTE(time_out)
from trip
where HOUR(time_out) = 12;
time_out | min |
---|---|
1900-01-01 12:35:00 | 35 |
1900-01-01 12:00:00 | 0 |
Time components can also be got with the EXTRACT function. In this case the solution can be written in the following form:
Solution 2
select time_out, EXTRACT(MINUTE FROM time_out) AS min
from trip
where EXTRACT(HOUR FROM time_out) = 12;
The EXTRACT function can also return composite components of date and/or time, for example, year and month. Let’s solve the following exercise.
Solution 3
select YEAR(b_datetime) AS y, MONTH(b_datetime) AS m,
EXTRACT(YEAR_MONTH FROM b_datetime) AS ym, count(*) AS qty
from utb
group by EXTRACT(YEAR_MONTH FROM b_datetime);
y | m | ym | qty |
---|---|---|---|
2000 | 1 | 200001 | 1 |
2001 | 1 | 200101 | 1 |
2002 | 1 | 200201 | 1 |
2002 | 6 | 200206 | 1 |
2003 | 1 | 200301 | 69 |
2003 | 2 | 200302 | 7 |
2003 | 3 | 200303 | 2 |
2003 | 4 | 200304 | 2 |
2003 | 5 | 200305 | 2 |
2003 | 6 | 200306 | 2 |
The full list of possible components can be found, for example, here.
Note
It is appropriate to mention here rather free style of MySQL grouping. Columns of a SELECT clause are allowed not to be present in the GROUP BY column list. It is obvious that an implicit aggregate function is supposed to be there, otherwise it would be impossible to interpret the statement unambiguously. I suppose that MIN or MAX functions are used implicitly but I’m not going to make it out here, because this feature contradicts SQL standard.
PostgreSQL
As far as I know, there are no functions like YEAR, MONTH, etc. in PostgreSQL. Still the EXTRACT function exists, and the second solution variant that we’ve written for MySQL is valid for this DBMS too:
select time_out, EXTRACT(MINUTE FROM time_out) AS min
from trip
where EXTRACT(HOUR FROM time_out) = 12;
There is yet a function analogous to the DATEPART of MS SQL. A syntactical difference between them may be demonstrated with the same exercise solution:
select time_out, DATE_PART('MINUTE', time_out) AS min
from trip
where DATE_PART('HOUR', time_out) = 12;
Let’s proceed to the second exercise. Compound components are not supported by the PostgreSQL EXTRACT function, therefore an ordinary grouping by two components, year and month, may be used:
Solution 4
select EXTRACT(YEAR FROM b_datetime) AS y,
EXTRACT(MONTH FROM b_datetime) AS m, count(*) AS qty
from utb
group by EXTRACT(YEAR FROM b_datetime), EXTRACT(MONTH FROM b_datetime);
Nevertheless, a compound time component can be imitated with the TO_CHAR formatting function:
select TO_CHAR(b_datetime, 'YYYYMM') AS ym, count(*) AS qty
from utb
group by TO_CHAR(b_datetime, 'YYYYMM');
The produced result will be analogous to the one of Solution 3 except the first two columns, which, of course, can be added to the output by including their names in the GROUP BY clause like in Solution 4.