- 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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->defineOptions() (Line: 141)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', 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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->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: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', 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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 110)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', 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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 35)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', 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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->defineOptions() (Line: 141)
Drupal\views\Plugin\views\PluginBase->init(Object, Object, Array) (Line: 104)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 1876)
Drupal\views\ViewExecutable->buildTitle() (Line: 338)
Drupal\views\Plugin\views\display\Feed->attachTo(Object, 'page_1', Array) (Line: 1733)
Drupal\views\ViewExecutable->attachDisplays() (Line: 1333)
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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->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: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 1876)
Drupal\views\ViewExecutable->buildTitle() (Line: 338)
Drupal\views\Plugin\views\display\Feed->attachTo(Object, 'page_1', Array) (Line: 1733)
Drupal\views\ViewExecutable->attachDisplays() (Line: 1333)
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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 54)
Drupal\views\Plugin\views\argument\ManyToOne->defineOptions() (Line: 228)
Drupal\views\Plugin\views\PluginBase->unpackOptions(Array, Array) (Line: 110)
Drupal\views\Plugin\views\HandlerBase->init(Object, Object, Array) (Line: 82)
Drupal\views\Plugin\views\argument\ArgumentPluginBase->init(Object, Object, Array) (Line: 33)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 1876)
Drupal\views\ViewExecutable->buildTitle() (Line: 338)
Drupal\views\Plugin\views\display\Feed->attachTo(Object, 'page_1', Array) (Line: 1733)
Drupal\views\ViewExecutable->attachDisplays() (Line: 1333)
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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (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: 35)
Drupal\views\Plugin\views\argument\ManyToOne->init(Object, Object, Array) (Line: 894)
Drupal\views\Plugin\views\display\DisplayPluginBase->getHandlers('argument') (Line: 1045)
Drupal\views\ViewExecutable->_initHandler('argument', Array) (Line: 903)
Drupal\views\ViewExecutable->initHandlers() (Line: 1876)
Drupal\views\ViewExecutable->buildTitle() (Line: 338)
Drupal\views\Plugin\views\display\Feed->attachTo(Object, 'page_1', Array) (Line: 1733)
Drupal\views\ViewExecutable->attachDisplays() (Line: 1333)
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('page_1', Array) (Line: 81)
Drupal\views\Element\View::preRenderViewElement(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '4c23a5e6-f061-473b-9691-a6dc77468d59') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '4c23a5e6-f061-473b-9691-a6dc77468d59') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '4c23a5e6-f061-473b-9691-a6dc77468d59') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '4c23a5e6-f061-473b-9691-a6dc77468d59') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '22e4e727-c1c6-4048-8d84-37f2b5971f24') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '22e4e727-c1c6-4048-8d84-37f2b5971f24') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '22e4e727-c1c6-4048-8d84-37f2b5971f24') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', '22e4e727-c1c6-4048-8d84-37f2b5971f24') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', 'd40d5b76-e361-4fb6-9847-764032fed403') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', 'd40d5b76-e361-4fb6-9847-764032fed403') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', 'd40d5b76-e361-4fb6-9847-764032fed403') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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', 'd40d5b76-e361-4fb6-9847-764032fed403') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla ("<em>Products</em>") de productos identificados por números enteros consecutivos:
El objetivo es generar otra tabla en la que cada uno de estos registros se haya replicado un número aleatorio de veces. Como puede apreciarse, este escenario es semejante al de <a href="/dax/scenario/replicacion-de-cada-fila-de-una-tabla-segun-una-tabla-de-valores">Replicación de cada fila de una tabla según una tabla de valores</a> con la salvedad de que ahora no tenemos una tabla que nos indique el número de veces que deberemos replicar cada fila. Pero la idea es semejante: en este caso generaremos la columna conteniendo esos números aleatorios manteniendo el esquema de trabajo que vimos en el escenario mencionado.
Esta columna de números aleatorios la vamos a añadir a las columnas existentes de la tabla <em>Products</em> utilizando el siguiente código:
Products_Extended =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
Queremos ahora realizar una combinación cruzada entre la tabla anterior y una segunda tabla con tantas filas como indique el valor de <em>RandomValue</em> que vemos en la imagen anterior (el contenido exacto de dichas filas es irrelevante: lo importante es que contenga el número correcto de filas para que la combinación cruzada "replique" cada fila de la primera tabla el número de veces indicado por el valor generado aleatoriamente). La función a utilizar para realizar la combinación cruzada es <a href="/dax/function/generate">GENERATE</a>, y la función para generar la tabla con el número que nos interesa de filas es <a href="/dax/function/generateseries">GENERATESERIES</a>. El código completo es el siguiente:
Products_Extended =
VAR
Random =
ADDCOLUMNS(
Products;
"RandomValue"; RANDBETWEEN(2; 3)
)
RETURN
GENERATE(
Random;
GENERATESERIES(1; [RandomValue])
)
Hemos generado la tabla <em>Random</em> conteniendo los mismos campos que la tabla <em>Products</em> añadiéndole la columna con los valores aleatorios, y se devuelve la combinación cruzada de dicha tabla con la progresión aritmética generada por GENERATESERIES, indicando que deberán generarse <em>[RandomValue]</em> valores (cifra accesible vía contexto de fila para cada fila de la tabla <em>Random</em> para la que la función GENERATE se plantea la combinación cruzada). El resultado es el siguiente:
Obsérvese que la máquina DAX no reconoce el campo RandomValue en el editor de fórmulas, pese a lo cual lo interpreta correctamente. Esto significa que hemos de escribir dicha etiqueta a mano en el código, sin esperar que el sistema "Intellisense" del editor nos lo muestre en la lista de opciones disponibles.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(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: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 88)
__TwigTemplate_a7d6005c89ae729617b9a0c2bccb1776->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 46)
__TwigTemplate_804f7948456cfe20e11a34c43439c7c2->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array, Array) (Line: 43)
__TwigTemplate_bd990293b89f3b78c69fe0ee2f7828b5->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/field/field--text-with-summary.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('field', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_94047fbdba6937b76a4479dfa1763452->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/node.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('node', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 74)
__TwigTemplate_43dffa6ad507293d1ceeb24e05ce942c->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/custom/yg_aesthetic/templates/views-view-unformatted.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view_unformatted', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 479)
Drupal\Core\Template\TwigExtension->escapeFilter(Object, Array, 'html', NULL, 1) (Line: 110)
__TwigTemplate_349d2f5aada73507d566397721f27ea4->doDisplay(Array, Array) (Line: 405)
Twig\Template->displayWithErrorHandling(Array, Array) (Line: 378)
Twig\Template->display(Array) (Line: 390)
Twig\Template->render(Array) (Line: 55)
twig_render_template('themes/contrib/classy/templates/views/views-view.html.twig', Array) (Line: 384)
Drupal\Core\Theme\ThemeManager->render('views_view', Array) (Line: 433)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 446)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\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)