- 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\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-fb87303b-a0a4-4534-9e35-49416cdddf62') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-fb87303b-a0a4-4534-9e35-49416cdddf62') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-fb87303b-a0a4-4534-9e35-49416cdddf62') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-fb87303b-a0a4-4534-9e35-49416cdddf62') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-22d1b4bd-e6c7-4a64-99fe-6ce9b956ca6e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-22d1b4bd-e6c7-4a64-99fe-6ce9b956ca6e') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-22d1b4bd-e6c7-4a64-99fe-6ce9b956ca6e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-22d1b4bd-e6c7-4a64-99fe-6ce9b956ca6e') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-54f96f44-a649-4cf4-820d-fdeeca8af025') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-54f96f44-a649-4cf4-820d-fdeeca8af025') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-54f96f44-a649-4cf4-820d-fdeeca8af025') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-54f96f44-a649-4cf4-820d-fdeeca8af025') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-05a4e35a-71f2-407c-8d22-338089a35642') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-05a4e35a-71f2-407c-8d22-338089a35642') (Line: 95)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterMetaData is deprecated 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-05a4e35a-71f2-407c-8d22-338089a35642') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 713)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
- Deprecated function: Creation of dynamic property Drupal\mysql\Driver\Database\mysql\Select::$alterTags is deprecated 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-05a4e35a-71f2-407c-8d22-338089a35642') (Line: 124)
Drupal\editor\Plugin\Filter\EditorFileReference->process('En este escenario partimos de una tabla <em>Sales</em> que contiene en el campo <em>Amount</em> la cifra de ventas y en el campo <em>Customer Id</em> una referencia al cliente asociado.
El objetivo es obtener una función de consulta que reciba un número n como argumento y devuelva una tabla conteniendo los n clientes con mayor facturación, ordenada de mayor a menor facturación. Esta tabla deberá tener dos columnas con información del identificador del cliente y la suma de sus compras.
Para empezar a trabajar en la consulta, supongamos que queremos extraer 5 clientes. El primer paso consiste en calcular, para cada cliente, sus ventas (posteriormente ordenaremos esta tabla y seleccionaremos el número de filas que nos interesa).
Para esto, el lenguaje M nos ofrece la función <a href="/es/m/function/tablegroup">Table.Group</a>, que agrega una tabla según un campo, y añade columnas calculadas adicionales obtenidas tras realizar esta agregación.
En nuestro caso queremos agrupar la tabla de ventas según el campo <em>Customer Id</em> y queremos añadir una nueva columna (a la que podemos llamar <em>Total Sales</em>) que contenga la suma de ventas de cada cliente identificado.
La función <a href="/es/m/function/tablegroup">Table.Group</a> requiere tres argumentos principales: la tabla a agregar (Sales), el campo (o los campos) según los cuales se va a realizar la agregación (Customer Id) y una lista conteniendo información sobre las columnas a crear: para cada una habrá que añadir una lista con el nombre de la columna y la función que va a determinar los valores de la misma (es decir, su <em>función generadora</em>). Nosotros solo queremos crear una columna, de forma que, parcialmente en pseudo-código, nuestra fórmula de paso sería la siguiente:
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", función-generadora, type number}
}
)
Nuestra función generadora deberá sumar los valores de la columna <em>Amount</em> (recordemos que, cuando se aplique nuestra función generadora, la tabla va a estar filtrada según el valor de <em>Customer Id</em> que se esté considerando). Para realizar esta suma podemos usar la función <a href="/es/m/function/listsum">List.Sum</a>, lo que significa que nuestra función generadora puede ser la siguiente:
each List.Sum([Amount])
Nuestra consulta quedaría, por lo tanto, del siguiente modo:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
)
in
GroupedRows
Obsérvese que en el bloque que especifica la creación de la columna <em>Total Sales</em> se ha añadido como tercer argumento el tipo de la columna a crear:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0008.png"></a>
Ahora viene la parte más sencilla: ordenar y seleccionar las primeras filas. Para ordenar la tabla vamos a usar la función <a href="/es/m/function/tablesort">Table.Sort</a>. Esta función recibe una tabla y los criterios de ordenación, devolviendo la tabla ordenada. En nuestro escenario el criterio de ordenación viene determinado por el contenido de la columna <em>Total Sales</em>, y queremos que la ordenación sea descendente, lo que quiere decir que nuestra función de paso podría ser la siguiente:
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
)
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0009.png"></a>
Vemos en la imagen anterior que los clientes ya se muestran ordenados según su facturación.
Para quedarnos con las primeras numberOfCustomers filas, no tenemos más que recurrir a la función <a href="/es/m/function/tablefirstn">Table.FirstN</a>, con lo que nuestra consulta quedaría así:
let
numberOfCustomers = 5,
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0010.png"></a>
Ahora, para convertir nuestra consulta en una función de consulta, añadimos la cabecera y eliminamos la fórmula de paso que asigna el valor 5 a la variable numberOfCustomers:
(numberOfCustomers as number) =>
let
GroupedRows = Table.Group(
Sales,
"Customer Id",
{
{"Total Sales", each List.Sum([Amount]), type number}
}
),
SortedRows = Table.Sort(
GroupedRows,
{
{"Total Sales", Order.Descending}
}
),
TopNRows = Table.FirstN(SortedRows, numberOfCustomers)
in
TopNRows
Le damos un nombre apropiado (<em>TopCustomers</em>, por ejemplo) y la invocamos para ver el resultado:
<a class="colorbox insert-colorbox" data-colorbox-gallery="gallery-node" data-insert-class="" data-insert-type="image" href="/sites/default/files/2023-02/escenario_m_0011.png"></a>
(en la imagen anterior se muestra el resultado de pasar a la función el número 3 como argumento)
', 'es') (Line: 118)
Drupal\filter\Element\ProcessedText::preRenderText(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 788)
Drupal\Core\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: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 235)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\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)