- Deprecated function: Use of "static" in callables is deprecated in Drupal\user\Entity\Role::postLoad() (line 172 of core/modules/user/src/Entity/Role.php).
Drupal\user\Entity\Role::postLoad(Object, Array) (Line: 423)
Drupal\Core\Entity\EntityStorageBase->postLoad(Array) (Line: 353)
Drupal\Core\Entity\EntityStorageBase->loadMultiple(Array) (Line: 16)
Drupal\user\RoleStorage->isPermissionInRoles('access site in maintenance mode', Array) (Line: 112)
Drupal\Core\Session\UserSession->hasPermission('access site in maintenance mode') (Line: 105)
Drupal\Core\Session\AccountProxy->hasPermission('access site in maintenance mode') (Line: 83)
Drupal\redirect\RedirectChecker->canRedirect(Object) (Line: 120)
Drupal\redirect\EventSubscriber\RedirectRequestSubscriber->onKernelRequestCheckRedirect(Object, 'kernel.request', Object)
call_user_func(Array, Object, 'kernel.request', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.request') (Line: 145)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 141)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2318)
Drupal\views\Plugin\views\display\DisplayPluginBase->preExecute() (Line: 1697)
Drupal\views\ViewExecutable->preExecute(Array) (Line: 1632)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 144)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2318)
Drupal\views\Plugin\views\display\DisplayPluginBase->preExecute() (Line: 1697)
Drupal\views\ViewExecutable->preExecute(Array) (Line: 1632)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 110)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2318)
Drupal\views\Plugin\views\display\DisplayPluginBase->preExecute() (Line: 1697)
Drupal\views\ViewExecutable->preExecute(Array) (Line: 1632)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 38)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2318)
Drupal\views\Plugin\views\display\DisplayPluginBase->preExecute() (Line: 1697)
Drupal\views\ViewExecutable->preExecute(Array) (Line: 1632)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'taxonomy_term') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 228)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->valueForm(Array, Object) (Line: 941)
Drupal\views\Plugin\views\filter\FilterPluginBase->buildExposedForm(Array, Object) (Line: 111)
Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 534)
Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 281)
Drupal\Core\Form\FormBuilder->buildForm('\Drupal\views\Form\ViewsExposedForm', Object) (Line: 134)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm() (Line: 1243)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('taxonomy_term_access') (Line: 145)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 228)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->valueForm(Array, Object) (Line: 941)
Drupal\views\Plugin\views\filter\FilterPluginBase->buildExposedForm(Array, Object) (Line: 111)
Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 534)
Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 281)
Drupal\Core\Form\FormBuilder->buildForm('\Drupal\views\Form\ViewsExposedForm', Object) (Line: 134)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm() (Line: 1243)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('views') (Line: 1316)
Drupal\views\Plugin\views\query\Sql->query() (Line: 1454)
Drupal\views\Plugin\views\query\Sql->build(Object) (Line: 1326)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('views_substitutions', Array) (Line: 1418)
Drupal\views\Plugin\views\query\Sql->query() (Line: 1454)
Drupal\views\Plugin\views\query\Sql->build(Object) (Line: 1326)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('views') (Line: 1316)
Drupal\views\Plugin\views\query\Sql->query(1) (Line: 1455)
Drupal\views\Plugin\views\query\Sql->build(Object) (Line: 1326)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('views_substitutions', Array) (Line: 1418)
Drupal\views\Plugin\views\query\Sql->query(1) (Line: 1455)
Drupal\views\Plugin\views\query\Sql->build(Object) (Line: 1326)
Drupal\views\ViewExecutable->build() (Line: 392)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 196)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('node_load_multiple') (Line: 696)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->buildQuery(Array) (Line: 422)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->getFromStorage(Array) (Line: 393)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->doLoadMultiple(Array) (Line: 346)
Drupal\Core\Entity\EntityStorageBase->loadMultiple(Array) (Line: 1616)
Drupal\views\Plugin\views\query\Sql->loadEntities(Array) (Line: 1541)
Drupal\views\Plugin\views\query\Sql->execute(Object) (Line: 1431)
Drupal\views\ViewExecutable->execute(NULL) (Line: 1459)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98fc117b-200e-4c63-b888-8eb784ab6840') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98fc117b-200e-4c63-b888-8eb784ab6840') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98fc117b-200e-4c63-b888-8eb784ab6840') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98fc117b-200e-4c63-b888-8eb784ab6840') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '861e46e9-f2f7-475f-ae25-ce849b83e07e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '861e46e9-f2f7-475f-ae25-ce849b83e07e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '861e46e9-f2f7-475f-ae25-ce849b83e07e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '861e46e9-f2f7-475f-ae25-ce849b83e07e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a8ba434f-32d1-417a-aa13-8470a25e1714') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a8ba434f-32d1-417a-aa13-8470a25e1714') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a8ba434f-32d1-417a-aa13-8470a25e1714') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a8ba434f-32d1-417a-aa13-8470a25e1714') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Suponiendo que tengamos una tabla calendario ("<em>Calendar</em>") y un campo "<em>Date</em>" conteniendo las fechas, podemos acceder a las fechas involucradas en el contexto actual a través de dicho campo. Esto nos permite acceder al primer día, al último día, etc. del período involucrado en el contexto actual utilizando funciones DAX y simples operaciones aritméticas.
Así, por ejemplo, podemos acceder al primer día del contexto actual calculando el valor mínimo de la columna de fechas con la función <a href="/es/dax/function/min">MIN</a>, de la siguiente forma:
Primer día = MIN('Calendar'[Date])
Para verlo en funcionamiento, llevemos nuestro campo <em>Calendar[Date]</em> a una matriz, naveguemos por la estructura jerárquica de la fecha hasta mostrar, por ejemplo, los meses, y añadamos la medida creada:
Vemos que, efectivamente, la medida devuelve el primer día del período indicado en la cabecera de cada fila.
Podemos calcular el último día del contexto actual de forma semejante, utilizando la función <a href="/es/dax/function/max">MAX</a>:
Último día = MAX('Calendar'[Date])
De hecho, podríamos acceder al siguiente día del contexto actual (o a cualquier otro día que pudiésemos referenciar al primer o último día del contexto actual) sumando 1 al valor máximo:
Siguiente día = MAX('Calendar'[Date]) + 1
Si llevamos estas medidas a nuestra matriz, obtendríamos el siguiente resultado:
Si llevásemos estas medidas a una matriz en la que no hemos incluido en filas el campo <em>Calendar[Date]</em>, los valores mínimo y máximo coincidirían con la primera y última fecha del calendario (sin restricciones adicionales):
La imagen anterior es la correspondiente a un calendario que incluye todas las fechas entre el 1 de enero de 2013 y el 31 de diciembre de 2016. Obsérvese que el resultado devuelto por la medida <em>Siguiente día</em> (1 de enero de 2017) no está incluido en el calendario.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '547aa44a-0082-41d5-b4b3-1ba02d0ba202') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '547aa44a-0082-41d5-b4b3-1ba02d0ba202') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '547aa44a-0082-41d5-b4b3-1ba02d0ba202') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '547aa44a-0082-41d5-b4b3-1ba02d0ba202') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f7a2d4c9-3f4a-44ec-888b-ade91c2f33b7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f7a2d4c9-3f4a-44ec-888b-ade91c2f33b7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f7a2d4c9-3f4a-44ec-888b-ade91c2f33b7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f7a2d4c9-3f4a-44ec-888b-ade91c2f33b7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '340bea73-e7c1-483a-8c03-dfa3c03fe1cb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '340bea73-e7c1-483a-8c03-dfa3c03fe1cb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '340bea73-e7c1-483a-8c03-dfa3c03fe1cb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '340bea73-e7c1-483a-8c03-dfa3c03fe1cb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '448eb155-1b55-46c4-a32a-f04a8cf49df0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '448eb155-1b55-46c4-a32a-f04a8cf49df0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '448eb155-1b55-46c4-a32a-f04a8cf49df0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '448eb155-1b55-46c4-a32a-f04a8cf49df0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En general, cuando queremos trabajar con datos repartidos entre dos o más tablas, partimos de un modelo de datos en el que las tablas están relacionadas entre sí por medio de "relaciones" que involucran un campo clave en los extremos de éstas. Pero no siempre es necesario que existan estas relaciones.
En este escenario partimos de una tabla de países:
...y de una segunda tabla en la que se incluye la extensión de los mismos países:
Obsérvese que las listas no están ordenadas según el mismo criterio.
Una vez importadas las tablas a Power BI, confirmamos (pues el escenario se basa en esta hipótesis) que no existe una relación entre ellas:
El objetivo es añadir el campo <em>Extensión</em> de la tabla homónima a la tabla <em>Países</em>. Si existiese una relación entre las tablas podría conseguirse recurriendo a la función <a href="/es/dax/function/related">RELATED</a>. Pero en este caso no existe. Afortunadamente disponemos de una buena alternativa: la función <a href="/es/dax/function/lookupvalue">LOOKUPVALUE</a>. Esta función nos permite extraer valores de una columna buscando en una o más columnas de la misma tabla un valor (o valores) que pueden estar o no en la misma tabla.
Podemos aprovecharnos de esto añadiendo a la tabla de <em>Países</em> una nueva columna que extraiga la <em>Extensión</em> (de la tabla homómina) buscando en la columna <em>País</em> (de la misma tabla) el valor del país de la tabla <em>Países</em>. Véamoslo en la práctica:
Extensión =
LOOKUPVALUE(
'Extensión'[Extensión]; // Valor a extraer
'Extensión'[País]; // Columna de búsqueda
'Países'[País] // Columna de la que extraer el valor a buscar
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'e4c86d9d-37c8-4cfe-941a-995999c85154') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario queremos añadir a una tabla una columna conteniendo las fechas contenidas en un campo existente añadiendo un cierto desplazamiento (de, por ejemplo, 7 días) y un número aleatorio adicional de días, número aleatorio que varíe entre, por ejemplo, -3 y +3. Para ello partimos de una tabla, <em>Sales</em>, conteniendo un campo <em>Date</em> conteniendo una fecha (en formato <em>datetime</em>).
Para añadir un desplazamiento de n días vamos a utilizar la función <a href="/dax/function/dateadd">DATEADD</a>, que nos permite añadir un número de intervalos a una fecha o a un conjunto de fechas. La expresión de la nueva columna sería:
Random date = DATEADD(Sales[Date]; n; DAY)
...siendo <em>n</em> el número de días a añadir (o restar) a las fechas del contexto. En nuestro caso n resultará de sumar a 7 un número aleatorio que deberá variar entre -3 y +3, número que podemos generar con la función <a href="/dax/function/randbetween">RANDBETWEEN</a>. Es decir, n vendrá dado por:
n = 7 + RANDBETWEEN(-3; 3)
La expresión final de la nueva columna será entonces:
Random date = DATEADD(Sales[Date]; 7 + RANDBETWEEN(-3; 3); DAY)
Podemos ver las dos columnas, la original <em>Date </em>y la recién creada <em>Random date</em>, en la siguiente imagen:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'e4c86d9d-37c8-4cfe-941a-995999c85154') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario queremos añadir a una tabla una columna conteniendo las fechas contenidas en un campo existente añadiendo un cierto desplazamiento (de, por ejemplo, 7 días) y un número aleatorio adicional de días, número aleatorio que varíe entre, por ejemplo, -3 y +3. Para ello partimos de una tabla, <em>Sales</em>, conteniendo un campo <em>Date</em> conteniendo una fecha (en formato <em>datetime</em>).
Para añadir un desplazamiento de n días vamos a utilizar la función <a href="/dax/function/dateadd">DATEADD</a>, que nos permite añadir un número de intervalos a una fecha o a un conjunto de fechas. La expresión de la nueva columna sería:
Random date = DATEADD(Sales[Date]; n; DAY)
...siendo <em>n</em> el número de días a añadir (o restar) a las fechas del contexto. En nuestro caso n resultará de sumar a 7 un número aleatorio que deberá variar entre -3 y +3, número que podemos generar con la función <a href="/dax/function/randbetween">RANDBETWEEN</a>. Es decir, n vendrá dado por:
n = 7 + RANDBETWEEN(-3; 3)
La expresión final de la nueva columna será entonces:
Random date = DATEADD(Sales[Date]; 7 + RANDBETWEEN(-3; 3); DAY)
Podemos ver las dos columnas, la original <em>Date </em>y la recién creada <em>Random date</em>, en la siguiente imagen:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'e4c86d9d-37c8-4cfe-941a-995999c85154') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario queremos añadir a una tabla una columna conteniendo las fechas contenidas en un campo existente añadiendo un cierto desplazamiento (de, por ejemplo, 7 días) y un número aleatorio adicional de días, número aleatorio que varíe entre, por ejemplo, -3 y +3. Para ello partimos de una tabla, <em>Sales</em>, conteniendo un campo <em>Date</em> conteniendo una fecha (en formato <em>datetime</em>).
Para añadir un desplazamiento de n días vamos a utilizar la función <a href="/dax/function/dateadd">DATEADD</a>, que nos permite añadir un número de intervalos a una fecha o a un conjunto de fechas. La expresión de la nueva columna sería:
Random date = DATEADD(Sales[Date]; n; DAY)
...siendo <em>n</em> el número de días a añadir (o restar) a las fechas del contexto. En nuestro caso n resultará de sumar a 7 un número aleatorio que deberá variar entre -3 y +3, número que podemos generar con la función <a href="/dax/function/randbetween">RANDBETWEEN</a>. Es decir, n vendrá dado por:
n = 7 + RANDBETWEEN(-3; 3)
La expresión final de la nueva columna será entonces:
Random date = DATEADD(Sales[Date]; 7 + RANDBETWEEN(-3; 3); DAY)
Podemos ver las dos columnas, la original <em>Date </em>y la recién creada <em>Random date</em>, en la siguiente imagen:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'e4c86d9d-37c8-4cfe-941a-995999c85154') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario queremos añadir a una tabla una columna conteniendo las fechas contenidas en un campo existente añadiendo un cierto desplazamiento (de, por ejemplo, 7 días) y un número aleatorio adicional de días, número aleatorio que varíe entre, por ejemplo, -3 y +3. Para ello partimos de una tabla, <em>Sales</em>, conteniendo un campo <em>Date</em> conteniendo una fecha (en formato <em>datetime</em>).
Para añadir un desplazamiento de n días vamos a utilizar la función <a href="/dax/function/dateadd">DATEADD</a>, que nos permite añadir un número de intervalos a una fecha o a un conjunto de fechas. La expresión de la nueva columna sería:
Random date = DATEADD(Sales[Date]; n; DAY)
...siendo <em>n</em> el número de días a añadir (o restar) a las fechas del contexto. En nuestro caso n resultará de sumar a 7 un número aleatorio que deberá variar entre -3 y +3, número que podemos generar con la función <a href="/dax/function/randbetween">RANDBETWEEN</a>. Es decir, n vendrá dado por:
n = 7 + RANDBETWEEN(-3; 3)
La expresión final de la nueva columna será entonces:
Random date = DATEADD(Sales[Date]; 7 + RANDBETWEEN(-3; 3); DAY)
Podemos ver las dos columnas, la original <em>Date </em>y la recién creada <em>Random date</em>, en la siguiente imagen:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '46d7b1ed-8bab-4fc1-8789-cbe6657b8ca5') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '46d7b1ed-8bab-4fc1-8789-cbe6657b8ca5') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '46d7b1ed-8bab-4fc1-8789-cbe6657b8ca5') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '46d7b1ed-8bab-4fc1-8789-cbe6657b8ca5') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5c8295a5-d833-4a35-bf57-35e69a3f3cff') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5c8295a5-d833-4a35-bf57-35e69a3f3cff') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5c8295a5-d833-4a35-bf57-35e69a3f3cff') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5c8295a5-d833-4a35-bf57-35e69a3f3cff') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2e9813ee-d18b-47e7-bc9f-46a4586d92a6') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2e9813ee-d18b-47e7-bc9f-46a4586d92a6') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2e9813ee-d18b-47e7-bc9f-46a4586d92a6') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2e9813ee-d18b-47e7-bc9f-46a4586d92a6') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '44dad59e-f058-470f-9c22-ceb2790c4512') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '44dad59e-f058-470f-9c22-ceb2790c4512') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '44dad59e-f058-470f-9c22-ceb2790c4512') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '44dad59e-f058-470f-9c22-ceb2790c4512') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente y sencillo de resolver es aquel en el que nos encontramos con dos tablas de idéntica estructura que deseamos agregar según algún campo. Veamos cómo sería. Suponemos que ya hemos obtenido los datos y tenemos cargadas en Power BI las dos tablas que, en este caso, contienen información de ventas:
En este escenario queremos obtener el total de ventas por vendedor. Vamos a hacerlo en dos fases:
<ol><li>Unión de las tablas anteriores</li>
<li>Agregación de la tabla completa para mostrar las ventas (campo "<em>Precio final</em>") según el campo que identifica cada vendedor</li>
</ol>Para el primer paso vamos a recurrir a la función <a href="/es/dax/function/union">UNION</a>. Sin embargo, no vamos a unir las tablas directamente pues, como vemos en las imágenes anteriores, a pesar de tener la misma estructura (y, en el editor de consultas, aparecer con las columnas en el mismo orden) cuando se importan a Power BI las columnas no se muestran en el mismo orden (probablemente por un <em>bug</em> en el software que existe desde, al menos, finales de 2017). Es por ello que vamos a aplicar la función UNION a las tablas especificando a mano las columnas que nos interesan y el orden que nos interesa, para lo que recurriremos a la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Ventas totales =
VAR
Tabla1 = SELECTCOLUMNS(
Ventas1;
"Vendedor"; Ventas1[Id Vendedor];
"PVP"; Ventas1[Precio final]
)
VAR
Tabla2 = SELECTCOLUMNS(
Ventas2;
"Vendedor"; Ventas2[Id Vendedor];
"PVP"; Ventas2[Precio final]
)
RETURN
UNION(Tabla1; Tabla2)
Hemos seleccionado apenas las columnas "Vendedor" y "Precio final" (con el nombre de "PVP") pero podríamos haber seleccionado otras columnas también.
Ahora, para el segundo paso, utilizamos la función <a href="/es/dax/function/summarize">SUMMARIZE</a> para agregar la tabla anterior:
Ventas totales por vendedor =
SUMMARIZE(
'Ventas totales';
'Ventas totales'[Vendedor];
"Ventas"; SUM('Ventas totales'[PVP]
)
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '138cbae9-3a3d-4ed3-a00d-833f11d84aad') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '138cbae9-3a3d-4ed3-a00d-833f11d84aad') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '138cbae9-3a3d-4ed3-a00d-833f11d84aad') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '138cbae9-3a3d-4ed3-a00d-833f11d84aad') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb8ed33-87f4-4ba9-a994-aa7da330abeb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb8ed33-87f4-4ba9-a994-aa7da330abeb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb8ed33-87f4-4ba9-a994-aa7da330abeb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb8ed33-87f4-4ba9-a994-aa7da330abeb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '889838af-b5e8-477b-9185-7f190ec4e0c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '889838af-b5e8-477b-9185-7f190ec4e0c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '889838af-b5e8-477b-9185-7f190ec4e0c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '889838af-b5e8-477b-9185-7f190ec4e0c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario deseamos evaluar una métrica (por ejemplo, la suma de ventas) para el total de fechas previas a una dada. Partimos de una tabla de ventas ("<em>Ventas</em>") en la que se incluye una fecha ("<em>Fecha</em>") y un precio de venta ("<em>Precio final</em>"):
Adicionalmente tenemos una tabla conteniendo un calendario que, en este escenario, no está enlazado con la tabla de ventas para evitar un filtrado automático, y una visualización tipo "segmentación" en la que seleccionamos un período de interés a partir de las fechas del calendario:
Tenemos ya creada una medida que totaliza las ventas:
Ventas = SUM(Ventas[Precio final])
Como se ha comentado, el objetivo es sumar las ventas previas al período que seleccionemos en la segmentación (es decir, solo nos interesa la fecha más antigua del período seleccionado en la segmentación). En pseudo-código sería:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima de la segmentación
Como la segmentación está filtrando el calendario (pues esta visualización se ha generado a partir de él), lo anterior sería equivalente a:
Recalcula la medida "Ventas"
Para las fechas anteriores a la fecha mínima del calendario
Este esquema encaja con la estructura de la función <a href="/dax/function/calculate">CALCULATE</a>, añadiendo como filtro el contexto dado por la segunda condición:
CALCULATE(
Medida de Ventas;
Tabla de ventas tal que Ventas[Fecha] < Fecha mínima del calendario
)
Para concretar el filtrado vamos a recurrir a la función <a href="/dax/function/filter">FILTER</a>, que acepta como primer argumento una tabla y como segundo argumento un criterio de filtrado. En este caso la tabla a filtrar es la tabla de ventas y el criterio, que la fecha de venta sea menor que la menor fecha del calendario. El código quedaría de la siguiente forma:
Ventas previas = CALCULATE(
[Ventas];
FILTER(
Ventas;
Ventas[Fecha] < MIN(Calendario[Date])
)
)
Probemos el código seleccionando una fecha en el segmentador que incluya solo un par de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'dd443c51-faa1-43f9-b74e-eb5383fa640b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'dd443c51-faa1-43f9-b74e-eb5383fa640b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'dd443c51-faa1-43f9-b74e-eb5383fa640b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'dd443c51-faa1-43f9-b74e-eb5383fa640b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '87b6a972-574a-4cd6-8179-06989f49685a') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '87b6a972-574a-4cd6-8179-06989f49685a') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '87b6a972-574a-4cd6-8179-06989f49685a') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '87b6a972-574a-4cd6-8179-06989f49685a') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ac5e74e8-39a6-4d88-9205-b26e9b44abcb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ac5e74e8-39a6-4d88-9205-b26e9b44abcb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ac5e74e8-39a6-4d88-9205-b26e9b44abcb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ac5e74e8-39a6-4d88-9205-b26e9b44abcb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ea3427fa-4d8d-477d-8fbb-c48f5b3f98ef') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ea3427fa-4d8d-477d-8fbb-c48f5b3f98ef') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ea3427fa-4d8d-477d-8fbb-c48f5b3f98ef') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'ea3427fa-4d8d-477d-8fbb-c48f5b3f98ef') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '697c0c01-cd14-42e5-a082-0cd8d2ee8fee') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '697c0c01-cd14-42e5-a082-0cd8d2ee8fee') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '697c0c01-cd14-42e5-a082-0cd8d2ee8fee') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '697c0c01-cd14-42e5-a082-0cd8d2ee8fee') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una lista de localizaciones ("Geography") en la que se incluye el nombre de la ciudad y el país al que pertenece (entre otros datos):
...y una tabla de ventas ("<em>Movements</em>") en la que se incluye la fecha de venta, la ciudad a la que está asociada y el importe de venta:
Ambas tablas están relacionadas por el campo <em>Geography Id</em>:
El objetivo es añadir una columna calculada a la tabla de localizaciones en la que se muestren las ventas totales del país al que corresponde el registro.
Al crear la columna calculada se va a recorrer la tabla de localizaciones creándose el contexto de fila correspondiente. Podemos acceder al valor del campo <em>Country</em> usando la función <a href="/dax/function/earlier">EARLIER</a>, de forma que podríamos seleccionar -para cada fila recorrida- el subconjunto de la tabla de localizaciones que incluye ciudades del país en cuestión. Es decir:
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
...devolvería este subconjunto. A su vez, este subconjunto de ciudades nos permitiría filtrar la tabla de ventas mediante la función <a href="/dax/function/calculatetable">CALCULATETABLE</a>, agregando como filtro el subconjunto anterior:
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Por último, no quedaría más que recorrer esta tabla (subconjunto de la tabla de ventas) sumando el campo <em>Sales</em>:
Ventas del país =
SUMX(
CALCULATETABLE(
Movements;
FILTER(
Geography;
Geography[Country] = EARLIER(Geography[Country])
)
);
Movements[Sales]
)
El resultado sería el siguiente:
Podemos confirmar que las cifras son las correctas llevando a una visualización tipo tabla la lista de países y el campo <em>Sales</em> de la tabla de ventas:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9dd03df2-93af-4afb-8c3e-1470e7b08249') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9dd03df2-93af-4afb-8c3e-1470e7b08249') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9dd03df2-93af-4afb-8c3e-1470e7b08249') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9dd03df2-93af-4afb-8c3e-1470e7b08249') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b494e960-f8da-4194-90a9-c29257d5b500') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b494e960-f8da-4194-90a9-c29257d5b500') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b494e960-f8da-4194-90a9-c29257d5b500') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b494e960-f8da-4194-90a9-c29257d5b500') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'beb94fa3-30e6-4b52-8550-2bb981b86742') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'beb94fa3-30e6-4b52-8550-2bb981b86742') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'beb94fa3-30e6-4b52-8550-2bb981b86742') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'beb94fa3-30e6-4b52-8550-2bb981b86742') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Si tenemos una medida [Total sales] que suma los importes de ventas, podemos mostrar las ventas por categoría llevando el campo que contiene el listado de categorías, ProductCategory[Category], a un objeto visual tipo tabla junto con la medida [Total sales]:
Si añadimos una segmentación de datos conteniendo el listado de países y seleccionamos uno, vemos como nuestra tabla se filtra de forma adecuada:
Si quisiéramos calcular las ventas totales por categoría, con independencia del país o de los países que se hayan seleccionado, podríamos hacerlo asegurándonos de que el cálculo se realiza para toda la lista de países, es decir, limpiando de filtros la tabla de Geography (también podríamos limpiar los filtros aplicados al campo de la tabla Geography<em> </em>que contiene la lista de países, aunque, en este caso, las cifras devueltas por la medida podrían cambiar si se aplica un filtro a algún otro campo de la tabla). Para "limpiar" la tabla Geography de filtros usaremos la función <a href="/es/dax/function/all">ALL</a>, y para recalcular la medida [Total sales] en el nuevo contexto usaremos la función <a href="/es/dax/function/calculate">CALCULATE</a>:
Category sales =
CALCULATE(
SUM(Sales[SalesAmount]),
ALL(Geography)
)
El resultado, si llevamos la nueva medida a la tabla que habíamos creado, es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-48c7d6c1-4870-4d74-b165-caba177a4d17') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-48c7d6c1-4870-4d74-b165-caba177a4d17') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-48c7d6c1-4870-4d74-b165-caba177a4d17') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-48c7d6c1-4870-4d74-b165-caba177a4d17') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-dab86cbb-c629-45d8-9afa-ee730c81aa40') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-dab86cbb-c629-45d8-9afa-ee730c81aa40') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-dab86cbb-c629-45d8-9afa-ee730c81aa40') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-dab86cbb-c629-45d8-9afa-ee730c81aa40') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e40ca511-b94c-46b4-bc19-759574e3d53f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e40ca511-b94c-46b4-bc19-759574e3d53f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e40ca511-b94c-46b4-bc19-759574e3d53f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e40ca511-b94c-46b4-bc19-759574e3d53f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un escenario frecuente es aquel en el que queremos calcular el total acumulado, incluyendo todos los datos hasta una cierta fecha y no solo los implicados en el contexto de filtro actual. Por ejemplo, si suponemos la existencia de una tabla de ventas Sales que contiene una columna Amount con la cifra de ventas, podríamos definir una medida que calculase la suma de esta columna con la siguiente expresión DAX:
Sales = SUM(Sales[Amount])
Lógicamente, esta medida se va a adaptar al contexto de filtro, por lo que si la llevamos a una matriz en la que se esté desagregando las ventas por año:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_01.png"></a>
...vemos que, para cada año, la cifra de ventas mostrada incluye solo las ventas de dicho año.
Lo que querríamos sería que, en cada evaluación de la medida, el período temporal considerado comenzase el primer día para que el hubo ventas (supongamos que el 1 de enero de 2015) y se extendiese hasta la última fecha del "período actual". Por ejemplo, en la cifra correspondiente al año 2018 el período actual es el correspondiente a los 365 días de dicho año. Pues bien, para el cálculo del acumulado para dicho año querríamos que se considerase el período comprendido entre el 1 de enero de 2015 y el 31 de diciembre de 2018. Es decir, escrito en pseudo-código:
Accumulated sales =
CALCULATE(
[Sales],
Período entre la primera fecha disponible y la última fecha del contexto actual
)
El período en cuestión puede calcularse usando la función <a href="/es/dax/function/datesbetween">DATESBETWEEN</a> que devuelve el conjunto de fechas entre dos dadas. Si el calendario está contenido en la tabla Calendar, tendríamos, por lo tanto, que codificar la siguiente medida:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
Primera fecha disponible,
Última fecha del contexto actual
)
)
Ahora bien, es el cálculo de esas dos fechas lo que resulta más complejo, pues queremos que la primera fecha ("<em>Primera fecha disponible</em>") sea absoluta y haga referencia a la primera fecha disponible en el calendario, mientras que la segunda ("<em>Última fecha del contexto actual</em>") queremos que se adapte al contexto.
Para la obtención de la primera fecha disponible en el calendario deberemos asegurarnos de que no se están aplicando filtros al mismo, para lo que podemos usar la función <a href="/es/dax/function/all">ALL</a> (lo que va a devolver una tabla). Y para la extracción de la primera fecha disponible de dicha tabla no podemos usar la función <a href="/es/dax/function/min">MIN</a> pues ésta exige una columna como argumento, de forma que tendremos que usar la función <a href="/es/dax/function/firstdate">FIRSTDATE</a>, que sí acepta una tabla como argumento y devuelve otra tabla (con la fecha más antigua disponible), tabla que podemos pasar a la función <a href="/es/dax/function/calculate">CALCULATE</a> como argumento de filtro:
FIRSTDATE(ALL(Sales[Order Date]))
Para el cálculo de la última fecha del contexto actual no tenemos más que utilizar la función <a href="/es/dax/function/max">MAX</a> pasando como argumento la columna temporal que está desagregando nuestro objeto visual: la columna 'Calendar'[Date]. Es decir, la última fecha del contexto actual vendría dada por:
MAX('Calendar'[Date])
Es decir, la expresión
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
...va a devolver el conjunto de fechas del calendario entre la más antigua disponible y la última implicada en el contexto actual. Podemos escribir, por lo tanto, la medida que devuelve las ventas acumuladas:
Accumulated sales =
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL(Sales[Order Date])),
MAX('Calendar'[Date])
)
)
Si quisiéramos utilizar variables para hacer más legible el código, podríamos crear dos variables, __firstdate y __lastDate conteniendo las dos fechas implicadas en el código anterior:
Accumulated sales =
VAR __firstDate = FIRSTDATE(ALL(Sales[Order Date]))
VAR __lastDate = MAX('Calendar'[Date])
RETURN
CALCULATE(
[Sales],
DATESBETWEEN(
'Calendar'[Date],
__firstDate,
__lastDate
)
)
Ahora, si llevamos la medida anterior a nuestra matriz, comprobamos que se están acumulando las ventas tal y como queríamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_02.png"></a>
Y, por supuesto, si mostramos la matriz desagregada por cualquier otro nivel de nuestra jerarquía temporal, por trimestres, por ejemplo, el cálculo de las ventas acumuladas sigue realizándose correctamente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-01/dax_scenario_calculo_totales_03.png"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e3def38f-234a-46ca-9d2c-af05d08c3f86') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e3def38f-234a-46ca-9d2c-af05d08c3f86') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e3def38f-234a-46ca-9d2c-af05d08c3f86') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-e3def38f-234a-46ca-9d2c-af05d08c3f86') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-399492ec-c31f-4b47-ab0f-908beb07d754') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-399492ec-c31f-4b47-ab0f-908beb07d754') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-399492ec-c31f-4b47-ab0f-908beb07d754') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-399492ec-c31f-4b47-ab0f-908beb07d754') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-35575ed9-54ba-4c8c-8bfe-1341d2c9b89f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-35575ed9-54ba-4c8c-8bfe-1341d2c9b89f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-35575ed9-54ba-4c8c-8bfe-1341d2c9b89f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-35575ed9-54ba-4c8c-8bfe-1341d2c9b89f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Supongamos que estamos mostrando las ventas por mes usando la siguiente medida:
Sales = SUM(Sales[Amount])
(obviamente el campo que contiene el montante de cada venta es el campo <em>Amount</em> de la tabla <em>Sales</em>)
Y las ventas del mes anterior con la siguiente medida:
PM Sales =
CALCULATE(
[Sales],
DATEADD('Calendar'[Date], -1, MONTH)
)
El resultado de llevar ambas medidas a una matriz mostrando por filas los meses es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0077.jpg"></a>
Ahora queremos calcular el incremento de un mes para el siguiente, para lo que creamos una nueva medida:
MoM Sales = [Sales] - [PM Sales]
Si la llevamos a nuestra matriz obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0078.jpg"></a>
Vemos cómo esta última medida devuelve valores incluso cuando alguna de las dos medidas anteriores tomen un valor nulo, como ocurre en enero de 2015, mes para el que hay ventas pero, por ser el primer mes de la serie histórica, no tiene un valor asociado para el mes anterior. En estas circunstancias podríamos preferir que nuestra medida <em>MoM Sales</em> no devolviese ningún valor, lo que podemos conseguir fácilmente usando la función <a href="https://www.interactivechaos.com/dax/function/and">AND</a> y comprobando si las dos medidas en las que se basa toman valores no nulos.
Concretamente, la expresión
AND([Sales], [PM Sales])
...comprueba si ambos valores son no nulos, y devuelve el booleano <em>True</em> en caso positivo (si no son nulos) o <em>False</em> en caso opuesto (si alguno es nulo), lo que nos permite reescribir nuestra medida <em>MoM Sales</em> para que solo devuelva un valor si se cumple dicha condición:
MoM Sales =
IF(
AND([Sales], [PM Sales]),
[Sales] - [PM Sales]
)
Ahora, nuestra matriz muestra el aspecto deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-05/dax-0079.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04f04b66-88c9-446b-90e2-327c78cd4142') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04f04b66-88c9-446b-90e2-327c78cd4142') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04f04b66-88c9-446b-90e2-327c78cd4142') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04f04b66-88c9-446b-90e2-327c78cd4142') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-45f4f9d9-a89a-44c9-999a-e86f49967944') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-45f4f9d9-a89a-44c9-999a-e86f49967944') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-45f4f9d9-a89a-44c9-999a-e86f49967944') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-45f4f9d9-a89a-44c9-999a-e86f49967944') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-f88cb230-f0de-458d-9388-ef753ced4737') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-f88cb230-f0de-458d-9388-ef753ced4737') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-f88cb230-f0de-458d-9388-ef753ced4737') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-f88cb230-f0de-458d-9388-ef753ced4737') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-23c459c9-da03-4a99-8587-a1b4104ad45b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-23c459c9-da03-4a99-8587-a1b4104ad45b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-23c459c9-da03-4a99-8587-a1b4104ad45b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-23c459c9-da03-4a99-8587-a1b4104ad45b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla en la que se incluye información de los cambios de una cierta métrica por día. Por ejemplo, supongamos que se trata de las variaciones en la cantidad de cierto producto que hay en nuestro almacén. En este ejemplo la tabla se llama <em>data</em> y los dos campos que contiene son <em>Fecha</em> y <em>Movimientos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0090.jpg"></a>
Obsérvese que la tabla incluye el último día del año 2019 aun cuando en este escenario queremos trabajar únicamente con el año 2020. Explicaré más adelante el motivo de comenzar la tabla por esta fecha.
El objetivo es calcular el estado de nuestro almacén a comienzo de cada mes (o de cada trimestre, o de cada año).
Para esto, tras leer los datos desde Power BI vamos a calcular una medida base que simplemente sume el campo <em>Movimientos</em> (para el contexto en el que nos encontremos en cada momento):
Quantity = SUM(data[Movimientos])
Hacemos esto para evitar tener que sumar dicho campo cada vez que necesitemos realizar este cálculo en futuras medidas.
Ahora podemos calcular el total acumulado de nuestros movimientos. Para esto vamos a crear una medida que sume <em>Quantity</em> desde el comienzo de los tiempos hasta "la fecha actual" (hasta la fecha máxima de cada contexto de cálculo). Todas las <a href="https://www.interactivechaos.com/recursos-educativos/funciones-dax?title=&field_funcion_dax_categoria_value%5B%5D=Funciones+de+inteligencia+de+tiempo">funciones DAX de inteligencia de tiempo</a> requieren un calendario que sirva de referencia. Si tenemos una tabla con este calendario, estupendo. Si no, podemos crear una tabla calculada con la función <a href="https://www.interactivechaos.com/dax/function/calendarauto">CALENDARAUTO</a>. Supongamos que llamamos a esta nueva tabla <em>Calendar</em>:
Calendar = CALENDARAUTO()
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0091.jpg"></a>
Una vez creada esta tabla no debemos olvidar crear una relación entre el recién creado campo <em>Calendar[Date]</em> y el campo <em>Data[Fecha]</em>.
La medida que calcula el acumulado de nuestra medida <em>Quantity</em> (acumulado "hasta la fecha actual") es la siguiente:
Accumulated Quantity =
CALCULATE(
[Quantity],
DATESBETWEEN(
'Calendar'[Date],
FIRSTDATE(ALL('Calendar'[Date])),
LASTDATE('Calendar'[Date])
)
)
Básicamente estamos recalculando la medida <em>Quantity</em> (para lo que usamos la función <a href="https://www.interactivechaos.com/dax/function/calculate">CALCULATE</a>) en un nuevo contexto: aquel formado por todas las fechas entre la primera que encontremos en el calendario (usando la función <a href="https://www.interactivechaos.com/dax/function/firstdate">FIRSTDATE</a>) y la última fecha "del contexto actual" (usando la función <a href="https://www.interactivechaos.com/dax/function/lastdate">LASTDATE</a>). Obsérvese el uso de la función <a href="https://www.interactivechaos.com/dax/function/all">ALL</a> como argumento de FIRSTDATE: es lo que nos permite asegurar que estamos extrayendo el primer día de todo el calendario, y no el primer día del contexto actual.
Podemos crear una tabla en el lienzo de Power BI para ver el resultado hasta ahora:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0092.jpg"></a>
A la tabla anterior se ha llevado el campo <em>Calendar[Date]</em> y las medidas <em>Quantity</em> y <em>Accumulated Quantity</em>, y, tal y como se muestra en la imagen, se ha filtrado de forma que solo muestre fechas a partir del 1 de enero de 2020.
Por último, no tenemos más que calcular, para cada fecha, el valor de la medida con el acumulado <em>el primer día del mes correspondiente</em>. Para esto podemos usar la función <a href="https://www.interactivechaos.com/dax/function/openingbalancemonth">OPENINGBALANCEMONTH</a> (o las funciones equivalentes <a href="https://www.interactivechaos.com/dax/function/openingbalancequarter">OPENINGBALANCEQUARTER</a> y <a href="https://www.interactivechaos.com/dax/function/openingbalanceyear">OPENINGBALANCEYEAR</a> si quisiéramos calcular dicho acumulado el primer día de cada trimestre o de cada año):
Quantity First Day of Month =
OPENINGBALANCEMONTH(
[Accumulated Quantity],
'Calendar'[Date]
)
Con esta medida estamos asociando a cada fecha (a cada contexto temporal, en realidad, sea de un día o no) la cifra de <em>Accumulated Quantity</em> del primer día del mes al que pertenece dicha fecha. Si llevamos esta medida a nuestra tabla obtenemos el siguiente resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-07/dax-0093.jpg"></a>
En la imagen anterior (que solo muestra la tabla entre el 1 de enero y el 5 de febrero) vemos que a cualquier día del mes de enero se asocia el valor 0 (acumulado a principio de dicho mes) y que a cualquier día de febrero se asocia el valor 21 (acumulado a principio de dicho mes). Y éste es el motivo de haber comenzado nuestra tabla de movimientos por el día 31 de diciembre de 2019: la función OPENINGBALANCEMONTH devuelve, en realidad, el valor de la métrica de que se trate <em>antes del primer día del mes correspondiente</em> -lo que tiene mucha lógica-: si el primer día de mi tabla (supongamos que es el 1 de enero) tengo un incremento de +2 (por ejemplo), la cifra acumulada a principio de dicho mes era de 0 (la cifra correspondiente al final del 31 de diciembre). De igual forma, si a finales de enero el total acumulado era de 21, con independencia del incremento que se produzca el 1 de febrero, el total acumulado <em>a principios de febrero</em> era de 21 (es decir, la cifra del último día de enero).
Si no hubiésemos incluido la fecha del 31 de diciembre, todos los días de enero habrían recibido como total acumulado a principio de mes el valor 127, que es la suma total de la columna <em>Quantity</em>, sencillamente porque no habría un <em>día del mes anterior</em> para hacer el cálculo y DAX, por diseño, consideraría toda la tabla.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b61fe087-d3d8-4380-91bb-c1f556178ac0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b61fe087-d3d8-4380-91bb-c1f556178ac0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b61fe087-d3d8-4380-91bb-c1f556178ac0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'b61fe087-d3d8-4380-91bb-c1f556178ac0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '91048b56-9864-408e-b66b-e30f09799deb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '91048b56-9864-408e-b66b-e30f09799deb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '91048b56-9864-408e-b66b-e30f09799deb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '91048b56-9864-408e-b66b-e30f09799deb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a3f6c097-0ac4-40e9-bade-3ad0519a03ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a3f6c097-0ac4-40e9-bade-3ad0519a03ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a3f6c097-0ac4-40e9-bade-3ad0519a03ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a3f6c097-0ac4-40e9-bade-3ad0519a03ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla calendario en la que se incluyen campos para el año y el número de mes:
El objetivo es añadir una columna con el año fiscal y otra con el mes fiscal. Para esto vamos a suponer que el mes en el que termina el año fiscal es marzo (tercer mes del año), lo que podremos modificar en cada bloque de código fácilmente.
Para el cálculo del año fiscal vamos a comparar el mes incluido en cada fila con el mes en el que termina el año fiscal: si es superior, sumaremos 1 al valor del año:
FY =
VAR
UltimoMes = 3
RETURN
'Calendar'[Año] +
IF(
MONTH('Calendar'[Date]) > UltimoMes;
1;
0
)
En el código anterior definimos la variable "UltimoMes" con el valor correspondiente al último mes del año fiscal (3) usando la función <a href="/dax/function/var">VAR</a>, y devolvemos el valor del campo <em>Año</em> sumándole 1 o no en función de que el mes de la fecha sea o no superior al último mes del año fiscal. Para esto extraemos el mes de la fecha con la función <a href="/dax/function/month">MONTH</a> y realizamos la comparación con <a href="/dax/function/if">IF</a>. En la imagen anterior se muestran fechas de marzo y abril para ver el salto de un período al otro.
Un par de notas interesantes: Los nombres de las variables no pueden contener espacios, guiones, vocales acentuadas... de ahí el nombre de "UltimoMes". Y observa que es posible incrustar una función (IF, en este caso) donde se espera un valor númerico (siempre que la función devuelva un valor adecuado).
Para añadir el mes fiscal, podemos restar al mes de la fecha (que extraeremos con la función <a href="/dax/function/month">MONTH</a>) el último mes del año fiscal. Esto devolverá un número positivo para los meses posteriores a éste (abril = 1, mayo = 2...), pero un número negativo o cero para los anteriores (enero = -2, febrero = -1 y marzo = 0). Para solucionar esto podemos simplemente calcular el módulo de la resta y 12 usando la función <a href="/dax/function/mod">MOD</a> y sumando 1 al resultado (el módulo devolverá cero para marzo, por ejemplo):
FM =
VAR
UltimoMes = 3
RETURN
MOD(MONTH('Calendar'[Date]) - UltimoMes; 12) + 1
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb9f4ae-e4af-4486-9175-e93ad731a82b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb9f4ae-e4af-4486-9175-e93ad731a82b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb9f4ae-e4af-4486-9175-e93ad731a82b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '7eb9f4ae-e4af-4486-9175-e93ad731a82b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '8bbd8758-9ff2-4813-90aa-fae48f39077d') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '8bbd8758-9ff2-4813-90aa-fae48f39077d') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '8bbd8758-9ff2-4813-90aa-fae48f39077d') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '8bbd8758-9ff2-4813-90aa-fae48f39077d') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f3aa1909-9a3f-40ee-876d-9106416dedb9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f3aa1909-9a3f-40ee-876d-9106416dedb9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f3aa1909-9a3f-40ee-876d-9106416dedb9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'f3aa1909-9a3f-40ee-876d-9106416dedb9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de productos:
...y de un listado de ventas de estos productos, incluyendo el número de unidades de cada uno involucrados en las ventas:
Como puede apreciarse, esta información está, en este caso, almacenada en ficheros Excel. Una vez importadas ambas tablas con los nombres de "Productos" y "Ventas" respectivamente, y una vez confirmado que se crea la relación entre ambas tomando el campo "Id Producto" como clave, querríamos añadir a la tabla de productos, una columna calculada con el valor máximo de unidades involucradas en las ventas de cada producto. Así, por ejemplo, en la imagen anterior vemos que el producto 3 ha sido vendido dos veces, la primera involucrando 6 unidades, y la segunda involucrando 11, por lo que querríamos obtener el número 11 como valor máximo encontrado.
Para esto vamos a recorrer la tabla de productos buscando, para cada uno de ellos, el valor máximo en cuestión. En pseudo-código sería lo siguiente:
Para cada uno de los productos:
= Obtén la lista de ventas de dicho producto y quédate con el valor máximo del campo "Unidades"
Si conseguimos obtener la lista de ventas de cada producto, la función que nos permitiría recorrer dicha lista y extraer un valor máximo es <a href="/dax/function/maxx">MAXX</a>. Esta función permite especificar una tabla (la de ventas de cada producto en nuestro caso) y una expresión que se evaluará para todas las filas de la misma (simplemente el número de unidades involucradas en nuestro ejemplo), devolviéndose el valor máximo encontrado. Ahora, para cada fila recorrida el pseudo-código sería el siguiente:
= MAXX(
Lista de ventas del producto considerado en la fila; // Obtiene el valor máximo de esta tabla...
Unidades // Según este criterio
)
La obtención de la lista de ventas asociada a cada producto también es sencilla: estamos recorriendo la tabla de productos, por lo que, para cada uno de ellos, el campo "Id Producto" nos permitiría filtrar la tabla de ventas adecuadamente usando la función <a href="/dax/function/filter">FILTER</a>. En nuestro caso, la expresión a usar sería la siguiente:
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto])
Estaríamos filtrando la tabla "Ventas" para incluir solo las ventas asociadas al producto "Id Producto".
El código final sería el siguiente:
Max Unidades Vendidas =
MAXX(
FILTER(Ventas; Ventas[Id Producto] = Productos[Id Producto]);
Ventas[Unidades]
)
Y el resultado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '6e7ea336-e513-4349-a3ec-f7cc14d9cd1b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '6e7ea336-e513-4349-a3ec-f7cc14d9cd1b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '6e7ea336-e513-4349-a3ec-f7cc14d9cd1b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '6e7ea336-e513-4349-a3ec-f7cc14d9cd1b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '61138555-e1c0-45a5-9bbb-dcefc4489cf9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '61138555-e1c0-45a5-9bbb-dcefc4489cf9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '61138555-e1c0-45a5-9bbb-dcefc4489cf9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '61138555-e1c0-45a5-9bbb-dcefc4489cf9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'c7517dfc-1136-438b-b5c4-736188acc9ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'c7517dfc-1136-438b-b5c4-736188acc9ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'c7517dfc-1136-438b-b5c4-736188acc9ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'c7517dfc-1136-438b-b5c4-736188acc9ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bd8c8912-3173-4504-886e-057331c10f2a') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bd8c8912-3173-4504-886e-057331c10f2a') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bd8c8912-3173-4504-886e-057331c10f2a') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bd8c8912-3173-4504-886e-057331c10f2a') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98f6ede6-aae6-4e3b-89fa-9826e897310c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98f6ede6-aae6-4e3b-89fa-9826e897310c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98f6ede6-aae6-4e3b-89fa-9826e897310c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '98f6ede6-aae6-4e3b-89fa-9826e897310c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de un listado de ventas (Sales) en el que se indica -por ejemplo- el identificador de cliente y las fechas de las compras:
El objetivo es añadir a esta tabla una columna que indique el número de días transcurridos desde la compra anterior (anterior en el tiempo, pues nada nos asegura que el orden de los datos en la tabla original sea cronológico, y ya sabemos que Power BI tampoco asegura el orden de las filas).
La resolución de este escenario no es sencilla. Aun cuando podría resolverse en una única expresión, se plantea a continuación su resolución paso a paso. Las fases involucradas son las siguientes:
<ol><li>Es necesario obtener, para cada fecha de compra del cliente X, la fecha de la anterior compra.</li>
<li>La anterior fecha de compra es la mayor fecha de todas las compras del cliente X (exceptuando la compra que estemos analizando, por supuesto).</li>
<li>Podemos obtener todas las compras anteriores del cliente X realizando una combinación cruzada de la tabla consigo misma tomando como campo común el correspondiente al identificador del cliente y considerando en la tabla de la derecha (véase la documentación de la función <a href="/es/dax/function/generate">GENERATE</a>) solo las fechas anteriores a la de la fecha de compra siendo considerada en la tabla izquierda. Así, por ejemplo, para la compra que aparece en la tercera línea de la imagen anterior (correspondiente al cliente 1, con fecha de 21 de enero de 2019), una combinación cruzada con la misma tabla en las condiciones mencionadas devolvería una fila para la combinación de la fila 3 y la fila 1 (mismo cliente y fecha anterior) y otra para la combinación de la fila 3 y la fila 2 (de nuevo, mismo cliente y fecha anterior).</li>
</ol>Por último, una vez obtenida la tabla mencionada en el punto 1, bastaría calcular la diferencia entre cada fecha de compra y la fecha de la última compra.
Vamos punto por punto.
En primer lugar queremos obtener, para cada fila (es decir, para cada compra), el conjunto de compras anteriores del mismo cliente. Esto, como se ha comentado, puede lograrse con una combinación cruzada que nos permita especificar las condiciones de la combinación, es decir, con la función <a href="/es/dax/function/generate">GENERATE</a>. Como esta función requiere que las tablas involucradas en la combinación tengan campos con nombres diferentes, vamos modificar los nombres de los campos de la segunda copia con la función <a href="/es/dax/function/selectcolumns">SELECTCOLUMNS</a>, añadiendo un símbolo "_" al final de los nombres:
SelfJoin =
GENERATE(
Sales;
FILTER(
SELECTCOLUMNS(
Sales;
"Customer_"; Sales[Customer];
"Purchase Date_"; Sales[Purchase Date]
);
[Purchase Date_] < Sales[Purchase Date] && Sales[Customer] = [Customer_]
)
)
Tal y como se ve, estamos obteniendo la combinación cruzada imponiendo la condición de que el identificador de cliente sea el mismo, y que las fechas de la columna de la derecha sean inferiores a la fecha considerada en cada una de las filas de la izquierda (para simplificar, estamos suponiendo que un mismo cliente no va a realizar dos compras el mismo día).
Obsérvese que no aparecen los registros de la primera tabla para los que no hay registros en la segunda que cumplan las condiciones impuestas (es decir, en la tabla que acabamos de crear, solo se incluyen fechas de compra para las que hay alguna compra anterior).
Obtener, a partir de aquí, la fecha anterior a cada compra es fácil: basta con agrupar (con la función <a href="/es/dax/function/groupby">GROUPBY</a>) por cliente y fecha de compra (campos <em>Customer</em> y <em>Purchase Date</em>) y seleccionar el valor máximo (de cada grupo) del campo <em>Purchase Date_</em>:
LastPurchases =
GROUPBY(
SelfJoin;
SelfJoin[Customer];
SelfJoin[Purchase Date];
"Last Purchase"; MAXX(
CURRENTGROUP();
SelfJoin[Purchase Date_]
)
)
Ahora viene un proceso un tanto complicado: como en la tabla solo se incluyen fechas de compra para las que existe una compra anterior, para que en el resultado final aparezcan todas las fechas originales tendríamos que realizar una combinación externa izquierda entre la tabla de fechas original y la nueva. Para esto tendríamos que usar la función <a href="/es/dax/function/naturalleftouterjoin">NATURALLEFTOUTERJOIN</a>, pero esta función exige que las tablas a combinar tengan la misma ascendencia (procedan de la misma fuente), lo que no se cumple en nuestro caso. Tal y como se explica en la <a href="/es/dax/function/naturalleftouterjoin">documentación de esta función</a>, es posible resolver este problema añadiendo una cadena de texto vacía al final de los nombres:
Purchase and Last Purchase =
NATURALLEFTOUTERJOIN(
SELECTCOLUMNS(
Sales;
"Customer"; Sales[Customer] & "";
"Purchase Date"; Sales[Purchase Date] & ""
);
SELECTCOLUMNS(
LastPurchases;
"Customer"; LastPurchases[SelfJoin_Customer] & "";
"Purchase Date"; LastPurchases[SelfJoin_Purchase Date] & "";
"Last Purchase"; LastPurchases[Last Purchase]
)
)
Por último, para calcular el número de días desde la última compra basta con añadir una nueva columna que devuelva la diferencia (solo si existe una última compra):
Days since last purchase =
ADDCOLUMNS(
'Purchase and Last Purchase';
"# days";
VAR
NumberOfDays =
'Purchase and Last Purchase'[Purchase Date] -
'Purchase and Last Purchase'[Last Purchase]
RETURN
IF(
ISBLANK('Purchase and Last Purchase'[Last Purchase]);
BLANK();
NumberOfDays
)
)
Para devolver la diferencia de días comentada utilizamos la función <a href="/es/dax/function/if">IF</a> para confirmar si el valor del campo correspondiente a la última compra es un BLANK o no, para lo que utilizamos la función <a href="/es/dax/function/isblank">ISBLANK</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-26f2094f-6fc5-4d8f-9cc2-da5576c21073') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-26f2094f-6fc5-4d8f-9cc2-da5576c21073') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-26f2094f-6fc5-4d8f-9cc2-da5576c21073') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-26f2094f-6fc5-4d8f-9cc2-da5576c21073') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5b76a210-02d1-4484-a8b9-c3a70422d70c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5b76a210-02d1-4484-a8b9-c3a70422d70c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5b76a210-02d1-4484-a8b9-c3a70422d70c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5b76a210-02d1-4484-a8b9-c3a70422d70c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-08e7a98a-1bb0-4e89-bba5-5402a6b3a4c0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-08e7a98a-1bb0-4e89-bba5-5402a6b3a4c0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-08e7a98a-1bb0-4e89-bba5-5402a6b3a4c0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-08e7a98a-1bb0-4e89-bba5-5402a6b3a4c0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3cb7ced5-598b-408d-9d7d-d253ab959bba') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3cb7ced5-598b-408d-9d7d-d253ab959bba') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3cb7ced5-598b-408d-9d7d-d253ab959bba') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3cb7ced5-598b-408d-9d7d-d253ab959bba') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0110.jpg"></a>
Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.
El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).
Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo <em>Id</em> 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, <em>Id</em> y <em>Date</em>. A partir del valor del campo <em>Date</em> querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.
En pseudo código sería algo así:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < fecha-de-la-fila-actual
)
)
Se ha utilizado la etiqueta <em>fecha-de-la-fila-actual</em> para hacer referencia al valor del campo <em>Date</em> de la fila siendo considerada.
La función <a href="/es/dax/function/filter">FILTER</a>, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla <em>data</em>:
data[Date] < fecha-de-la-fila-actual
Lógicamente, el siguiente código no funcionaría:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < data[Date])
)
)
...pues dentro del contexto de fila creado por <a href="/es/dax/function/filter">FILTER</a>, el valor de <em>data[Date]</em> es el valor del campo <em>Date</em> de la fila que <a href="/es/dax/function/filter">FILTER</a> esté iterando. Lo que querríamos es que el valor de <em>fecha-de-la-fila-actual</em> fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función <a href="/es/dax/function/filter">FILTER</a>.
Para ello tenemos dos soluciones:
La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función <a href="/es/dax/function/earlier">EARLIER</a>. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:
Number of Previous values =
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0111.jpg"></a>
Vemos que, para la primera fila, la función devuelve un <em>Blank</em> pues no hay filas con fechas anteriores y la función <a href="/es/dax/function/countrows">COUNTROWS</a> devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función <a href="/es/dax/function/coalesce">COALESCE</a>:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0112.jpg"></a>
En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función <a href="/es/dax/function/earliest">EARLIEST</a> que nos devuelve el valor del campo indicado en el último contexto de fila existente:
Number of Previous values =
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIEST(data[Date])
)
),
0
)
El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
)
En primer lugar creamos una variable (<em>__currentDate</em>) con la palabra reservada <a href="/es/dax/function/var">VAR</a>. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo <em>data[Date]</em> toma el valor del campo <em>Date</em> en la fila que se esté evaluando.
Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla <em>data</em>. Tal y como se ha comentado, la función <a href="/es/dax/function/filter">FILTER</a> crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo <em>Date</em> -evaluado en el contexto de fila de la función <a href="/es/dax/function/filter">FILTER</a>- con el valor registrado en la variable <em>__currentDate</em> (valor que se registró en el contexto de fila de la columna calculada):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2021-06/dax-0113.jpg"></a>
Comprobamos que el resultado es el mismo que obtuvimos con la función <a href="/es/dax/function/earlier">EARLIER</a> pero más fácil de interpretar.
Una vez más, podríamos usar la función <a href="/es/dax/function/coalesce">COALESCE</a> para forzar ceros allí donde <a href="/es/dax/function/countrows">COUNTROWS</a> devuelva <em>Blanks</em>:
Number of Previous values =
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2b6e74a4-1aaa-4448-b6f3-018249d85a2e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2b6e74a4-1aaa-4448-b6f3-018249d85a2e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2b6e74a4-1aaa-4448-b6f3-018249d85a2e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '2b6e74a4-1aaa-4448-b6f3-018249d85a2e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '28eeb081-03c0-4a9e-a2ca-62575e0c2f0f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '28eeb081-03c0-4a9e-a2ca-62575e0c2f0f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '28eeb081-03c0-4a9e-a2ca-62575e0c2f0f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '28eeb081-03c0-4a9e-a2ca-62575e0c2f0f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a078d921-b097-4d8d-b0ad-cc0336356343') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a078d921-b097-4d8d-b0ad-cc0336356343') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a078d921-b097-4d8d-b0ad-cc0336356343') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'a078d921-b097-4d8d-b0ad-cc0336356343') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '16b99db9-6e42-49ab-a76c-4b16388c1658') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '16b99db9-6e42-49ab-a76c-4b16388c1658') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '16b99db9-6e42-49ab-a76c-4b16388c1658') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '16b99db9-6e42-49ab-a76c-4b16388c1658') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario tenemos un conjunto de productos, las ventas y un listado de países en los que se han realizado las ventas. Y queremos calcular, para cada producto, las ventas del país en el que éstas hayan sido mayores.
Comencemos viendo las ventas por país. Para esto llevamos a una matriz el campo conteniendo el nombre de cada producto (<em>Product[ProductName]</em>) a filas y el campo conteniendo los países (<em>Geography[Country]</em>) a columnas:
Comprobamos cómo, por ejemplo, el valor máximo de ventas para el producto "<em>All-Purpose Bike Stand</em>" (el primero de la lista) es de 13.515€ -cifra correspondiente a los Estados Unidos-. Lo que deseamos, por lo tanto, es un listado de los productos acompañado, cada uno de ellos, por el valor máximo de sus ventas en el país que sea.
La función <a href="/dax/function/maxx">MAXX </a>recorre una tabla evaluando, para cada fila, una expresión y escogiendo el valor máximo de los resultados obtenidos. En nuestro caso, para cada producto, querríamos recorrer una tabla de países evaluando las ventas totales del producto del que se trate en cada país. Algo como:
MAXX(<listado-de-países>; <ventas>)
El listado de países lo podemos obtener a partir del campo que contiene los países en los que se realizan las ventas utilizando la función <a href="/dax/function/values">VALUES </a>que extrae los valores del mismo:
VALUES(Geography[Country]
Por último, si tenemos una medida <em>Sales</em> que sume el campo de ventas, podríamos obtener el resultado buscado con la medida:
Product max sales = MAXX(VALUES(Geography[Country]); [Sales])
En esta expresión, recorremos una tabla creada dinámicamente conteniendo el listado de países (<em>VALUES(Geography[Country])</em>) evaluando, para cada fila, la expresión <em>[Sales]</em>. Esta medida se contextualiza para cada fila devolviendo solo las ventas de cada país. El resultado, si lo llevásemos a una tabla, sería:
La medida <em>Product max sales</em>, si la llevásemos directamente a una visualización tipo <em>tarjeta</em>, mostraría el valor máximo de este listado de ventas:
Ahora bien, cuando llevemos esta medida a una tabla, también va a contextualizarse. Por ejemplo, si en dicha tabla tenemos un listado de productos, la tabla de países creada dinámicamente incluirá solo las ventas por país para dicho producto, y el valor máximo calculado por MAXX será el correspondiente solo a dicho producto.
Por lo tanto, basta crear una tabla con el listado de productos y esta medida para obtener el resultado deseado:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '604fe7cf-ded3-4023-ae2b-8e849cc091b5') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '604fe7cf-ded3-4023-ae2b-8e849cc091b5') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '604fe7cf-ded3-4023-ae2b-8e849cc091b5') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '604fe7cf-ded3-4023-ae2b-8e849cc091b5') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0850870a-4ac3-49b7-a664-1d92969c95ac') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0850870a-4ac3-49b7-a664-1d92969c95ac') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0850870a-4ac3-49b7-a664-1d92969c95ac') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '0850870a-4ac3-49b7-a664-1d92969c95ac') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '3eb731fa-4fc4-4f0b-9a07-593e057b732b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '3eb731fa-4fc4-4f0b-9a07-593e057b732b') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '3eb731fa-4fc4-4f0b-9a07-593e057b732b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '3eb731fa-4fc4-4f0b-9a07-593e057b732b') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Podemos encontrarnos con el caso de que, por cualquier motivo, el fichero (suponiendo que se trate de uno solo) que alimenta nuestro informe Power BI cambie de nombre o se mueva a una nueva localización. En un caso así veremos que, al intentar actualizar los datos, Power BI nos muestra un mensaje de error:
Este problema tiene una sencilla solución: tras cerrar la ventana anterior, y suponiendo que estemos en la vista de informe o de datos, hacemos clic derecho en el nombre de alguna de las consultas (en la columna <em>Campos</em> que tenemos en el extremo derecho de la interfaz) y hacemos clic en la opción <em>Editar consulta</em>, lo que provocará que se abra el editor de consultas. Seleccionamos cualquiera de las consultas en la columna <em>Consultas</em> que se muestra a la izquierda y hacemos clic en el paso <em>Origen</em> que se muestra en la parte superior del conjunto de transformaciones a aplicar a esta consulta, en el extremo derecho de la pantalla:
A continuación, hacemos clic en el icono que se muestra a la derecha de la etiqueta <em>Origen</em> (el icono con aspecto de flor o de tuerca, depende de nuestro estado de ánimo). Esto abrirá una ventana cuyo contenido dependerá del tipo de fuente de datos de que se trate. En todo caso, podremos reconfigurar dicha fuente de datos lo que significa que, si se trata de un fichero Excel, por ejemplo, podremos recorrer nuestro disco duro buscando el fichero correcto:
Una vez encontrado el fichero, hacemos clic en el botón <em>Aceptar</em> que se muestra en la misma ventana, y otro clic en el botón de <em>Inicio > Cerrar y aplicar</em> para volver a la interfaz principal de Power BI con la consulta ya modificada.', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9016ada0-c23b-4f3a-9f90-baed27bfbede') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9016ada0-c23b-4f3a-9f90-baed27bfbede') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9016ada0-c23b-4f3a-9f90-baed27bfbede') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9016ada0-c23b-4f3a-9f90-baed27bfbede') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-da07c2cd-781c-4498-99c5-ae1268dfedc7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-da07c2cd-781c-4498-99c5-ae1268dfedc7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-da07c2cd-781c-4498-99c5-ae1268dfedc7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-da07c2cd-781c-4498-99c5-ae1268dfedc7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5bd7eda1-4b9a-4b3d-a94c-2aac29e3ba9d') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5bd7eda1-4b9a-4b3d-a94c-2aac29e3ba9d') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5bd7eda1-4b9a-4b3d-a94c-2aac29e3ba9d') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-5bd7eda1-4b9a-4b3d-a94c-2aac29e3ba9d') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d7ba40cb-dc01-44b3-b5fe-c30e201170cf') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d7ba40cb-dc01-44b3-b5fe-c30e201170cf') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d7ba40cb-dc01-44b3-b5fe-c30e201170cf') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d7ba40cb-dc01-44b3-b5fe-c30e201170cf') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-7fc1cafc-e2c1-450c-8262-aabd0fc9bc07') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-7fc1cafc-e2c1-450c-8262-aabd0fc9bc07') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-7fc1cafc-e2c1-450c-8262-aabd0fc9bc07') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-7fc1cafc-e2c1-450c-8262-aabd0fc9bc07') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3b4d3fbb-bba0-4819-b6f9-e5dd0ffb343f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3b4d3fbb-bba0-4819-b6f9-e5dd0ffb343f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3b4d3fbb-bba0-4819-b6f9-e5dd0ffb343f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-3b4d3fbb-bba0-4819-b6f9-e5dd0ffb343f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6dd2737f-9cb0-49d2-8d60-d0246e5d4689') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6dd2737f-9cb0-49d2-8d60-d0246e5d4689') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6dd2737f-9cb0-49d2-8d60-d0246e5d4689') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6dd2737f-9cb0-49d2-8d60-d0246e5d4689') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d6e78bb0-18ba-410b-81e2-b14e9c8533d9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d6e78bb0-18ba-410b-81e2-b14e9c8533d9') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d6e78bb0-18ba-410b-81e2-b14e9c8533d9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d6e78bb0-18ba-410b-81e2-b14e9c8533d9') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Un caso con el que nos encontramos con cierta frecuencia es aquel en el que tenemos datos tabulares pero no disponemos de valores para todas las combinaciones de filas y columnas, y querríamos tener al menos ceros que nos permitan operar con la tabla completa.
Para ver cómo podemos resolver este problema vamos a partir de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0031.jpg"></a>
Como vemos, se trata de una tabla en la que se muestran las ventas de tres posibles productos a lo largo de los cuatro trimestres del año, tabla en la que muchas de las combinaciones de trimestres y productos no existen.
Si, tras leer esta tabla con Power BI, llevamos los datos a una matriz, el resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0032.jpg"></a>
...con blanks en todas aquellas intersecciones de filas y columnas para las que no hay datos en nuestra tabla original.
Pues bien, para crear una tabla a partir de la leída que contenga valores en todas las combinaciones de filas y columnas vamos a comenzar identificando los posibles valores en filas y en columnas -lo que podemos conseguir usando la función <a href="https://www.interactivechaos.com/dax/function/values">VALUES</a>-, y calculando el producto cartesiano de ambos conjuntos con <a href="https://www.interactivechaos.com/dax/function/crossjoin">CROSSJOIN</a>:
Tabla =
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
)
El resultado se muestra en la siguiente imagen:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0033.jpg"></a>
A esta tabla le faltaría la columna de "Ventas" para incluir todos los datos que necesitamos. La añadimos con la función <a href="https://www.interactivechaos.com/dax/function/addcolumns">ADDCOLUMNS</a>:
Tabla =
ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
Ahora ya tenemos la tabla con valores nulos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0034.jpg"></a>
Si llevamos esta tabla a una matriz confirmamos que el aspecto es el deseado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0035.jpg"></a>
Ahora necesitamos "sumar" los valores de ambas tablas, la original y la que acabamos de crear. Para ello vamos a recurrir a unirlas (verticalmente) con la función <a href="https://www.interactivechaos.com/dax/function/union">UNION</a>:
Tabla =
VAR
tabla1 = ADDCOLUMNS(
CROSSJOIN(
VALUES(Data[Trimestre]);
VALUES(Data[Producto])
);
"Ventas"; 0
)
VAR
tabla2 = Data
RETURN
UNION(
tabla1;
tabla2
)
El resultado es el siguiente:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0036.jpg"></a>
Como nuestro objetivo es tener una tabla con una única entrada para cada combinación de filas y columnas, la agregamos según estos criterios. El problema con el que nos encontramos aquí es que la función <a href="https://www.interactivechaos.com/dax/function/summarize">SUMMARIZE</a>, por ejemplo, exige una tabla de base, no una tabla calculada. De forma que vamos a crear una nueva tabla calculada a partir de la anterior:
Tabla completa =
SUMMARIZE(
Tabla;
Tabla[Trimestre];
Tabla[Producto];
"Ventas"; SUM(Tabla[Ventas])
)
El resultado es el esperado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0037.jpg"></a>
Ahora ya podemos llevar esta tabla a una matriz y comprobar que incluye todos los valores:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0038.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '41837857-0178-4e3c-acd4-d56266d5d974') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '41837857-0178-4e3c-acd4-d56266d5d974') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '41837857-0178-4e3c-acd4-d56266d5d974') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '41837857-0178-4e3c-acd4-d56266d5d974') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bf2996fb-ebfe-4052-b2eb-fef704e53234') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bf2996fb-ebfe-4052-b2eb-fef704e53234') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bf2996fb-ebfe-4052-b2eb-fef704e53234') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'bf2996fb-ebfe-4052-b2eb-fef704e53234') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '4b970cc7-125a-477c-bdb7-83ac11805295') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '4b970cc7-125a-477c-bdb7-83ac11805295') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '4b970cc7-125a-477c-bdb7-83ac11805295') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '4b970cc7-125a-477c-bdb7-83ac11805295') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '1ce90b45-3e40-4719-89cf-33c23cef9583') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '1ce90b45-3e40-4719-89cf-33c23cef9583') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '1ce90b45-3e40-4719-89cf-33c23cef9583') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '1ce90b45-3e40-4719-89cf-33c23cef9583') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Una de las preguntas más frecuentes relativas al calendario necesario para utilizar funciones de inteligencia de tiempo es ¿Es mejor crearlo externamente a Power BI? ¿O en el editor de consultas? ¿O tal vez con DAX?
En este escenario vamos a crear un calendario completo en DAX, incluyendo el número y nombre del mes, trimestre, día de la semana, etc.
Para comenzar, creamos la tabla con el calendario básico usando la función <a href="/es/dax/function/calendarauto">CALENDARAUTO</a>. Esta función crea una tabla con una única columna con una secuencia de fechas cubriendo todas las fechas que aparezcan en nuestro conjunto de datos, por defecto desde el 1 de enero del primer año hasta el 31 de diciembre del último año:
Calendar = CALENDARAUTO()
Sin embargo, queremos añadir a esta tabla básica otros campos, para lo que vamos a usar las siguientes funciones DAX (obsérvese en la imagen anterior que el campo creado recibe el nombre de "<em>Date</em>"):
<ul><li>Para crear el año: <a href="/es/dax/function/year">YEAR</a></li>
<li>Para crear el número de mes: <a href="/es/dax/function/month">MONTH</a></li>
<li>Para crear el número de día: <a href="/es/dax/function/day">DAY</a></li>
</ul>Estos nuevos campos los vamos a añadir a la tabla básica usando la función <a href="/es/dax/function/addcolumns">ADDCOLUMNS</a>:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Day"; DAY([Date])
)
Los nombres para el mes y el día de la semana podemos crearlos con la función <a href="/es/dax/function/format">FORMAT</a>, y el número de la semana y el número de día de la semana con las funciones <a href="/es/dax/function/weeknum">WEEKNUM</a> y <a href="/es/dax/function/weekday">WEEKDAY</a>, respectivamente:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
Por último, para obtener el número de trimestre podemos recurrir a la fórmula:
CEILING(MONTH([Date])/3;1)
...que calcula el entero más próximo igual o superior al mes dividido entre 3 (con la función <a href="/es/dax/function/ceiling">CEILING</a>) .
Si quisiéramos también tener el equivalente precedido por una "Q", podemos volver a recurrir a la función FORMAT y al operador & que nos permite concatenar cadenas de texto:
Calendar =
ADDCOLUMNS(
CALENDARAUTO();
"Year"; YEAR([Date]);
"Quarter #"; CEILING(MONTH([Date])/3;1);
"Quarter"; "Q" & FORMAT(CEILING(MONTH([Date])/3;1); "#");
"Month"; MONTH([Date]);
"Month Name"; FORMAT([Date]; "MMMM");
"Week #"; WEEKNUM([Date]);
"Day"; DAY([Date]);
"Week Day"; WEEKDAY([Date]);
"Day Name"; FORMAT([Date]; "DDDD")
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '950bc7a2-ef4b-4e2b-be45-fdd867a6eecb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '950bc7a2-ef4b-4e2b-be45-fdd867a6eecb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '950bc7a2-ef4b-4e2b-be45-fdd867a6eecb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '950bc7a2-ef4b-4e2b-be45-fdd867a6eecb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9e5387c9-aed0-44df-b6a1-4329d1928507') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9e5387c9-aed0-44df-b6a1-4329d1928507') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9e5387c9-aed0-44df-b6a1-4329d1928507') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9e5387c9-aed0-44df-b6a1-4329d1928507') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9316a7e8-57d2-4b0c-81cf-f79b87b0af3c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9316a7e8-57d2-4b0c-81cf-f79b87b0af3c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9316a7e8-57d2-4b0c-81cf-f79b87b0af3c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', '9316a7e8-57d2-4b0c-81cf-f79b87b0af3c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario vamos a crear un campo con la versión de texto de otro campo de fechas (para convertir, por ejemplo, una fecha del tipo 21 de mayo de 2018 en "20180521", teniendo todos los valores de la nueva columna la misma longitud).
Supongamos que nuestro campo de fechas con formato <em>datetime</em> es <em>Sales[Ship Date]:</em>
Para formar nuestra nueva columna deberemos extraer el año, mes y día (podríamos hacerlo más complejo extrayendo la hora, etc.) con las funciones <a href="/dax/function/year">YEAR</a>, <a href="/dax/function/month">MONTH</a> y <a href="/dax/function/day">DAY</a>. Una primera versión de la expresión para crear la nueva columna podría ser, sencillamente, la concatenación de dichos valores, pero podemos ver que no funcionaría con días o meses menores de 10, pues resultarían cadenas de texto de menos de 8 caracteres (en lugar de usar la función <a href="/dax/function/concatenate">CONCATENATE</a> vamos a usar el operador de concatenación &):
ShipDateKey = YEAR(Sales[Ship Date]) & MONTH(Sales[Ship Date]) & DAY(Sales[Ship Date])
Debemos asegurar que tanto el mes como el día tienen ceros a la izquierda en caso de ser necesario para mantener la longitud de 2 caracteres (el año -en nuestros datos- siempre tiene 4 caracteres de longitud). Para esto podemos utilizar la función <a href="/dax/function/format">FORMAT</a> o añadir un cero a la izquierda del mes y del día (tanto si se necesita como si no) y extraer los dos caracteres de la derecha, alternativa que utilizaremos aquí por motivos pedagógicos. Si el cero no hacía falta, los dos caracteres que extraigamos serán los originales. Si, por el contrario, era necesario, estaremos extrayendo el cero y el valor original. Así, por ejemplo, si hemos extraído los meses 11 y 5, esta operación resultaría en las siguientes cadenas de texto:
"0" & "11" = "011" » "11"
"0" & "5" = "05" » "05"
Para extraer los dos caracteres de la derecha utilizaremos la función <a href="/dax/function/right">RIGHT</a>, de forma que la versión final de la expresión sería:
ShipDateKey =
YEAR(Sales[Ship Date]) &
RIGHT("0" & MONTH(Sales[Ship Date]); 2) &
RIGHT("0" & DAY(Sales[Ship Date]); 2)
El resultado, esta vez correcto, sería el mostrado en la siguiente imagen:
Si utilizásemos la función FORMAT, el código quedaría de la siguiente forma:
ShipDateKey =
YEAR(Sales[Ship Date]) &
FORMAT(MONTH(Sales[Ship Date]); "00") &
FORMAT(DAY(Sales[Ship Date]); "00"
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04047a52-b525-444e-918f-fa45163c0cbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04047a52-b525-444e-918f-fa45163c0cbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04047a52-b525-444e-918f-fa45163c0cbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-04047a52-b525-444e-918f-fa45163c0cbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d08322e8-ce9e-43c3-9aa9-f2a9265c60af') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d08322e8-ce9e-43c3-9aa9-f2a9265c60af') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d08322e8-ce9e-43c3-9aa9-f2a9265c60af') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d08322e8-ce9e-43c3-9aa9-f2a9265c60af') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d93c8f76-b083-4d6f-b9c6-bcbc619540a8') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d93c8f76-b083-4d6f-b9c6-bcbc619540a8') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d93c8f76-b083-4d6f-b9c6-bcbc619540a8') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-d93c8f76-b083-4d6f-b9c6-bcbc619540a8') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-07805a95-30f5-454b-b582-d2f9322b1e50') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-07805a95-30f5-454b-b582-d2f9322b1e50') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-07805a95-30f5-454b-b582-d2f9322b1e50') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-07805a95-30f5-454b-b582-d2f9322b1e50') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-cdcdfc2b-374d-4e69-a8ee-3b29dda83494') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-cdcdfc2b-374d-4e69-a8ee-3b29dda83494') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-cdcdfc2b-374d-4e69-a8ee-3b29dda83494') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-cdcdfc2b-374d-4e69-a8ee-3b29dda83494') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0365df4b-0c0d-4db4-9924-1b98edaf0cc0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0365df4b-0c0d-4db4-9924-1b98edaf0cc0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0365df4b-0c0d-4db4-9924-1b98edaf0cc0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-0365df4b-0c0d-4db4-9924-1b98edaf0cc0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una métrica que queremos calcular para cada valor de una variable categórica. Por ejemplo, el "resultado" por país (con independencia de lo que represente este resultado) incluido en un libro Excel:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0084.jpg"></a>
Nuestro objetivo es mostrar en Power BI un pequeño gráfico para cada uno de estos valores que muestre el signo del mismo, de forma que si el valor es positivo (o cero) se muestre un cierto gráfico y si es negativo, se muestre otro.
Leemos los datos desde Power BI y creamos una tabla que nos servirá para mostrar el listado de países y sus respectivos resultados:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0085.jpg"></a>
Las gráficas a mostrar serán los <a href="https://www.vertex42.com/ExcelTips/unicode-symbols.html">símbolos unicode</a> 128200 y 128201:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0086.jpg"></a>
Aun cuando los colores que muestran no están especialmente bien escogidos (el rojo cuando la gráfica sube y el azul cuando baja) servirán para nuestros propósitos.
Para ver estos símbolos en pantalla podemos crear una sencilla medida DAX que devuelva el símbolo en cuestión:
up = UNICHAR(128200)
Y llevar esta medida a, por ejemplo, una tarjeta:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0087.jpg"></a>
En todo caso, lo que nos interesa es crear una medida que, a partir de un cierto valor -como el resultado de cada país-, devuelva un símbolo u otro en función del signo de dicho valor.
Como -en este sencillo caso, solo tenemos dos opciones (que el valor sea mayor o igual a cero, o que sea menor que cero), bastaría usar la función <a href="https://www.interactivechaos.com/dax/function/if">IF</a> para evaluar el valor en cuestión y devolver el símbolo adecuado:
Trend = IF(
SUM(data[Result]) >= 0,
UNICHAR(128200),
UNICHAR(128201)
)
Es decir, calculamos la suma del campo "<em>Result</em>" (hay que aplicar una función de agregación al campo necesariamente) y, si es mayor o igual a cero, devolvemos el símbolo unicode 128200. Y si no, el 128201. Si llevamos esta medida a nuestra tabla vemos el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0088.jpg"></a>
En un escenario con más de dos opciones tendríamos que usar IFs anidados o, mejor, la función <a href="https://www.interactivechaos.com/dax/function/switch">SWITCH</a>, que también podemos usar aquí:
Trend =
VAR results = SUM(data[Result])
RETURN
SWITCH(
TRUE(),
results >= 0, UNICHAR(128200),
results < 0, UNICHAR(128201)
)
En la expresión anterior se ha calculado previamente la suma del campo <em>Result</em> para no tener que ejecutarla posteriormente más de una vez, y devolvemos el resultado de la primera condición que se cumpla: si <em>results</em> (suma del campo <em>Result</em>) es mayor o igual a cero, devolvemos el primer símbolo unicode, y si es negativo el segundo. También podríamos devolver un valor por defecto en el caso de que ninguna de las condiciones se cumpliese. Gráficamente el resultado es, en todo caso, el mismo que teníamos antes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-06/dax-0089.jpg"></a>', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-11820a93-cd8f-487e-8445-dd9b4a5ac0d3') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-11820a93-cd8f-487e-8445-dd9b4a5ac0d3') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-11820a93-cd8f-487e-8445-dd9b4a5ac0d3') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-11820a93-cd8f-487e-8445-dd9b4a5ac0d3') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-137810a2-a125-4bd5-ac12-1aa450ad87d7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-137810a2-a125-4bd5-ac12-1aa450ad87d7') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-137810a2-a125-4bd5-ac12-1aa450ad87d7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-137810a2-a125-4bd5-ac12-1aa450ad87d7') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9b656efa-c235-425d-9cf0-cd6b21b452d3') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9b656efa-c235-425d-9cf0-cd6b21b452d3') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9b656efa-c235-425d-9cf0-cd6b21b452d3') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-9b656efa-c235-425d-9cf0-cd6b21b452d3') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6c9ec734-5f64-4d46-a787-28500073fcef') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6c9ec734-5f64-4d46-a787-28500073fcef') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6c9ec734-5f64-4d46-a787-28500073fcef') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-6c9ec734-5f64-4d46-a787-28500073fcef') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-be0135c1-0468-4985-8d35-f18cc39db6ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-be0135c1-0468-4985-8d35-f18cc39db6ea') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-be0135c1-0468-4985-8d35-f18cc39db6ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-be0135c1-0468-4985-8d35-f18cc39db6ea') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a4f99a8b-4108-400c-bea5-55beb6a99203') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a4f99a8b-4108-400c-bea5-55beb6a99203') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'file') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a4f99a8b-4108-400c-bea5-55beb6a99203') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('entity_query') (Line: 147)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 640)
Drupal\Core\Entity\EntityStorageBase->loadByProperties(Array) (Line: 63)
Drupal\Core\Entity\EntityRepository->loadEntityByUuid('file', 'insert-max_800_px-a4f99a8b-4108-400c-bea5-55beb6a99203') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('El objetivo de este escenario es utilizar una segmentación para controlar el contenido de una gráfica. Por ejemplo, partimos de la siguiente tabla de datos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0051.jpg"></a>
Tras leerla desde Power BI, podemos crear una gráfica de columnas mostrando el contenido del campo <em>Ingresos</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0052.jpg"></a>
Lo que desearíamos es usar una segmentación para mostrar en la gráfica los ingresos o los gastos. Comenzamos creando la segmentación para lo cual vamos a crear una tabla (desde Power BI) usando la herramienta de <em>Especificar datos</em> en la que incluyamos, en una columna, las dos etiquetas a mostrar:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0053.jpg"></a>
A continuación, podemos crear la segmentación usando como campo <em>Opciones[Opciones]</em>:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0054.jpg"></a>
A la segmentación mostrada en la imagen anterior se ha aplicado cierto formato para hacerla más amigable: se ha retirado el título, se le ha dado orientación horizontal y se ha aplicado un color personalizado tanto a la fuente como al fondo de los elementos.
Ahora necesitamos crear una medida que, en función de la opción escogida, devuelva la agregación de ingresos o de gastos:
Valor = SWITCH(
SELECTEDVALUE(Opciones[Opciones]);
"Ingresos"; SUM(data[Ingresos]);
"Gastos"; SUM(data[Gastos]);
SUM(data[Ingresos])
)
En ella analizamos el contenido del campo <em>Opciones[Opciones]</em> una vez aplicado el contexto de filtro, y devolvemos un resultado u otro en función de su valor: si toma el valor <em>Ingresos</em>, se devuelve la suma del campo homónimo. Si toma el valor <em>Gastos</em>, hacemos lo propio con dicho campo. Se incluye también un valor por defecto (la suma de ingresos) para el caso de que el usuario no haya seleccionado ninguna opción en la segmentación.
Ahora llevamos esta medida al campo <em>Valor</em> de la gráfica, sustituyendo al campo <em>Ingresos</em> que habíamos llevado al comienzo. Y ya está. Si presionamos el botón de ingresos en la segmentación, <em>Opciones[Opciones]</em> toma el valor <em>Ingresos</em>, por lo que la medida <em>Valor</em> que hemos creado devolverá la suma de ingresos (en la siguiente imagen se ha añadido una tabla con los valores a representar para facilitar la comparación):
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0055.jpg"></a>
Y si seleccionamos <em>Gastos</em>, se muestran los gastos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2020-02/dax-0056.jpg"></a>
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 934)
Drupal\views\Plugin\views\field\EntityField->render_item(0, Array) (Line: 1171)
Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender(Object) (Line: 238)
template_preprocess_views_view_field(Array, 'views_view_field', Array)
call_user_func_array('template_preprocess_views_view_field', Array) (Line: 287)
Drupal\Core\Theme\ThemeManager->render('views_view_field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 1748)
Drupal\views\Plugin\views\field\FieldPluginBase->theme(Object) (Line: 774)
Drupal\views\Plugin\views\style\StylePluginBase->elementPreRenderRow(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 713)
Drupal\views\Plugin\views\style\StylePluginBase->renderFields(Array) (Line: 579)
Drupal\views\Plugin\views\style\StylePluginBase->renderGrouping(Array, Array, 1) (Line: 467)
Drupal\views\Plugin\views\style\StylePluginBase->render(Array) (Line: 2169)
Drupal\views\Plugin\views\display\DisplayPluginBase->render() (Line: 1538)
Drupal\views\ViewExecutable->render() (Line: 199)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1635)
Drupal\views\ViewExecutable->executeDisplay('bloque_escenarios_dax', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Return type of Drupal\google_analytics\Component\Render\GoogleAnalyticsJavaScriptSnippet::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in include() (line 10 of modules/contrib/google_analytics/src/Component/Render/GoogleAnalyticsJavaScriptSnippet.php).
include('/var/www/vhosts/interactivechaos.ovh/httpdocs/modules/contrib/google_analytics/src/Component/Render/GoogleAnalyticsJavaScriptSnippet.php') (Line: 578)
Composer\Autoload\ClassLoader::Composer\Autoload\{closure}('/var/www/vhosts/interactivechaos.ovh/httpdocs/modules/contrib/google_analytics/src/Component/Render/GoogleAnalyticsJavaScriptSnippet.php') (Line: 432)
Composer\Autoload\ClassLoader->loadClass('Drupal\google_analytics\Component\Render\GoogleAnalyticsJavaScriptSnippet') (Line: 372)
google_analytics_page_attachments(Array) (Line: 313)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}(Object, 'google_analytics') (Line: 405)
Drupal\Core\Extension\ModuleHandler->invokeAllWith('page_attachments', Object) (Line: 310)
Drupal\Core\Render\MainContent\HtmlRenderer->invokePageAttachmentHooks(Array) (Line: 288)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Use of "static" in callables is deprecated in Drupal\user\Entity\Role::postLoad() (line 172 of core/modules/user/src/Entity/Role.php).
Drupal\user\Entity\Role::postLoad(Object, Array) (Line: 423)
Drupal\Core\Entity\EntityStorageBase->postLoad(Array) (Line: 353)
Drupal\Core\Entity\EntityStorageBase->loadMultiple() (Line: 126)
eu_cookie_compliance_page_attachments(Array) (Line: 313)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}(Object, 'eu_cookie_compliance') (Line: 405)
Drupal\Core\Extension\ModuleHandler->invokeAllWith('page_attachments', Object) (Line: 310)
Drupal\Core\Render\MainContent\HtmlRenderer->invokePageAttachmentHooks(Array) (Line: 288)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 141)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2633)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 144)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2633)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 51)
Drupal\views\Plugin\views\filter\ManyToOne->defineOptions() (Line: 117)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 110)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 95)
Drupal\views\Plugin\views\filter\FilterPluginBase->init(Object, Object, Array) (Line: 44)
Drupal\views\Plugin\views\filter\InOperator->init(Object, Object, Array) (Line: 36)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2633)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\views\ManyToOneHelper::$handler is deprecated in Drupal\views\ManyToOneHelper->__construct() (line 24 of core/modules/views/src/ManyToOneHelper.php).
Drupal\views\ManyToOneHelper->__construct(Object) (Line: 38)
Drupal\views\Plugin\views\filter\ManyToOne->init(Object, Object, Array) (Line: 98)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('filter') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('filter', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 2633)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated in Drupal\Core\Database\Query\Select->addMetaData() (line 178 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addMetaData('entity_type', 'taxonomy_term') (Line: 115)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 228)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->valueForm(Array, Object) (Line: 941)
Drupal\views\Plugin\views\filter\FilterPluginBase->buildExposedForm(Array, Object) (Line: 111)
Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 534)
Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 281)
Drupal\Core\Form\FormBuilder->buildForm('\Drupal\views\Form\ViewsExposedForm', Object) (Line: 134)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm(1) (Line: 2638)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated in Drupal\Core\Database\Query\Select->addTag() (line 149 of core/lib/Drupal/Core/Database/Query/Select.php).
Drupal\Core\Database\Query\Select->addTag('taxonomy_term_access') (Line: 145)
Drupal\Core\Entity\Query\Sql\Query->prepare() (Line: 80)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 228)
Drupal\taxonomy\Plugin\views\filter\TaxonomyIndexTid->valueForm(Array, Object) (Line: 941)
Drupal\views\Plugin\views\filter\FilterPluginBase->buildExposedForm(Array, Object) (Line: 111)
Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 534)
Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 281)
Drupal\Core\Form\FormBuilder->buildForm('\Drupal\views\Form\ViewsExposedForm', Object) (Line: 134)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm(1) (Line: 2638)
Drupal\views\Plugin\views\display\DisplayPluginBase->viewExposedFormBlocks() (Line: 35)
Drupal\views\Plugin\Block\ViewsExposedFilterBlock->build() (Line: 171)
Drupal\block\BlockViewBuilder::preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 160)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 159)
Drupal\Core\Render\Renderer->renderPlain(Array) (Line: 175)
Drupal\Core\Render\Renderer->renderPlaceholder('', Array) (Line: 665)
Drupal\Core\Render\Renderer->replacePlaceholders(Array) (Line: 550)
Drupal\Core\Render\Renderer->doRender(Array, 1) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, 1) (Line: 148)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 147)
Drupal\Core\Render\Renderer->renderRoot(Array) (Line: 279)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders(Object) (Line: 71)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments(Object) (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.response') (Line: 202)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 190)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)