Formatting Variable as Date (mm/dd) - vba

I am trying to create a script that identifies the date range of the previous month (Cell G9 is today's date). It is working; however, the output is formatting the date much differently than I am intending. The [J36] output is "01/08" when it should be "08/01" and the [J37] output is "6:11:37 AM" (interpretting it as a time), when it should be "08/31". I am only coding for the output in particular cells because I want to see that it is working. However, it is the variable I want to format, not the cell. I'm going to be using the startdate and enddate variable in future code and those variables on their own won't be visable in any cells.
I attempted to use the format(startdate,mm/dd), but I got an overflow error.
Here is my script:
Dim thismonth As Integer
thismonth = Month(Sheet1.[G9])
Dim startdate As Date
Dim enddate As Date
Select Case thismonth
Case 1
startdate = 12 / 1
enddate = 12 / 31
Case 2
startdate = 1 / 1
enddate = 1 / 31
Case 3
startdate = 2 / 1
enddate = 2 / 28
Case 4
startdate = 3 / 1
enddate = 3 / 31
Case 5
startdate = 4 / 1
enddate = 4 / 30
Case 6
startdate = 5 / 1
enddate = 5 / 31
Case 7
startdate = 6 / 1
enddate = 6 / 30
Case 8
startdate = 7 / 1
enddate = 7 / 31
Case 9
startdate = 8 / 1
enddate = 8 / 31
Case 10
startdate = 9 / 1
enddate = 9 / 31
Case 11
startdate = 10 / 1
enddate = 10 / 31
Case 12
startdate = 11 / 1
enddate = 11 / 30
End Select
Sheet1.[J36] = startdate
Sheet1.[J37] = enddate

How about a much simpler solution:
Dim startDate as Date
Dim endDate as Date
startDate = Application.WorksheetFunction.EOMONTH(Sheet1.[G9],-2) + 1
endDate = Application.WorksheetFunction.EOMONTH(Sheet1.[G9],-1)
You can get rid of VBA altogether and write this worksheet formula directly in J36 and J37 respectively.
J36: =EOMONTH(G9,-2)+1
J37: =EOMONTH(G9,-1)

Related

Case statement giving both values (the one in "then" and in "else" together) in Bigquery. What is wrong?

I want to create a flag in Bigquery which will return 1 when true and 0 when false. The statement works fine when it has to return the "else" value which is 0. However, when it satisfies the condition, it returns two rows with both 1 and 0 in them. Why is this happening?
Below is the code used:
table AS(
SELECT
id,
month,
ROUND((text/(month_days/7)), 2) AS value
FROM (SELECT id, extract(month FROM date) AS month,
(32 - EXTRACT(DAY FROM DATE_ADD(DATE_TRUNC(DATE(date), MONTH), INTERVAL 31 DAY))) AS month_days,
sum(text_sent) AS text
FROM table1
WHERE date BETWEEN '2020-01-01 00:00:00 UTC' AND '2020-06-30 00:00:00 UTC'
GROUP BY 1,2,3)),
table_flag AS(
SELECT
id,
CASE
WHEN month = 1 AND value > 100 THEN 1
WHEN month = 2 AND value > 150 THEN 1
WHEN month = 3 AND value > 130 THEN 1
WHEN month = 4 AND value > 200 THEN 1
WHEN month = 5 AND value > 235 THEN 1
WHEN month = 6 AND value > 125 THEN 1
WHEN month = 7 AND value > 324 THEN 1
WHEN month = 8 AND value > 160 THEN 1
WHEN month = 9 AND value > 350 THEN 1
WHEN month = 10 AND value > 80 THEN 1
WHEN month = 11 AND value > 245 THEN 1
ELSE 0
END AS value_flag
FROM
table)
SELECT
t.id,
t.value,
t.month,
tf.value_flag
FROM
table t
LEFT JOIN
table_flag tf
ON
t.id = tf.id
WHERE t.id IS NOT NULL
GROUP BY 1,2,3,4
ORDER BY 1
I have also tried nested IF, but that doesn't work either:
SELECT DISTINCT(id),
(IF((month = 1 AND value > 100), 1,
(IF((month = 2 AND value > 150), 1,
(IF((month = 3 AND value > 130), 1,
(IF((month = 4 AND value > 200), 1,
(IF((month = 5 AND value > 235), 1,
(IF((month = 6 AND value > 125), 1,
(IF((month = 7 AND value > 324), 1,
(IF((month = 8 AND value > 160), 1,
(IF((month = 9 AND value > 350), 1,
(IF((month = 10 AND value > 80), 1,
(IF((month = 11 AND value > 245), 1,0))))))))))))))))))))))
AS value_flag
FROM table)
This is how the output looks right now (This is NOT what I want):
enter image description here
The output is completely wrong. Please suggest alternate method (if any) to do it.
P.S.: This is my first question here, please let me know if any other information is needed. Thanks in advance for the help!
Both table and table_flag has several rows with identical id. BigQuery for each row in table finds several rows in table_flag. To remove duplicates we could add month to table_flag and to the ON clause. But we actually do not need the last LEFT JOIN. Try this:
WITH table AS(
SELECT
id,
month,
ROUND((text/(month_days/7)), 2) AS value
FROM (
SELECT
id,
extract(month FROM date) AS month,
(32 - EXTRACT(DAY FROM DATE_ADD(DATE_TRUNC(DATE(date), MONTH), INTERVAL 31 DAY))) AS month_days,
sum(text_sent) AS text
FROM table1
WHERE
date BETWEEN '2020-01-01 00:00:00 UTC' AND '2020-06-30 00:00:00 UTC'
AND id IS NOT NULL
GROUP BY 1,2,3
)
)
SELECT
id,
value,
month,
CASE
WHEN month = 1 AND value > 100 THEN 1
WHEN month = 2 AND value > 150 THEN 1
WHEN month = 3 AND value > 130 THEN 1
WHEN month = 4 AND value > 200 THEN 1
WHEN month = 5 AND value > 235 THEN 1
WHEN month = 6 AND value > 125 THEN 1
WHEN month = 7 AND value > 324 THEN 1
WHEN month = 8 AND value > 160 THEN 1
WHEN month = 9 AND value > 350 THEN 1
WHEN month = 10 AND value > 80 THEN 1
WHEN month = 11 AND value > 245 THEN 1
ELSE 0
END AS value_flag
FROM table
ORDER BY 1
or this:
SELECT
id,
month,
ROUND((text/(month_days/7)), 2) AS value,
CASE
WHEN month = 1 AND ROUND((text/(month_days/7)), 2) > 100 THEN 1
WHEN month = 2 AND ROUND((text/(month_days/7)), 2) > 150 THEN 1
WHEN month = 3 AND ROUND((text/(month_days/7)), 2) > 130 THEN 1
WHEN month = 4 AND ROUND((text/(month_days/7)), 2) > 200 THEN 1
WHEN month = 5 AND ROUND((text/(month_days/7)), 2) > 235 THEN 1
WHEN month = 6 AND ROUND((text/(month_days/7)), 2) > 125 THEN 1
WHEN month = 7 AND ROUND((text/(month_days/7)), 2) > 324 THEN 1
WHEN month = 8 AND ROUND((text/(month_days/7)), 2) > 160 THEN 1
WHEN month = 9 AND ROUND((text/(month_days/7)), 2) > 350 THEN 1
WHEN month = 10 AND ROUND((text/(month_days/7)), 2) > 80 THEN 1
WHEN month = 11 AND ROUND((text/(month_days/7)), 2) > 245 THEN 1
ELSE 0
END AS value_flag
FROM (
SELECT
id,
extract(month FROM date) AS month,
(32 - EXTRACT(DAY FROM DATE_ADD(DATE_TRUNC(DATE(date), MONTH), INTERVAL 31 DAY))) AS month_days,
sum(text_sent) AS text
FROM table1
WHERE
date BETWEEN '2020-01-01 00:00:00 UTC' AND '2020-06-30 00:00:00 UTC'
AND id IS NOT NULL
GROUP BY 1,2,3
)
ORDER BY 1

