- 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-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-350e337f-140f-4fa2-bda4-0f03477cb3c2') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-03329b88-76e4-4c9b-8765-af78475b80e1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-e53eaa7f-c9ca-4db7-8f55-7fbf3b792f47') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-5c3969df-7095-40d4-b46e-af97df4d2797') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-0c5b04ec-58bd-46b2-a673-efde628eabbb') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-b68efa25-a5d8-4ce5-8aa3-96568aef9119') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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-a1dd98da-72fb-45f2-a860-f2a054bc67d1') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de un listado de clientes:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0024.jpg"></a>
...y de una tabla de compras de cada uno de ellos:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0025.jpg"></a>
El objetivo es obtener un listado de clientes en el que se muestre el número de días (por ejemplo, podría ser otro período) entre compras. Para hacer el escenario sencillo los clientes reciben como nombre "Cliente x", siendo x el número de compras realizadas (de esta forma, el <em>Cliente 0</em> no ha realizado ninguna, el <em>Cliente 1</em> ha realizado una, etc.), y la frecuencia de compra en días para cada cliente coincide también con x. Así, el cliente 2 realizó una primera compra el 3 de enero, y una segunda dos días más tarde, el 5 de enero.
Una vez hemos asegurado que el modelo de datos incluye las relaciones adecuadas (incluyendo una relación entre la tabla de ventas y el necesario calendario), podemos crear una tabla calculada que, usando la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>, extraiga el listado de clientes y agregue la información necesaria. Partimos, por lo tanto, de la siguiente expresión DAX que define esta primera versión de nuestra tabla de resultados:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre]
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0026.jpg"></a>
Aunque podríamos calcular directamente la frecuencia de compra para cada uno de ellos, hagámoslo paso por paso, incluyendo una columna adicional para cada uno de los datos que necesitamos.
Si entendemos por frecuencia de compra el número de días transcurridos entre la primera compra y la última dividido entre el número de compras realizadas, en primer lugar sería preciso calcular las fechas de primera y de última compra por cliente, para lo que vamos a recurrir a las funciones <a href="/dax/function/firstdate">FIRSTDATE</a> y <a href="/dax/function/lastdate">LASTDATE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha])
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0027.jpg"></a>
El cálculo del rango de días entre ambas fechas se reduce a una sencilla resta, que realizaremos usando la función <a href="/dax/function/datediff">DATEDIFF</a>, función que nos permite especificar el período a considerar -días, en nuestro ejemplo-:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0028.jpg"></a>
Debemos entender que estamos realizando un enfoque un tanto ingenuo del problema al presuponer que el cliente existe como tal desde su primera compra y solo hasta la última. Más realista sería considerar como comienzo del período el día en el que el cliente "se dio de alta como tal", hubiese realizado o no una compra, y/o considerar como fin del período el día actual, por ejemplo.
Considérese también que, al crearse la tabla calculada en un entorno de contexto de fila, para cada cliente se extrae la información de la tabla remota relacionada con él. Así, cuando se está calculando la primera fecha de compra para el cliente X, la expresión
FIRSTDATE(Calendario[Fecha])
...filtra el campo <em>Fecha</em> de la tabla <em>Calendario</em> de forma que solo incluya las fechas para las que existen compras asociadas al cliente que corresponda.
El siguiente paso es contar el número de compras por cliente, para lo que podemos extraer la tabla <em>Ventas</em> (una vez filtrada por el contexto, para lo que usaremos la función <a href="/dax/function/relatedtable">RELATEDTABLE</a>) y contar el número de filas que tiene con <a href="/dax/function/countrows">COUNTROWS</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas))
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0029.jpg"></a>
Por último queda lo más sencillo, que es dividir el rango de fechas entre el número de compras, para lo que recurriremos a la función <a href="/dax/function/divide">DIVIDE</a>:
Frecuencia de compra =
SELECTCOLUMNS(
Clientes;
"Nombre"; Clientes[Nombre];
"Primera compra"; FIRSTDATE(Calendario[Fecha]);
"Última compra"; LASTDATE(Calendario[Fecha]);
"Rango"; DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
"Nº de compras"; COUNTROWS(RELATEDTABLE(Ventas));
"Frecuencia de compra"; DIVIDE(
DATEDIFF(FIRSTDATE(Calendario[Fecha]); LASTDATE(Calendario[Fecha]); DAY);
COUNTROWS(RELATEDTABLE(Ventas))
)
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2019-10/dax-0030.jpg"></a>
Comprobamos que, en esta primera versión de la expresión, si un cliente no ha realizado ninguna compra se muestra un BLANK, y si ha realizado una única compra de devuelve una frecuencia de 1. Podríamos completar nuestro DIVIDE con alguna función lógica que realizase un cálculo u otro en función del número de compras y, de esta forma, gestionar estas excepciones.
Puede descargarse el fichero Excel y el informe Power BI resultante <a href="https://www.interactivechaos.com/sites/default/files/data/calculo_de_la_frecuencia_de_compra_de_los_clientes.zip">aquí</a>.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '67229f85-0b0f-4009-b1d9-384ec4ac3a8f') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '89501d32-a9ec-4177-a5ac-18dcba38df11') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '5026e66a-ec6a-46ba-b942-408f7acdaa96') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('Partimos de una tabla de ventas ("<em>Movements</em>") en la que figura la fecha de venta, el identificador del usuario y el importe de venta:
Nuestro objetivo es añadir una nueva columna en la que se muestre la última compra del mismo cliente. Al recorrerse la tabla creándose el nuevo campo se creará para cada fila el contexto de fila asociado, lo que nos da acceso a los campos de la fila. Concretamente, la función <a href="/dax/function/earlier">EARLIER</a> nos permite acceder al identificador del cliente y a la fecha, de forma que podemos calcular el subconjunto de la tabla que contiene las compras del cliente actual anteriores a la fecha actual con la siguiente expresión:
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
Una vez calculado este subconjunto, podemos extraer la última fecha muy fácilmente usando la función <a href="/dax/function/lastdate">LASTDATE</a>, función que devuelve una tabla con la última fecha del contexto actual. Usada como argumento de <a href="/dax/function/calculate">CALCULATE</a> y añadiendo como filtro el subconjunto calculado, podemos extraer la última fecha del conjunto (es decir, la última fecha de compra antes de la actual):
Last Purchase =
CALCULATE(
LASTDATE(Movements[Order Date]);
FILTER(
Movements;
Movements[Customer Id] = EARLIER(Movements[Customer Id]) &&
Movements[Order Date] < EARLIER(Movements[Order Date])
)
)
Recordemos que, aunque la función LASTDATE devuelve una tabla, el resultado puede ser usado como un escalar allí donde se requiera una simple fecha. El resultado obtenido es el siguiente:
Podemos confirmar que el cálculo es correcto si llevamos a una visualización tipo tabla el identificador de usuario, el campo <em>Order Date</em> y el campo recién creado <em>Last Purchase</em>, filtrando el identificador de usuario (usando una segmentación, por ejemplo) y ordenando la tabla creada según el campo <em>Order Date</em>:
Vemos cómo la fecha de última compra coincide con la anterior.
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', 'a31aa195-9f87-4a2e-b537-eb3fea9b2fad') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'a31aa195-9f87-4a2e-b537-eb3fea9b2fad') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'a31aa195-9f87-4a2e-b537-eb3fea9b2fad') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'a31aa195-9f87-4a2e-b537-eb3fea9b2fad') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '76624da2-fe68-42d3-a4ee-7fd62a27825e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '76624da2-fe68-42d3-a4ee-7fd62a27825e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '76624da2-fe68-42d3-a4ee-7fd62a27825e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '76624da2-fe68-42d3-a4ee-7fd62a27825e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'bc6e090c-08b7-4c0f-b2f7-d1ed0731d599') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'bc6e090c-08b7-4c0f-b2f7-d1ed0731d599') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'bc6e090c-08b7-4c0f-b2f7-d1ed0731d599') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', 'bc6e090c-08b7-4c0f-b2f7-d1ed0731d599') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '87a43dbc-6379-4017-9d5b-b943975a3190') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '87a43dbc-6379-4017-9d5b-b943975a3190') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '87a43dbc-6379-4017-9d5b-b943975a3190') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '87a43dbc-6379-4017-9d5b-b943975a3190') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '958fe5a6-6cdb-4cf8-bff3-cf406ae1651c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '958fe5a6-6cdb-4cf8-bff3-cf406ae1651c') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '958fe5a6-6cdb-4cf8-bff3-cf406ae1651c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '958fe5a6-6cdb-4cf8-bff3-cf406ae1651c') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este sencillo escenario partimos de los siguientes datos:
<ul><li>Tabla de vendedores:</li>
</ul><ul><li>Tabla de ventas:</li>
</ul>El objetivo es crear una tabla calculada en la que se incluya el nombre del vendedor y las fechas de su primera y última venta. Comencemos creando la tabla con los nombres, para lo que vamos a usar la función <a href="/dax/function/selectcolumns">SELECTCOLUMNS</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor]
)
Añadamos ahora la columna con la primera fecha de venta. Podríamos pensar en la necesidad de extraer mediante la función <a href="/dax/function/relatedtable">RELATEDTABLE</a> el subconjunto de la tabla de ventas asociada a cada fila de nuestra tabla (tal y como hacemos en el escenario de <a href="/dax/scenario/creacion-de-una-tabla-con-las-ventas-medias-por-vendedor">Creación de una tabla con las ventas medias por vendedor</a>) pero la función <a href="/dax/function/firstdate">FIRSTDATE</a>, tal y como podemos leer en la documentación, devuelve la primera fecha <strong>en el contexto actual</strong>, lo que supone el contexto de fila definido por cada vendedor, en nuestro caso, lo que hace innecesario el uso de la mencionada función RELATEDTABLE. Basta con usar FIRSTDATE de la siguiente forma:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha])
)
Vemos que las fechas son distintas, lo que ya nos indica que el cálculo de FIRSTDATE se realiza en contextos diferentes para cada fila. En todo caso comprobamos mediante una inspección ocular de la tabla de ventas que las fechas mostradas son las correctas.
La adición de la última fecha de venta es análoga, utilizando la función <a href="/dax/function/lastdate">LASTDATE</a>:
Listado vendedores = SELECTCOLUMNS(
Vendedores;
"Nombre"; Vendedores[Nombre Vendedor];
"Primera venta"; FIRSTDATE(Ventas[Fecha]);
"Última venta"; LASTDATE(Ventas[Fecha])
)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '04717648-30bd-460e-8253-3ce85a78b479') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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', '0d385c59-bec5-4ba0-9742-689bc429b6b0') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla de ventas (<em>Sales</em>) en la que se indica, entre otros campos, la fecha y el importe de venta (<em>SalesAmount</em>). La medida <em>[Sales]</em> suma este última columna.
El objetivo es llevar a una gráfica de líneas las ventas acumuladas durante las dos semanas previas para todas las fechas del calendario. Lo que necesitamos es calcular la medida <em>Sales</em> para el período de dos semanas de duración que termina en la fecha que se esté considerando en cada momento, es decir, en pseudo-código sería:
Fortnight sales = CALCULATE(
[Sales];
Período-de-dos-semanas-terminando-en-la-fecha-actual
)
Como puede verse, utilizaremos la función <a href="/dax/function/calculate">CALCULATE </a>para evaluar la medida <em>Sales </em>en el período de interés.
Para el cálculo del período de dos semanas que terminan en la fecha siendo considerada utilizaremos la función <a href="/dax/function/datesinperiod">DATESINPERIOD</a>, función que nos permite especificar la fecha de inicio de cálculo, el intervalo a añadir o restar (días en nuestro caso) y el número de intervalos a añadir o restar (14 en nuestro caso). Podríamos describir el período de interés de la siguiente forma:
Período-de-dos-semanas-terminando-en-la-fecha-actual =
DATESINPERIOD(
'Calendar'[Date];
LASTDATE('Calendar'[Date]);
-14;
DAY)
En nuestro ejemplo, la fecha de partida será la última del contexto (o la primera, pues se determinará según el contexto de fila ya que vamos a realizar nuestro cálculo para cada uno de los días por separado).
Podemos, por lo tanto, definir la medida de la siguiente forma:
Fortnight sales = CALCULATE(
[Sales];
DATESINPERIOD(
'Calendar'[Date];
FIRSTDATE('Calendar'[Date]);
-14;
DAY
)
)
Si llevamos a una tabla la columna del calendario conteniendo las fechas (<em>'Calendar'[Date]</em>) y la recién creada medida, obtenemos el siguiente resultado:
Puede comprobarse como, lógicamente, los 13 primeros días muestran acumulados parciales al no existir fechas anteriores al 1 de julio de 2001.
Si llevamos estos mismos campos a un gráfico de líneas, el resultado es el siguiente:
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 374)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 204)
Drupal\Core\Render\Renderer->render(Array) (Line: 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)