I have the below data set:
x
NAME 2012 2013 2014 2015 2016 2017 2018 2019
JOHN 180 185 192 205 199 198 193 null
MIKE 190 191 191 195 195 null 195 195
Currently i have the below query:
SELECT
GREATEST(COALESCE("2019", 0),
COALESCE("2018", 0),
COALESCE("2017", 0),
COALESCE("2016", 0),
COALESCE("2015", 0),
COALESCE("2014", 0),
COALESCE("2013", 0),
COALESCE("2012", 0)) AS max_weight
, LEAST (COALESCE("2019", 0),
COALESCE("2018", 0),
COALESCE("2017", 0),
COALESCE("2016", 0),
COALESCE("2015", 0),
COALESCE("2014", 0),
COALESCE("2013", 0),
COALESCE("2012", 0)) AS max_weight
, PERSON_NAME
FROM yourTable;
Is there a way to alter te above query so that it asks for the desired year, uses that as an input parameter and only grabs data for that partciular year + the 5 years prior?
So for example: If i inputed 2017 , it would return the following result:
PERSON_NAME MIN_WEIGHT MAX_WEIGHT
JOHN 185 205
MIKE 190 195
Is there any way to do this? (similar to a parameter in a function / stored procedure)? I was thinking of substituting the year #s with some sort of parameter and inputting that …
Thanks in advance.
Advertisement
Answer
You can UNPIVOT
your columns into rows, so that you can apply aggregates like MAX
on them.
Like so,
with test_data (NAME, "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019" ) AS (
SELECT 'JOHN', 180, 185, 192, 205, 199, 198, 193, null FROM DUAL UNION ALL
SELECT 'MIKE', 190, 191, 191, 195, 195, null, 195, 195 FROM DUAL )
SELECT *
FROM test_data
UNPIVOT (
weight FOR year IN ("2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019")
);
+------+------+--------+
| NAME | YEAR | WEIGHT |
+------+------+--------+
| JOHN | 2012 | 180 |
| JOHN | 2013 | 185 |
| JOHN | 2014 | 192 |
| JOHN | 2015 | 205 |
| JOHN | 2016 | 199 |
| JOHN | 2017 | 198 |
| JOHN | 2018 | 193 |
| MIKE | 2012 | 190 |
| MIKE | 2013 | 191 |
| MIKE | 2014 | 191 |
| MIKE | 2015 | 195 |
| MIKE | 2016 | 195 |
| MIKE | 2018 | 195 |
| MIKE | 2019 | 195 |
+------+------+--------+
Once you have the data unpivoted like that, you can use aggregate functions and GROUP BY
to get the results you’re looking for:
with test_data (NAME, "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019" ) AS (
SELECT 'JOHN', 180, 185, 192, 205, 199, 198, 193, null FROM DUAL UNION ALL
SELECT 'MIKE', 190, 191, 191, 195, 195, null, 195, 195 FROM DUAL )
SELECT name,
min(weight) min_weight,
max(weight) max_weight,
max(year) keep ( dense_rank last order by weight desc, year asc ) min_weight_year,
max(year) keep ( dense_rank first order by weight desc, year asc ) max_weight_year
FROM test_data
UNPIVOT (
weight FOR year IN ("2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019")
)
GROUP BY name;
+------+------------+------------+-----------------+-----------------+
| NAME | MIN_WEIGHT | MAX_WEIGHT | MIN_WEIGHT_YEAR | MAX_WEIGHT_YEAR |
+------+------------+------------+-----------------+-----------------+
| JOHN | 180 | 205 | 2012 | 2015 |
| MIKE | 190 | 195 | 2012 | 2015 |
+------+------------+------------+-----------------+-----------------+