Selecting a row based on a field value on the 1st of the month in SQL

In the below table I want to select a row where "Days" = 1 but the account should have Days = 0 on the 1st of the month.
Account| Date | Days
-------|------|-----
A | 1/3/2015 | 0
A | 5/3/2015 | 1
A | 9/3/2015 | 10
B | 1/3/2015 | 30
B | 3/3/2015 | 1
B | 6/3/2015 | 12
The result should be 2nd row
A 5/3/2015 1
On the 1st A has 0 days but B has 30 days hence I want only account A
This code is for ORACLE, but take a look. Idea is:
SELECT *
FROM ACCOUNTS
WHERE DAYS = 1
AND ACC IN (SELECT ACCOUNT
FROM ACCOUNTS
WHERE ACC_DATE = TRUNC (ACC_DATE, 'MONTH') AND DAYS = 0)
Try to convert to MSSQL and run.
Try this using window function max with case to find out if there is a row with day = 1 and Days = 0 and if there is, return second row using row_number in the order of increasing date for that account in that month.
select *
from (
select
t.*,
max(case when day(date) = 1 and Days = 0 then 1 end)
over (partition by Account, month(Date), year(Date)) flag,
row_number() over (
partition by Account, month(Date), year(Date)
order by Date
) rn
from your_table t
) t where flag = 1 and rn = 2
You could try this:
SELECT account, date, days
FROM table_name t
WHERE days = 1
AND EXISTS (SELECT 1
FROM table_name
WHERE account = t.account
AND date = DATEADD(month, DATEDIFF(month, 0, t.date), 0)
--cast(date As Date) = DATEADD(month, DATEDIFF(month, 0, t.date), 0)
AND days = 0);

