ADDCOLUMNS https://interactivechaos.ovh/en en Creación de un calendario https://interactivechaos.ovh/es/dax/scenario/creacion-de-un-calendario <span class="field field--name-title field--type-string field--label-hidden">Creating a calendar</span> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/en/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span></span> <span class="field field--name-created field--type-created field--label-hidden">Sun, 07/07/2019 - 18:20</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>One of the most frequently asked questions regarding the calendar required to use time intelligence features is, is it better to create it external to Power BI? Or in the query editor? Or maybe with DAX?</p> <p>In this scenario we are going to create a complete calendar in DAX, including the number and name of the month, quarter, day of the week, etc.</p> <p>To begin, we create the basic calendar table using the <a href="/en/dax/function/calendarauto">CALENDARAUTO</a> function. This function creates a table with a single column with a sequence of dates covering all the dates that appear in our data set, by default from January 1 of the first year to December 31 of the last year:</p> <div class="codigo"> <p>Calendar = CALENDARAUTO()</p> </div> <img alt="Calendar created with CALENDARAUTO" data-entity-type="file" data-entity-uuid="41837857-0178-4e3c-acd4-d56266d5d974" src="/sites/default/files/inline-images/escenario-dax-0075.png" class="align-center" width="284" height="324" loading="lazy" /><p>However, we want to add other fields to this basic table, for which we are going to use the following DAX functions (note in the image above that the field created is named "<em>Date</em>"):</p> <ul><li>To create the year: <a href="/en/dax/function/year">YEAR</a></li> <li>To create the month number: <a href="/en/dax/function/month">MONTH</a></li> <li>To create the day number: <a href="/en/dax/function/day">DAY</a></li> </ul><p>We are going to add these new fields to the basic table using the <a href="/en/dax/function/addcolumns">ADDCOLUMNS</a> function:</p> <div class="codigo"> <p>Calendar = <br />     ADDCOLUMNS(<br />         CALENDARAUTO();<br />         "Year"; YEAR([Date]);<br />         "Month"; MONTH([Date]);<br />         "Day"; DAY([Date])<br />     )</p> </div> <img alt="Fields for the year, month number, and day of the month" data-entity-type="file" data-entity-uuid="bf2996fb-ebfe-4052-b2eb-fef704e53234" src="/sites/default/files/inline-images/escenario-dax-0076.png" class="align-center" width="407" height="387" loading="lazy" /><p>The names for the month and the day of the week can be created with the <a href="/en/dax/function/format">FORMAT</a> function, and the week number and the day of the week number with the <a href="/en/dax/function/weeknum">WEEKNUM</a> and <a href="/en/dax/function/weekday">WEEKDAY</a> functions, respectively:</p> <div class="codigo"> <p>Calendar = <br />     ADDCOLUMNS(<br />         CALENDARAUTO();<br />         "Year"; YEAR([Date]);<br />         "Month"; MONTH([Date]);<br />         "Month Name"; FORMAT([Date]; "MMMM");<br />         "Week #"; WEEKNUM([Date]);<br />         "Day"; DAY([Date]);<br />         "Week Day"; WEEKDAY([Date]);<br />         "Day Name"; FORMAT([Date]; "DDDD")<br />     )</p> </div> <img alt="Fields for the name of the month and the day, the number of the week and the number of the day of the week" data-entity-type="file" data-entity-uuid="4b970cc7-125a-477c-bdb7-83ac11805295" src="/sites/default/files/inline-images/escenario-dax-0077.png" class="align-center" width="696" height="501" loading="lazy" /><p>Finally, to obtain the quarter number we can use the formula:</p> <div class="codigo"> <p>CEILING(MONTH([Date])/3,1)</p> </div> <p>...which calculates the nearest integer equal to or greater than the month divided by 3 (with the <a href="/en/dax/function/ceiling">CEILING</a> function).</p> <p>If we also wanted to have the equivalent preceded by a "Q", we can again resort to the FORMAT function and the &amp; operator that allows us to concatenate text strings:</p> <div class="codigo"> <p>Calendar = <br />     ADDCOLUMNS(<br />         CALENDARAUTO();<br />         "Year"; YEAR([Date]);<br />         "Quarter #"; CEILING(MONTH([Date])/3;1);<br />         "Quarter"; "Q" &amp; FORMAT(CEILING(MONTH([Date])/3;1); "#");<br />         "Month"; MONTH([Date]);<br />         "Month Name"; FORMAT([Date]; "MMMM");<br />         "Week #"; WEEKNUM([Date]);<br />         "Day"; DAY([Date]);<br />         "Week Day"; WEEKDAY([Date]);<br />         "Day Name"; FORMAT([Date]; "DDDD")<br />     )</p> </div> <img alt="Fields for the quarter" data-entity-type="file" data-entity-uuid="1ce90b45-3e40-4719-89cf-33c23cef9583" src="/sites/default/files/inline-images/escenario-dax-0078.png" class="align-center" width="836" height="575" loading="lazy" /></div> <div class="field field--name-field-funciones-dax-involucradas field--type-entity-reference field--label-above"> <div class="field__label">DAX functions involved</div> <div class="field__items"> <div class="field__item"><a href="/es/taxonomy/term/90" hreflang="es">CALENDARAUTO</a></div> <div class="field__item"><a href="/es/taxonomy/term/40" hreflang="es">YEAR</a></div> <div class="field__item"><a href="/es/taxonomy/term/42" hreflang="es">MONTH</a></div> <div class="field__item"><a href="/es/taxonomy/term/43" hreflang="es">DAY</a></div> <div class="field__item"><a href="/es/taxonomy/term/84" hreflang="es">ADDCOLUMNS</a></div> <div class="field__item"><a href="/es/taxonomy/term/44" hreflang="es">FORMAT</a></div> <div class="field__item"><a href="/es/taxonomy/term/91" hreflang="es">WEEKNUM</a></div> <div class="field__item"><a href="/es/taxonomy/term/92" hreflang="es">WEEKDAY</a></div> <div class="field__item"><a href="/es/taxonomy/term/93" hreflang="es">CEILING</a></div> </div> </div> <div class="field field--name-field-dax-esc-dificultad field--type-list-string field--label-above"> <div class="field__label">Difficulty</div> <div class="field__item">Low</div> </div> Sun, 07 Jul 2019 16:20:39 +0000 admin 1156 at https://interactivechaos.ovh Cálculo del número de días entre compras https://interactivechaos.ovh/es/dax/scenario/calculo-del-numero-de-dias-entre-compras <span class="field field--name-title field--type-string field--label-hidden">Calculation of the number of days between purchases</span> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/en/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</span></span> <span class="field field--name-created field--type-created field--label-hidden">Tue, 07/02/2019 - 16:23</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>We start from a list of sales (<span class="code">Sales</span>) in which, for example, the customer identifier and the dates of the purchases are indicated:</p> <img alt="Starting data" data-entity-type="file" data-entity-uuid="6e7ea336-e513-4349-a3ec-f7cc14d9cd1b" src="/sites/default/files/inline-images/escenario-dax-0042.png" class="align-center" width="238" height="198" loading="lazy" /><p>The objective is to add to this table a column that indicates the number of days elapsed since the previous purchase (earlier in time, since nothing assures us that the order of the data in the original table is chronological, and we already know that Power BI neither ensures the order of the rows).</p> <p>The resolution of this scenario is not easy. Although it could be solved in a single expression, its resolution is presented below step by step. The phases involved are the following:</p> <ol><li>It is necessary to obtain, for each purchase date of customer X, the date of the previous purchase.</li> <li>The previous purchase date is the highest date of all customer X's purchases (except for the purchase we are analyzing, of course).</li> <li>We can obtain all the previous purchases of customer X by cross-joining the table with itself, taking as common field the one corresponding to the customer's identifier and considering in the right table (see the documentation of the <a href="/en/dax/function/generate">GENERATE</a> function) only the dates before the purchase date being considered in the left table. Thus, for example, for the purchase that appears in the third line of the previous image (corresponding to customer 1, dated January 21, 2019), a cross joining with the same table in the aforementioned conditions would return a row for the combination of row 3 and row 1 (same customer and previous date) and another for the combination of row 3 and row 2 (again, same customer and previous date).</li> </ol><p>Finally, once the table mentioned in point 1 has been obtained, it would be enough to calculate the difference between each purchase date and the date of the last purchase.</p> <p>Let's do it step by step.</p> <p>First we want to obtain, for each row (that is, for each purchase), the set of previous purchases of the same customer. This, as mentioned, can be achieved with a cross join that allows us to specify the conditions of the join, that is, with the <a href="/en/dax/function/generate">GENERATE</a> function. As this function requires that the tables involved in the combination have fields with different names, we are going to modify the names of the fields of the second copy with the <a href="/en/dax/function/selectcolumns">SELECTCOLUMNS</a> function, adding a "_" symbol at the end of the names:</p> <div class="codigo"> <p>SelfJoin = <br />     GENERATE(<br />         Sales;<br />         FILTER(<br />             SELECTCOLUMNS(<br />                 Sales;<br />                 "Customer_"; Sales[Customer];<br />                 "Purchase Date_"; Sales[Purchase Date]<br />             );<br />             [Purchase Date_] &lt; Sales[Purchase Date] &amp;&amp; Sales[Customer] = [Customer_]<br />         )<br />     )<sales></sales></p> </div> <img alt="Self-join using the row context created by the GENERATE function" data-entity-type="file" data-entity-uuid="61138555-e1c0-45a5-9bbb-dcefc4489cf9" src="/sites/default/files/inline-images/escenario-dax-0044.png" class="align-center" width="670" height="514" loading="lazy" /><p>As we can see, we are obtaining the cross join by imposing the condition that the customer identifier is the same, and that the dates in the column on the right are lower than the date considered in each of the rows on the left (for simplicity, we are assuming that the same customer will not make two purchases on the same day).</p> <p>Note that the records in the first table for which there are no records in the second that meet the imposed conditions do not appear (that is, in the table that we have just created, only purchase dates for which there is a previous purchase are included).</p> <p>Obtaining, from here, the date before each purchase is easy: just group (with the <a href="/en/dax/function/groupby">GROUPBY</a> function) by customer and purchase date (<em>Customer</em> and <em>Purchase Date</em> fields) and select the maximum value (of each group) of the field <em>Purchase Date_</em> :</p> <div class="codigo"> <p>LastPurchases = <br />     GROUPBY(<br />         SelfJoin;<br />         SelfJoin[Customer];<br />         SelfJoin[Purchase Date];<br />         "Last Purchase"; MAXX(<br />                             CURRENTGROUP();<br />                             SelfJoin[Purchase Date_]<br />                         )<br />     )</p> </div> <img alt="Table with the dates of the last purchase" data-entity-type="file" data-entity-uuid="c7517dfc-1136-438b-b5c4-736188acc9ea" src="/sites/default/files/inline-images/escenario-dax-0045.png" class="align-center" width="459" height="348" loading="lazy" /><p>Now comes a somewhat complicated process: as the table only includes purchase dates for which there is a previous purchase, if we want all the original dates to appear in the final result we would have to perform a left outer join between the original date table and the new one. For this we would have to use the <a href="/en/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a> function, but this function requires that the tables to be joined have the same lineage (they come from the same source), which is not true in our case. As explained in the <a href="/en/dax/function/naturalleftouterjoin">documentation for this function</a>, it is possible to solve this problem by adding an empty text string to the end of the names:</p> <div class="codigo"> <p>Purchase and Last Purchase = <br />     NATURALLEFTOUTERJOIN(<br />         SELECTCOLUMNS(<br />             Sales;<br />             "Customer"; Sales[Customer] &amp; "";<br />             "Purchase Date"; Sales[Purchase Date] &amp; ""<br />         );<br />         SELECTCOLUMNS(<br />             LastPurchases;<br />             "Customer"; LastPurchases[SelfJoin_Customer] &amp; "";<br />             "Purchase Date"; LastPurchases[SelfJoin_Purchase Date] &amp; "";<br />             "Last Purchase"; LastPurchases[Last Purchase]<br />         )<br />     )</p> </div> <img alt="Initial table including the date of the last purchase (if any)" data-entity-type="file" data-entity-uuid="bd8c8912-3173-4504-886e-057331c10f2a" src="/sites/default/files/inline-images/escenario-dax-0046.png" class="align-center" width="590" height="461" loading="lazy" /><p>Finally, to calculate the number of days since the last purchase, simply add a new column that returns the difference (only if there is a last purchase):</p> <div class="codigo"> <p>Days since last purchase = <br />     ADDCOLUMNS(<br />         'Purchase and Last Purchase';<br />         "# days";<br />             VAR<br />                 NumberOfDays =<br />                     'Purchase and Last Purchase'[Purchase Date] - <br />                     'Purchase and Last Purchase'[Last Purchase]<br />             RETURN<br />                 IF(<br />                     ISBLANK('Purchase and Last Purchase'[Last Purchase]);<br />                     BLANK();<br />                     NumberOfDays<br />                 )<br />     )</p> </div> <img alt="Final table showing the number of days since the last purchase" data-entity-type="file" data-entity-uuid="98f6ede6-aae6-4e3b-89fa-9826e897310c" src="/sites/default/files/inline-images/escenario-dax-0047.png" class="align-center" width="595" height="479" loading="lazy" /><p>To return the day difference, we use the <a href="/en/dax/function/if">IF</a> function to confirm if the value of the field corresponding to the last purchase is a BLANK or not, for which we use the <a href="/en/dax/function/isblank">ISBLANK</a> function.</p> </div> <div class="field field--name-field-funciones-dax-involucradas field--type-entity-reference field--label-above"> <div class="field__label">DAX functions involved</div> <div class="field__items"> <div class="field__item"><a href="/es/taxonomy/term/79" hreflang="es">GENERATE</a></div> <div class="field__item"><a href="/es/taxonomy/term/69" hreflang="es">SELECTCOLUMNS</a></div> <div class="field__item"><a href="/es/taxonomy/term/48" hreflang="es">FILTER</a></div> <div class="field__item"><a href="/es/taxonomy/term/60" hreflang="es">GROUPBY</a></div> <div class="field__item"><a href="/es/taxonomy/term/39" hreflang="es">MAXX</a></div> <div class="field__item"><a href="/es/taxonomy/term/82" hreflang="es">CURRENTGROUP</a></div> <div class="field__item"><a href="/es/taxonomy/term/83" hreflang="es">NATURALLEFTOUTERJOIN</a></div> <div class="field__item"><a href="/es/taxonomy/term/68" hreflang="es">VAR</a></div> <div class="field__item"><a href="/es/taxonomy/term/29" hreflang="es">IF</a></div> <div class="field__item"><a href="/es/taxonomy/term/56" hreflang="es">ISBLANK</a></div> <div class="field__item"><a href="/es/taxonomy/term/31" hreflang="es">BLANK</a></div> <div class="field__item"><a href="/es/taxonomy/term/84" hreflang="es">ADDCOLUMNS</a></div> </div> </div> <div class="field field--name-field-dax-esc-dificultad field--type-list-string field--label-above"> <div class="field__label">Difficulty</div> <div class="field__item">High</div> </div> Tue, 02 Jul 2019 14:23:33 +0000 admin 1147 at https://interactivechaos.ovh