I am relatively new to DAX and PowerBI, and have an issue that is driving me up the wall.
I have a table with data from my source system and a Calendar table, I also have a Measures table where various DAX Measures are calculated/stored.
In the source System, I have 3 columns that are relevant here: Unique_ID, PurchaseDate, TerminationDate
TerminationDate either has a value (as in the subscription is terminated) or is NULL (and therefore active)
The problem I am trying to solve is that I wish to know how many active subscriptions I had N Number of Months ago and have this as a Dynamic value.
I initially thought I had success with the below bit of code, however when I change the variable Month1 indexing it by increments of 1 eg: =MONTH(TODAY())-2 =MONTH(TODAY())-3 etc.) the value didn't change.
Previous 1 month Total active Services =
var month1= MONTH(TODAY())-1
var year= YEAR(TODAY())
return
calculate(
COUNTROWS(Table1),
FILTER(Table1,
Table1[PurchaseDate] >= month1
&& Table1[PurchaseDate] >= year
&& ((Table1[TerminationDate] <= month1
&& Table1[TerminationDate] <= year)
|| isblank(Table1[TerminationDate]) )
))
So, then I decided that the above was trying to be too clever and that I'd simplify things by having a measure for all subscriptions with a purchase date equal or less than todays' Month-1/Year, another measure where the Termination date was less than or equal to todays Month-1/Year and then subtracting one from the other should give the answer.
Previous 1 month Total active Services calculation 2 =
var month1= MONTH(TODAY())-1
var year= YEAR(TODAY())
return
calculate(
COUNTROWS(Table1),
FILTER(Table1,
Table1[TerminationDate] <= month1
&& Table1[TerminationDate] <= year
))
Bearing in mind I'm validating the accuracy of the above by running this in the SQL backend (and this is all being done on a copy of the DB, so I know there's no production changes)
select count(t.unique_id)
from table1 t
where t.terminationdate <= '2020-07-31'
and then doing the same but with '2020-06-30' etc.
Ideally the solution wouldn't necessitate the creation of additional columns nor utilize slicers - this is for (what should be) a very simple calculation.
Sample Data:
Unique_ID PurchaseDate TerminationDate
WM-SP-998407 2016-06-01 07:42:41.000 2020-01-02 11:25:26.000
WM-SP-998412 2016-06-01 08:02:11.000 2017-08-30 11:26:31.000
WM-SP-998417 2016-06-01 08:11:01.000 2017-08-30 11:26:05.000
WM-SP-998422 2016-06-01 08:11:02.000 2017-08-30 11:25:49.000
WM-SP-998427 2016-06-01 08:22:41.000 2018-08-30 11:26:18.000
WM-SP-998432 2016-06-01 08:47:41.000 NULL
WM-SP-998437 2016-06-01 09:22:41.000 2020-03-07 08:10:49.000
WM-SP-998442 2016-06-01 09:25:42.000 NULL
WM-SP-998447 2016-06-01 09:51:11.000 2018-08-30 11:26:33.000
WM-SP-998452 2016-06-01 09:51:11.000 NULL
WM-SP-998457 2016-06-01 10:00:51.000 NULL
Related
I am trying to make time adjustment (due to summer time change).
I have a bottom table with datetime as data type (in Azure SQL) created.
This is DIM table, and this is what I have now:
start_dt end_dt hour_diff
2022-01-22 00:00:00.000 2022-03-13 01:59:59.000 -5
2022-03-13 02:00:00.000 2022-11-06 01:59:59.000 -4
What I am trying to do is, if punch time is between 1/22/2022 12:00 AM --> 3/13/2022 01:59:59 AM (inclusive), it will take hour_diff of -5.
So, if somebody clocks in at 3/13/2022 1:59:59 AM, it will be -5 hour_diff.
If punch time is between 3/13/2022 2:00 AM --> 11/6/2022 01:59:59 AM (inclusive), it will take hour_diff of -4.
So, if somebody clocks in at 3/13/2022 2:00:00 AM, it will be -4 hour_diff.
Just FYI, bottom is SQL statement that I am using:
select
CONVERT(nvarchar(255), DateAdd(hour,hour_diff, ps), 0) punch_start,
CONVERT(nvarchar(255), DateAdd(hour,hour_diff, ps1), 0) punch_end
from [dbo].[Table1]
cross apply
(
values(
Try_Convert(datetime, punch_start),
Try_Convert(datetime, punch_end)
)
) x (ps,ps1)
left join
[dbo].[DIM] d on
ps between d.start_dt and d.end_dt
or
ps1 between d.start_dt and d.end_dt
I am trying to make sure this query works with current data in DIM table (using BETWEEN).
I need to find the price for an item for each financial year end date in a date range. In this case the financial year is e.g. 31 March
The table I have for example:
ItemID
Value
DateFrom
DateTo
1
10
'2019/01/01'
'2021/02/28'
1
11
'2021/03/01'
'2021/05/01'
SQL Fiddle
The SQL would thus result in the above table to be:
ItemID
Value
DateFrom
DateTo
1
10
'2019/01/01'
'2019/03/30'
1
10
'2020/03/31'
'2021/02/28'
1
11
'2020/03/01'
'2021/03/30'
1
11
'2020/03/31'
'2021/05/01'
You can solve it, but a prerequisite is the creation of a table called financial_years and filling it with data. This would be the structure of the table:
financial_years(id, DateFrom, DateTo)
Now that you have this table, you can do something like this:
select ItemID, Value, financial_years.DateFrom, financial_years.DateTo
from items
join financial_years
on (items.DateFrom between financial_years.DateFrom and financial_years.DateTo) or
(items.DateTo between financial_years.DateFrom and financial_years.DateTo)
order by financial_years.DateFrom;
The accepted answer is not correct, as it does not split out different parts of the year which have different values.
You also do not need a Year table, although it can be beneficial. You can generate it on the fly using a VALUES table.
Note also a better way to check the intervals overlap, using AND not OR
WITH Years AS (
SELECT
YearStart = DATEFROMPARTS(v.yr, 3, 31),
YearEnd = DATEFROMPARTS(v.yr + 1, 3, 31)
FROM (VALUES
(2015),(2016),(2017),(2018),(2019),(2020),(2021),(2022),(2023),(2024),(2025),(2026),(2027),(2028),(2029),(2030),(2031),(2032),(2033),(2034),(2035),(2036),(2037),(2038),(2039)
) v(yr)
)
SELECT
i.ItemID,
i.Value,
DateFrom = CASE WHEN i.DateFrom > y.YearStart THEN i.DateFrom ELSE y.YearStart END,
DateTo = CASE WHEN i.DateTo > y.YearEnd THEN y.YearEnd ELSE i.DateTo END
FROM items i
JOIN Years y ON i.DateFrom <= y.YearEnd
AND i.DateTo >= y.YearStart;
How can I get the number of days passed in the current quarter?
For example, if today is 1/2/2021, it will return 2.
If today is 2/5, it will return 36.
If today is 4/2, it will return 2.
Use date_trunc() to get the start of the quarter and subtract dates:
WITH cte(day) AS (
VALUES
(date '2021-01-02')
, (date '2021-02-05')
, (date '2021-04-02')
)
SELECT day
, day - date_trunc('quarter', day)::date + 1 AS days_passed_in_quarter
FROM cte;
day | days_passed_in_quarter
------------+------------------------
2021-01-02 | 2
2021-02-05 | 36
2021-04-02 | 2
+ 1 to fix off-by-one error as you clearly want to include the current day as "passed".
Always use unambiguous ISO 8601 date format (YYYY-MM-DD - 2021-02-05), which is the default in Postgres and always unambiguous, or you depend on the current datestyle setting (and may be in for surprises). Also avoids misunderstandings general communication.
Related:
PostgreSQL: between with datetime
I'm quite a beginner on VB/SQL, I just began my learning few months ago, but I can understand the logic of algorithms as I used to do some Excel VBA .
I'm actually designing a database where I can (wish to) follow up every colleague's activity during the year.
The objective is to have a (Monthly) ratio of =>
Billable days / (Billable + Non Billable - Absent)
The context :
A single person can be : Working internally (Non billable), OR Working Externally (Billable) , OR on Holidays (Absent).
I have a [Planning] Table where it stores the following data : [Consultant_ID] (linked to another table [Consultant], [Activity] (A list with the three choices described above), [Beginning_Date], [End_Date].
Example :
Consultant 1 : Working externally from 01/01/2019 to 01/06/2019,
Working internally from 02/06/2019 to 31/12/2019,
Holidays from 02/03/2019 to 15/03/2019
Is there a way to have the Billable ratio of March for example ?
I created 4 queries (Maybe too much ?)
3 queries : [Consultant_ID] [Activity] [Beginning_Date] [End_Date] [Ratio : Datediff("d";[Beginning_Date];[End_Date]).
For each query : The [Activity criteria] : one Working Internally, one Working Externally, one Absent.
And for the [Beginning_Date] and [End_Date] criterias : <=[Enter beginning date], >=[Enter End date]
And the 4th query [Consultant ID] [Billable] [Non billable] [Absent] (and planning to add the [RATIO]).
Problem is : the Datediff counts the dates of the whole activity of what it finds, and not only the dates between 01/03/2019 and 31/03/2019 as I wish to.
I Expect the output of the ratio to be : Billable days / (Billable + Non Billable - Absent) of the desired period.
The actual output shows the billable, non billable, and absent days of the whole period between the dates which are inputted
So instead of 31 Billable, 0 Non billable, 15 Absent
It shows 180 Billable, 0 Non Billable, 32 Absent
Sorry for the long post, it is actually my first, and thank you very much !
I've been struggling with this for a whole week
We first need to figure out the maxBegin and the minEnd dates for each row
SELECT
*,
(IIF (Beginning_Date > #3/1/2019#, Beginning_Date, #3/1/2019#) ) as maxBegin,
(IIF (End_Date < #3/31/2019#, End_Date, #3/31/2019#) ) as minEnd,
Datediff("d", maxBegin, minEnd) + 1 as theDiff
FROM Planning
Where Beginning_Date <= #3/31/2019# AND End_Date >= #3/1/2019#
Then use that to compute the durations. Note: DateDiff does not count both ends, so we need to add +1.
SELECT
Consultant_ID,
SUM(IIF (Activity = "Working Internally", Datediff("d", maxBegin, minEnd) +1, 0) ) as NonBillable,
SUM(IIF (Activity = "Working Externally", Datediff("d", maxBegin, minEnd) +1, 0) ) as Billable,
SUM(IIF (Activity = "Holidays", Datediff("d", maxBegin, minEnd) +1, 0) ) as Absent
FROM
(
SELECT
*,
(IIF (Beginning_Date > #3/1/2019#, Beginning_Date, #3/1/2019#) ) as maxBegin,
(IIF (End_Date < #3/31/2019#, End_Date, #3/31/2019#) ) as minEnd
FROM Planning
Where Beginning_Date <= #3/31/2019# AND End_Date >= #3/1/2019#
) as z
GROUP BY Planning.Consultant_ID;
Finally, you need to substitute the actual Begin/End dates via params into the sql to run your query. Also note that the Holidays are only 14, not 15.
Also, you can add the Ratio calculation right into this sql, and have only one query.
I have a dataset of documents with associated publication dates (regular Postgres TIMESTAMP.
After noticing that some of these data points are for some reason invalid, I would like to remove all documents from a specific outlet that are published in the hour of 10-11 am, on two specific dates.
So far, I have come up with two different queries to do this, but they strangely return different results The first one returns all documents based on the simple DATETIME range query, and has 1603 results.
The second one queries only the days, and then all elements that have DATE_PART('HOUR', published) = 10, which should (in theory) return the exact same.
As the below query shows, though, there are two elements that are incidentally published exactly on the hour. Although they still have the same DATE_PART signature, they seemingly get ignored in the second query.
Can anyone tell me whether this is default behavior, or why this would return different answers?
postgres=# SELECT document_id, published, DATE_PART('HOUR', published) AS hour
FROM documents
WHERE (published >= '2016-08-18 10:00:00.000' AND published <= '2016-08-18 10:59:59.999')
OR (published >= '2016-08-28 10:00:00.000' AND published <= '2016-08-28 10:59:59.999')
AND feedName = 'WP'
EXCEPT
SELECT document_id, published, DATE_PART('HOUR', published) AS hour
FROM documents WHERE (to_char(published, 'YYYY-MM-DD') = '2016-08-18'
OR to_char(published, 'YYYY-MM-DD') = '2016-08-28')
AND feedName = 'WP' AND DATE_PART('HOUR', published) = 10;
document_id | published | hour
-------------+---------------------+------
75676 | 2016-08-18 10:00:00 | 10
76424 | 2016-08-18 10:00:00 | 10
The problem turned out to be a missing set of brackets around the first query, where the two date ranges should have been connected with the OR operator inside a separate set of brackets, like so:
SELECT document_id, published, DATE_PART('HOUR', published) AS hour
FROM documents
WHERE ((published >= '2016-08-18 10:00:00.000' AND published <= '2016-08-18 10:59:59.999')
OR (published >= '2016-08-28 10:00:00.000' AND published <= '2016-08-28 10:59:59.999'))
AND feedName = 'WP'