Extract quarters from time

Is is possible to breakdown hour into quarters and extract them?
For example:
7:00-7:15 = 1
7:15-7:30 = 2
etc
I have time column with values such as 09:30
and I want to extract:
hour = 6
quarter = 2
I can take out the hour, but how do I take out the quarter.
Use the datepart function:
select
case
when TimeColumn is null then null
when datepart(minute, TimeColumn) < 15 then 1
when datepart(minute, TimeColumn) < 30 then 2
when datepart(minute, TimeColumn) < 45 then 3
else 4
end
from MyTable

Number of months between 2 dates

I am trying to create a formula or VBA function which calculates the number of months between two dates, according to this rule: if the start date is the 15th of the month or before, or the end date is after the 15th of the month, then that month counts.
For example:
Start Date End Date Output
---------- --------- --------
1/5/2014 2/16/2014 2 months
1/17/2014 2/16/2014 1 month
1/16/2014 2/5/2014 0 months
I have already tried =DATEDIF(A2, B2, "M") + IF( DATEDIF(A2, B2, "MD")>=15, 1, 0) but this only adds a month if the distance between the days in 2 dates is over 15. For example if the start date is 5/14/13-8/16/13 it will say that there are 3 months in between these dates. However, the actual distance between these 2 dates should be 4 months according to the conditions that I specified above.
Ho do I fix this formula?
Here is a vba solution as well
Function date_diff_to_months(date1 As Date, date2 As Date) As Integer
Dim y1 As Integer
Dim y2 As Integer
Dim d1 As Integer
Dim d2 As Integer
Dim m1 As Integer
Dim m2 As Integer
Dim m_diff As Integer
Dim y_diff As Integer
Dim month_adjustment As Integer
y1 = Year(date1)
y2 = Year(date2)
m1 = Month(date1)
m2 = Month(date2)
d1 = Day(date1)
d2 = Day(date2)
m_diff = m2 - m1
y_diff = (y2 - y1) * 12
If (m_diff > 0 Or y_diff > 0) Then
If (d1 <= 15 And d2 >= 15) Then
month_adjustment = 1
ElseIf (d1 >= 15 And d2 <= 15) Then
month_adjustment = -1
End If
End If
date_diff_to_months = m_diff + y_diff + month_adjustment
End Function
EDit: account for years...
=( (YEAR(B1)*12+MONTH(B1)) - (YEAR(A1)*12+MONTH(A1)) )
+ ( IF(DAY(A1)<=15,1,0)+IF(DAY(B1)>15,1,0) )

Check if given month+date is present in the data containing range of month+date

