Using Least with DatePart? - sql

I'm running a query during the month of august, but I want to convert it to a date_part function.
Here's the original query.
SELECT avg(CASE WHEN date = LEAST(current_date-1,'8/31/14') THEN bo ELSE NULL END) end_bo
From <table>
What I'm trying to do, is plug LEAST into the one below.
SELECT avg(CASE WHEN date_part('month', date) = 8 and date_part('year', date) = 2014 THEN bo ELSE NULL END) end_bo
From <table>
The problem is, I don't see where I can plug it in.

The first one looks to see which of those dates are earlier, currentdate or Aug 31 2014, if it is equal to date it returns bo.
While the second one tests to see if the current month is aug 2014 and returns bo.
To apply the same logic to the second query, it might look like this:
SELECT avg(CASE
WHEN least(date_part('month', currentdate), 8) = date_part('month', date)
and date_part('year', date) = 2014
THEN bo
ELSE NULL
END) end_bo
This would look at the current month, find if it was lower than 8, compare it with date month, if equal return bo.
LEAST simply returns the lowest number in a list. So least(9,8) (sept, aug) would return 8.

Related

Converting rows to columns in postgresql

i need to convert rows into columns using postgrsql
need resulSet as follows
monthname 2017 year(amount) 2018 year(amount)
Jan 10 250
feb 20 350
mar 40 100
below is my Query using crosstab function
SELECT *
FROM crosstab(
$$select
SUM(standard_loan_account_balance) as TOTAL_AMOUNT
,extract (year from mgc.transaction_date) as monthname
,extract(MONTH from mgc.transaction_date) as monthnumber
from bankfair.tbl_das_monthly_growth_chart mgc
where mgc.transaction_date
between (select (SELECT APP.app_today_date FROM bankfair.tbl_cmn_application_date app)+'-12 month'::interval)
and (SELECT APP.app_today_date FROM bankfair.tbl_cmn_application_date app) group by monthnumber,monthname
order by 1,2
$$
) as ct ("TOTAL_AMOUNT" numeric,"monthnumber" double precision,"monthname" double precision)
i didnt get expected output
I would start with a simple non-crosstab version of the query. This should do what you want:
select to_char(mgc.transaction_date, 'Month') as monthname,
sum(case when to_char(mgc.transaction_date, 'YYYY') = '2017'
then standard_loan_account_balance else 0
end) as slab_2017,
sum(case when to_char(mgc.transaction_date, 'YYYY') = '2018'
then standard_loan_account_balance else 0
end) as slab_2018
from bankfair.tbl_das_monthly_growth_chart mgc
group by monthname, extract(month from mgc.transaction_date)
order by monh(mgc.transaction_date);
You can then convert this to a crosstab version, if you need to.
In your desired resultset, the columns are
monthname 2017 year(amount) 2018 year(amount)
But in the AS clause that qualifies the result of the crosstab() call, you have put this, which seems to correspond to your non-pivoted columns:
as ct ("TOTAL_AMOUNT" numeric,"monthnumber" double precision,"monthname" double precision)
That's wrong, because the AS clause should designate exactly the pivoted-output columns. It seems that you did not understand this aspect of crosstab(), as you put the columns of the non-pivoted output.
The columns in the query passed as the first argument of crosstab also don't match. The first column needs to be the month's name, the second column the year, and the third column the amount. Finally, you need to limit the years to the ones that are hardcoded in your AS clause.

SQL Over partition by

I basically have a case statement that displays the sum of profit and a month to date total for each person. My idea is i want to display a daily figure of that person as well as their whole month total altogether.
My issue is when i limit results to just yesterday (supposed to be a daily figure) this then effects the calculation of the month value (just calculates the sum for that day rather than the whole month).
This is because the total month values are all out of the scope of the query. Is there anyway to calculate the whole month value for each person correctly without having the limits of where effecting the result.
e.g.
The result:
08/09/17: 25
09/09/17: 25
10/09/17: 25
11/09/17: 25 <<<< but only display one day and month total
Overall Month total: 100
Can this also includes nulls too? I think im almost looking at a dynamically stored month to date value that isn't effected by where clauses.
SELECT SUM(Figure) AS 'Daily Figure',
CASE WHEN
MONTH([DATE]) = MONTH(getdate()) AND
YEAR([DATE]) = YEAR(getdate())
THEN
SUM(Figure)
OVER (PARTITION BY [Name],
MONTH([DATE]))
ELSE 0 END
as [Month To Date Total]
WHERE
dateadd(day,datediff(day,1,GETDATE()),0)
If you want month-to-date and the current amount, then use conditional aggregation:
SELECT NAME,
SUM(CASE WHEN DAY(DATE) = DAY(GETDATE()) - 1 THEN Figure ELSE 0 END) AS DailyFigure,
SUM(Figure) as MonthToDate
WHERE MONTH([DATE]) = MONTH(getdate()) AND
YEAR([DATE]) = YEAR(getdate())
GROUP BY NAME;
This works on all but the first day of the month.

Select query for filtering data from particular range of year and month

