I have the following scenario:
There is a table that contains data loaded weekly and last day of the month for each customer and product.
I need to get the data sum for the data loaded on the last day of the month for each product (let's say) - that consolidates it for all the customers.
Input is 2 dates - start and end of the period and I need to get this done in a single SQL query.
Below is the query that I am using. Period is a datetime field.
SELECT
Period
,sum([Amount]) as 'Amount'
from tableA
where Period between convert(datetime,'201110'+'01',121) and dateadd(second,-1,dateadd(month,1,convert(datetime,'201201'+'01',121)))
and cond1 = .....
and cond2 = ....
group by
Period
The query above results in data as shown below.
I need to find out the amount on the last day of each month, i.e. one for 31-Oct-11, 30-Nov-11, 31-Dec-11 and so on.
The final result should look as below (as opposed to what I am getting currently - above):
Can you please help !!
If you just want the values for the last day of each month in the period I think adding a condition like this should work:
AND Period = DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))
The query would look something like this:
SELECT
Period,
SUM([Amount]) AS 'Amount'
FROM tableA
WHERE Period BETWEEN CONVERT(DATETIME,'201110'+'01',121) AND DATEADD(SECOND,-1,DATEADD(MONTH,1,CONVERT(DATETIME,'201201'+'01',121)))
AND Period = DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))
AND cond1 = .....
AND cond2 = ....
GROUP BY Period
If your period datetime has a time value you will have to remove that part to get the match with the last day date that the condition provides like this:
AND DATEADD(dd, DATEDIFF(dd, 0, Period), 0) =
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))
Related
dateadd(mm, DATEPART(MONTH, DATE) - 1, 0) + DATEPART(DAY, DATE) - 1
OUTPUT date is in the year for example 1990-12-02 00:00:00:000
Full query is below:
SELECT dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0) + dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0) + DATEPART(DAY, GP_DATE) - 1 GP_DATE
from table
I am trying to convert this query into snowflake syntax and snowflake syntax dateadd function does not allow 1, 0.
In SQL Server, there are some rather ugly implicit conversions available between datetimes and integers.
0, when converted to a date, becomes 1900-01-01.
You're also allowed to do maths on dates. Adding or subtracting 1 adds or subtracts 1 day from the date. Putting these facts together, we have:
dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0)
Which is taking the current year, and subtracting 1900 from it (or 1899 if the month is less than 11, for whatever reason). We then take that number and add it back to the date 0 (which as stated above is 1900-01-01). The result is that we get the first of January of next year or this year, depending on the month of GP_DATE. Call this D1.
Moving on:
dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0)
is taking the month of GP_DATE, subtracting 1 from it and adding that number of months to the date 0 (1900-01-01). The result is a the 1st of whichever month GP_DATE is in, but in 1900. Let's call this D2.
When we add D1 and D2 together, we approximately get a date of the 1st of whichever month GP_DATE is in, in either this year or next year. Note, however, that this goes wrong if the D1 year is a leap year, we get it wrong by a day for months after February.
Finally, we take DATEPART(DAY, GP_DATE) - 1, where we take the day of the month from GP_DATE, subtract 1, and add that on to our result so far. This should set the final date to be on the same day of the month as GP_DATE, except for the error mentioned above.
So, it appears that the code is trying to take GP_DATE and get the same date in either this year or next year, depending on how late in the year GP_DATE is. However, it also appears it was never tested with consideration for leap years.
A far more likely correct version of this query would be this instead:
SELECT
DATEADD(year,
DATEDIFF(year,GP_DATE,CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(month,GP_DATE)>10 THEN 0 ELSE 1 END
,GP_DATE)
i want to retrieve records where a date field is set to future months
does this look correct
Select * from table1 WHERE
datesetto >MONTH(dateadd(dd, -1, GetDate())))
select * from tablename where month(columndate)>month(getdate()) and
year(columndate)>=year(getdate())
SELECT * FROM table1
WHERE datesetto >= DATEADD(month, DATEDIFF(month, 0, getdate())+1, 0)
Explanation:
DATEDIFF(month, 0, getdate()) calculates how many months have passed since 1900-01-01.
DATEADD(month, DATEDIFF(month, 0, getdate()), 0) returns the beginning of this month.
DATEADD(month, DATEDIFF(month, 0, getdate())+1, 0) returns the beginning of next month.
Try this:
Select * from table1 WHERE
((DATEPART(MONTH,datesetto) > DATEPART(MONTH,GETDATE())
AND DATEPART(YEAR,datesetto) = DATEPART(YEAR,GETDATE()))
OR (DATEPART(YEAR,datesetto) > DATEPART(YEAR,GETDATE())))
DATEPART(Month,GETDATE()) will give the month of the current date and then you can compare it with the datesetto
Update: The above query will give data for any months greater than the current month and any month greater in the year than the current year.
I have a table similar to one below. I'm trying to select only the rows where the Start Date is in the current month. Here is what I have so far, but it's not working.
SELECT *
FROM TABLE1
WHERE StartDate = MONTH(getdate())
How can I select only the values where the start date is in the current month?
Use this construct to avoid functions on the StartDate columns (like MONTH or YEAR). These functions will prevent any index or statistics being used/
SELECT *
FROM TABLE1
WHERE
StartDate >= DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
AND StartDate < DATEADD(month, 1+DATEDIFF(month, 0, GETDATE()), 0)
Any answer that puts a function on StartDate will not scale as expected. See error number 2 here. The filter is now non-sargable, and index/statistics can't be used. Every row will be looked at for a table scan.
You need to check the month of both fields
WHERE MONTH(startdate) = MONTH(getdate())
I'm hoping to count orders per hour for every day in the last month.
I have this WHERE clause from another report (1), which determines the correct month 'last month' from the point it is run.
I'd like to ideally have hours as my 'leftmost' column, rather than the date.
I thought I could get distinct days within the WHERE and then count datepart where hour = 1, 2 etc. However, this code below (2) leads to over 300 records.
(1)
WHERE YEAR(Bookings.PICKUP_DATE)
= YEAR(DATEADD(mm, -1, DATEADD(m, DATEDIFF(m, 0, getdate()), 0)))
AND MONTH(Bookings.PICKUP_DATE)
= MONTH(DATEADD(mm, -1, DATEADD(m, DATEDIFF(m, 0, getdate()), 0)))
(2)
select
distinct(datepart(dd,b.pickup_date)) as DAYOFTHEMONTH
,COUNT(CASE WHEN DATEPART(HH,B.PICKUP_DATE) = 1 THEN 1 ELSE 0 END)
Apologies for not being clear before. I've worked this out now.
The reason I had too many records was simply that my GROUP BY clause did not have the DAY function applied.
My dataset is now correct and I get all days in the date range with:
distinct(datepart(dd,timestamp)) as DAYOFTHEMONTH
The count of orders for an hour (In this case midnight) is:
count(case when datepart(hh,timestamp) = 0 then timestamp else null end) as '00:00'
My WHERE clause is giving all data for the month before the present one:
WHERE
YEAR(timestamp) = YEAR(DATEADD(mm,-1,DATEADD(m,DATEDIFF(m,0,getdate()),0)))
AND
MONTH(timestamp) = MONTH(DATEADD(mm,-1,DATEADD(m,DATEDIFF(m,0,getdate()),0)))
Lastly, I get the correct grouping with DAY applied to the GROUP BY
GROUP BY day(timestamp)
Sorry to have been unclear. Hope this will prove useful to somebody out there in the future.
Thanks for the edit/help too guys, I'll ensure any other questions I ask are correct:)
I have a table of invoices that looks like this:
InvoiceDate InvoiceNumber PaidDate PayStatus Amount
-----------------------------------------------------------
2012-1-23 1234 2012-02-28 Unpaid 1234
2012-2-01 2345 2012-03-12 Paid 23456
I need to GROUP these by (and take their monthly sums) certainly conditions.
I came up with a WHERE CLAUSE for only the current month. The logic is like this.
only extract invoices with invoice dates less than or equal to the last day of the previous month
the 'lateness' should not exceed 90 days (lateness = diff(Period - (InvoiceDt + Terms)))
take either unpaid PayStatus OR if it's marked as paid, ActualPaymentdt should be greater than or equal to the last day of the previous month
if the day component of invoice date equals 1 AND it belongs to acct 4300, exclude it
This is only for the current month (which reports on the last day of the prev month). I'm at a loss at how to do it for ALL MONTHS in the invoice table.
-- only extract invoices with invoice dates less than or equal to the last day of the previous month
AND b.InvoiceDt <= DATEADD(dd, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
-- the 'lateness' should not exceed 90 days (lateness = diff(Period - (InvoiceDt + Terms)))
AND DATEDIFF(day, DATEADD(day, ISNULL(b.Term, 0), b.InvoiceDt), DATEADD(dd, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))) <= 90
-- take either unpaid PayStatus OR if it's marked as paid, ActualPaymentdt should be greater than or equal to the last day of the previous month
AND (b.PayStatus = 'Unpaid' OR b.ActualPaymentDt >= DATEADD(dd, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)))
-- if the day component of invoice date equals 1 AND it belongs to acct 4300, exclude it
AND NOT (b.AccountNumber = 4300 AND DAY(b.InvoiceDt) = 1)
Join on another derived table that contains all months in the invoices table:
CROSS JOIN (SELECT DISTINCT DATEADD(MONTH, DATEDIFF(MONTH, 0, InvoiceDt), 0) as InvoiceMonth
FROM invoices) m
Then substitute GETDATE() with m.InvoiceMonth.
And don't forget to GROUP BY m.InvoiceMonth as well.