Here is my query:
DECLARE #MM INT -- Current month
DECLARE #DD INT -- Current date
SET #MM = 1 -- For testing, set it to January
SET #DD = 1 -- For testing, set it to 01
SELECT xxxID, xxxFK, StartMonth, StartDate, StopMonth, StopDate, NULL AS OKorNOT
FROM xxxTable
ORDER BY xxxFK
And here is the data:
xxxID xxxFK StartMonth StartDate StopMonth StopDate OKorNOT
---------------- ----------- ----------- ----------- ----------- ----------- -----------
8 2287 11 15 1 2 NULL
4 2290 2 1 2 21 NULL
2 2306 9 15 10 31 NULL
3 2306 1 3 1 20 NULL
9 2661 11 15 1 3 NULL
10 2661 5 5 5 31 NULL
5 3778 6 2 9 5 NULL
6 3778 1 1 3 31 NULL
7 3778 5 10 5 31 NULL
1 3778 12 10 12 31 NULL
I need to populate OKorNot column with 1/0 depending on whether the given month-date lies between StartMonth-StartDate and StopMonth-StopDate. This is SQL Server 2000 by the way.
EDIT
The thing here to note that is that there are no years stored in the data and the months-dates may start in, say Nov-15 and end in Jan-15 so on Dec-31 and Jan-1 this case should return true.
Using integer operations only and an imaginary 384-days calendar
Since your dates are combinations of month and day, I tried to create an integer for every such combination, an integer that is unique and also preserves order. To have calculations as simple as possible, we invent a new calendar where all months have exactly 32 days and we act as if our dates are from this calendar. Then to get how many days have past since 1st of January, we have the formula:
DaysPast = 32 * month + day
(OK, it should be 32 * (month-1) + (day-1) but this way it's simpler and we only want to compare dates relatively to one another, not to January 1st. And the result is still unique for every date).
Therefore, we first calculate the DaysPast for our check date:
SET #CHECK = 32 * #MM + #DD
Then, we calculate the DaysPast for all dates (both start and stop ones) in our table:
( SELECT *
, (32 * StartMonth + StartDate) AS Start
, (32 * StopMonth + StopDate ) AS Stop
FROM xxxTable
) AS temp
Then, we have two cases.
First case, when Start = (8-Feb) and Stop = (23-Nov).
Then, the first condition #CHECK BETWEEN Start AND Stop will be true and the dates between Start and Stop will be OK.
The second condition will be False, so no more dates will be OK.
Second case, when Start = (23-Nov) and Stop = (8-Feb). :
Then, the first condition #CHECK BETWEEN Start AND Stop will be false because Start is bigger than Stop so no dates can match this condition.
The second condition Stop < Start will be true, so we also test if
#CHECK is NOT BETWEEN (9-Feb) AND (22-Nov)
to match the dates that are before (9-Feb) or after (22-Nov).
DECLARE #CHECK INT
SET #CHECK = 32 * #MM + #DD
SELECT *
, CASE WHEN
#CHECK BETWEEN Start AND Stop
OR ( Stop < Start
AND #CHECK NOT BETWEEN Stop+1 AND Start-1
)
THEN 1
ELSE 0
END
AS OKorNOT
FROM
( SELECT *
, (32 * StartMonth + StartDate) AS Start
, (32 * StopMonth + StopDate ) AS Stop
FROM xxxTable
) AS temp
ORDER BY xxxFK
It would be easier if you'd stored dates as, well, dates...
Anyway, something like this. I haven't tested. And you need to deal with year boundary which I've done
SELECT
xxxID, xxxFK, StartMonth, StartDate, StopMonth, StopDate,
CASE
WHEN
FullStart <= FullStop AND
DATEADD(month, #MM-1, DATEADD(day, #DD-1, 0)) BETWEEN FullStart AND FullStop
THEN 1
WHEN
FullStart > FullStop AND
DATEADD(month, #MM-1, DATEADD(day, #DD-1, 0)) BETWEEN
FullStart AND DATEADD(year, 1, FullStop)
THEN 1
ELSE 0
END AS OKOrNot
FROM
(
SELECT
xxxID, xxxFK, StartMonth, StartDate, StopMonth, StopDate,
DATEADD(month, StartMonth-1, DATEADD(day, StartDate-1, 0)) AS FullStart,
DATEADD(month, StopMonth-1, DATEADD(day, StopDate-1, 0)) AS FullStop
FROM xxxTable
) foo
ORDER BY xxxFK
edit: added "-1" to all values: if we're already Jan don't add another month...
SELECT *
FROM xxxTable
WHERE (StartMonth < StopMonth OR StartMonth = StopMonth AND StartDate<=StopDate)
AND (#MM > StartMonth OR #MM = StartMonth AND #DD >= StartDate)
AND (#MM < StopMonth OR #MM = StopMonth AND #DD <= StopDate)
OR (StartMonth > StopMonth OR StartMonth = StopMonth AND StartDate>StopDate)
AND ((#MM > StartMonth OR #MM = StartMonth AND #DD >= StartDate)
OR (#MM < StopMonth OR #MM = StopMonth AND #DD <= StopDate))