I want to display data from user selected year of March to next year of April(ex:if user selected 2017, then need to select data from from 2017 march to april 2018 ). What is the best query for filtering it. It should be order by from selected year.
SELECT DATEPART(mm,submitted_date),SUM(total_count),YEAR(submitted_date)
FROM store_details
WHERE YEAR(submitted_date) = '2017'
AND MONTH(submitted_date) >=3
Group By YEAR(submitted_date),DATEPART(mm,submitted_date)
Order By YEAR(submitted_date),DATEPART(mm,submitted_date)
Well, later versions (2012+) of SQL Server have a nice built in function called datefromparts. However, since your question is tagged with sql-server-2005 this doesn't help so much unless you can upgrade your database (and you really should think about it, since 2005 is no longer supported by Microsoft).
However, since you know you want all the data between March and April of next year, you can simply do this:
SELECT DATEPART(MONTH,submitted_date),SUM(total_count),YEAR(submitted_date)
FROM store_details
WHERE submitted_date >= CAST(CAST(#Year as char(4)) + '-03-01 00:00:00' As datetime)
WHERE submitted_date < CAST(CAST(#Year + 1 as char(4)) + '-04-01 00:00:00' As datetime)
Group By YEAR(submitted_date),DATEPART(MONTH,submitted_date)
Order By YEAR(submitted_date),DATEPART(MONTH,submitted_date)
(That is, assuming the user provides the year as an int value.)
If you already have the starting month and date in hand, then I don't see why you can't just add an upper bound to the date in your WHERE clause:
SELECT
DATEPART(mm, submitted_date),
SUM(total_count),
YEAR(submitted_date)
FROM store_details
WHERE
(YEAR(submitted_date) = '2017' AND MONTH(submitted_date) >= 3) AND
(YEAR(submitted_date) = '2018' AND MONTH(submitted_date) < 4)
GROUP BY
YEAR(submitted_date),
DATEPART(mm, submitted_date)
ORDER BY
YEAR(submitted_date),
DATEPART(mm, submitted_date)

SQL Server / SSRS: Calculating monthly average based on grouping and historical values

I need to calculate an average based on historical data for a graph in SSRS:
Current Month
Previous Month
2 Months ago
6 Months ago
This query returns the average for each month:
SELECT
avg_val1, month, year
FROM
(SELECT
(sum_val1 / count) as avg_val1, month, year
FROM
(SELECT
SUM(val1) AS sum_val1, SUM(count) AS count, month, year
FROM
(SELECT
COUNT(val1) AS count, SUM(val1) AS val1,
MONTH([SnapshotDate]) AS month,
YEAR([SnapshotDate]) AS year
FROM
[DC].[dbo].[KPI_Values]
WHERE
[SnapshotKey] = 'Some text here'
AND No = '001'
AND Channel = '999'
GROUP BY
[SnapshotDate]) AS sub3
GROUP BY
month, year, count) AS sub2
GROUP BY sum_val1, count, month, year) AS sub1
ORDER BY
year, month ASC
When I add the following WHERE clause I get the average for March (2 months ago):
WHERE month = MONTH(GETDATE())-2
AND year = YEAR(GETDATE())
Now the problem is when I want to retrieve data from 6 months ago; MONTH(GETDATE()) - 6 will output -1 instead of 12. I also have an issue with the fact that the year changes to 2016 and I am a bit unsure of how to implement the logic in my query.
I think I might be going about this wrong... Any suggestions?
Subtract the months from the date using the DATEADD function before you do your comparison. Ex:
WHERE SnapshotDate BETWEEN DATEADD(month, -6, GETDATE()) AND GETDATE()
MONTH(GETDATE()) returns an int so you can go to 0 or negative values. you need a user scalar function managing this, adding 12 when <= 0

Find previous equivalent dates over the past two calender years

If today is say 15th August 2012 then the query should return the following
15/01/2011,
15/02/2011,
...
...
15/07/2012
15/08/2012
If today is 31st August 2012 then the query would return
31/01/2011,
28/02/2011, <<<<this is the nearest date
...
...
31/07/2012
31/08/2012
We have a vw_DimDate in our Warehouse which should help
edit
It contains the following fields
Currently I'm using the following but it seems rather convoluted! ...
DECLARE #Dt DATETIME = '31 JUL 2012'--GETDATE()
;WITH DateSet_cte(DayMarker)
AS
(
SELECT DayMarker
FROM WHData.dbo.vw_DimDate
WHERE
DayMarker >= CONVERT(DATETIME,CONVERT(CHAR(4),DATEADD(YEAR,-1,#Dt),112) + '0101') AND
DayMarker <=#Dt
)
, MaxDate_cte(MaxDate)
AS
(
SELECT [MaxDate] = MAX(DayMarker)
FROM DateSet_cte
)
SELECT
[Mth] = CONVERT(DATETIME,CONVERT(CHAR(6),a.DayMarker,112) + '01')
, MAX(a.DayMarker) [EquivDate]
FROM DateSet_cte a
WHERE DAY(a.DayMarker) <= (SELECT DAY([MaxDate]) FROM MaxDate_cte)
GROUP BY CONVERT(DATETIME,CONVERT(CHAR(6),a.DayMarker,112) + '01')
;with Numbers as (
select distinct number from master..spt_values where number between 0 and 23
), Today as (
select CONVERT(date,CURRENT_TIMESTAMP) as d
)
select
DATEADD(month,-number,d)
from
Numbers,Today
where DATEPART(year,DATEADD(month,-number,d)) >= DATEPART(year,d) - 1
Seems odd to want a variable number of returned values based on how far through the year we are, but that's what I've implemented.
When you use DATEADD to add months to a value, then it automatically adjusts the day number if it would have produced an out of range date (e.g. 31st February), such that it's the last day of the month. Or, as the documentation puts it:
If datepart is month and the date month has more days than the return month and the date day does not exist in the return month, the last day of the return month is returned.
Of course, if you already have a numbers table in your database, you can eliminate the first CTE. You mentioned that you "have a vw_DimDate in our Warehouse which should help", but since I have no idea on what that (presumably, a) view contains, it wasn't any help.