Jump to content


Photo

Consulta con "campos dinámicos"


  • Please log in to reply
6 replies to this topic

#1 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 12 October 2012 - 10:29 AM

Compañeros, tengo 3 tablas en FIREBIRD 2.5 (por favor mirar imagen para entender el diseño y sus relaciones), como podemos ver, la tabla TARIFAS_SERVICIOS almacena tantos valores de tarifas para cada ESTUDIO (de la tabla ESTUDIOS) como TARIFAS hayan (en la tabla TARIFAS).

De ser posible, yo quiero obtener el resultado de una consulta con la siguiente estructura:

ESTUDIO                            VALOR_TARIFA_UNO            VALOR_TARIFA_DOS    VALOR_TARIFA_N

Estudio 1                            $20.000                              $30.000                        $40.000
Estudio 2                            $10.000                              $50.000                        $30.000
Estudio N                            $70.000                              $90.000                        $20.000

Como ven los campos para valores de tarifas son "dinámicos", si el día de mañana se agrega una nueva tarifa, la consulta deberá agregar un nuevo campo.

Espero se entienda.

Muchas gracias de antemano.

PD: Se que lo puedo resolver con un StringGrid pero quiero evitar la fatiga.

Attached Files


  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 12 October 2012 - 11:17 AM

Hola,
Entiendo tu duda. Lamentablemente al momento Firebird no cuenta con la posibilidad de pivotear consultas.
Armar una consulta para lo que buscas, es imposible. Porque desconoces la cantidad de campos. Hoy pueden ser 10 y mañana 100.

He visto antes esta duda y las propuestas pasan por armar tantas subconsultas de modo que se incluyan en el select según la cantidad de campos. Pero en tu caso no es deseable ya que desconoces la cantidad, Y que además no será del todo eficiente.

Creo la cláusula PIVOT está entre algunos de los puntos que se espera para la versión 3.

Saludos,


  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14448 posts
  • LocationMéxico

Posted 12 October 2012 - 11:36 AM

FastCube que es parte de FastReport te puede hacer eso amigo, la pega pues es que es de pago.

Saludos
  • 0

#4 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2092 posts
  • LocationRepública Dominicana

Posted 12 October 2012 - 12:12 PM

Saludos.

Una alternativa de manera nativa:
Info1

Otra alternativa sería implementar CTE.

Common Table Expressions (“WITH ... AS ... SELECT”)

Available in: DSQL, PSQL

Added in: 2.1

Description: A common table expression or CTE can be described as a virtual table or view, defined in a preamble to a main query, and going out of scope after the main query's execution. The main query can reference any CTEs defined in the preamble as if they were regular tables or views. CTEs can be recursive, i.e. self-referencing, but they cannot be nested.

Syntax:

<cte-construct>  ::=  <cte-defs>
                      <main-query>

<cte-defs>      ::=  WITH [RECURSIVE] <cte> [, <cte> ...]

<cte>            ::=  name [(<column-list>)] AS (<cte-stmt>)

<column-list>    ::=  column-alias [, column-alias ...]

<cte-stmt>      ::=  any SELECT statement or UNION

<main-query>    ::=  the main SELECT statement, which can refer to the
                      CTEs defined in the preamble
Example:

with dept_year_budget as (
  select fiscal_year,
        dept_no,
        sum(projected_budget) as budget
  from proj_dept_budget
  group by fiscal_year, dept_no
)
select d.dept_no,
      d.department,
      dyb_2008.budget as budget_08,
      dyb_2009.budget as budget_09
from department d
    left join dept_year_budget dyb_2008
      on d.dept_no = dyb_2008.dept_no
      and dyb_2008.fiscal_year = 2008
    left join dept_year_budget dyb_2009
      on d.dept_no = dyb_2009.dept_no
      and dyb_2009.fiscal_year = 2009
where exists (
  select * from proj_dept_budget b
  where d.dept_no = b.dept_no
)
Notes:

A CTE definition can contain any legal SELECT statement, as long as it doesn't have a “WITH...” preamble of its own (no nesting).

CTEs defined for the same main query can reference each other, but care should be taken to avoid loops.

CTEs can be referenced from anywhere in the main query.

Each CTE can be referenced multiple times in the main query, possibly with different aliases.

When enclosed in parentheses, CTE constructs can be used as subqueries in SELECT statements, but also in UPDATEs, MERGEs etc.

In PSQL, CTEs are also supported in FOR loop headers:

for with my_rivers as (select * from rivers where owner = 'me')
    select name, length from my_rivers into :rname, :rlen
do
begin
  ..
end
Recursive CTEs

A recursive (self-referencing) CTE is a UNION which must have at least one non-recursive member, called the anchor. The non-recursive member(s) must be placed before the recursive member(s). Recursive members are linked to each other and to their non-recursive neighbour by UNION ALL operators. The unions between non-recursive members may be of any type.

Recursive CTEs require the RECURSIVE keyword to be present right after WITH. Each recursive union member may reference itself only once, and it must do so in a FROM clause.

A great benefit of recursive CTEs is that they use far less memory and CPU cycles than an equivalent recursive stored procedure.

The execution pattern of a recursive CTE is as follows:

The engine begins execution from a non-recursive member.

For each row evaluated, it starts executing each recursive member one-by-one, using the current values from the outer row as parameters.

If the currently executing instance of a recursive member produces no rows, execution loops back one level and gets the next row from the outer result set.

Example with a recursive CTE:

with recursive
  dept_year_budget as (
    select fiscal_year,
          dept_no,
          sum(projected_budget) as budget
    from proj_dept_budget
    group by fiscal_year, dept_no
  ),
  dept_tree as (
    select dept_no,
          head_dept,
          department,
          cast('' as varchar(255)) as indent
    from department
    where head_dept is null
    union all
    select d.dept_no,
          d.head_dept,
          d.department,
          h.indent || '  '
    from department d
        join dept_tree h on d.head_dept = h.dept_no
  )
select d.dept_no,
      d.indent || d.department as department,
      dyb_2008.budget as budget_08,
      dyb_2009.budget as budget_09
from dept_tree d
    left join dept_year_budget dyb_2008
      on d.dept_no = dyb_2008.dept_no
      and dyb_2008.fiscal_year = 2008
    left join dept_year_budget dyb_2009
      on d.dept_no = dyb_2009.dept_no
      and dyb_2009.fiscal_year = 2009
Notes on recursive CTEs:

Aggregates (DISTINCT, GROUP BY, HAVING) and aggregate functions (SUM, COUNT, MAX etc) are not allowed in recursive union members.

A recursive reference cannot participate in an outer join.

The maximum recursion depth is 1024.


  • 0

#5 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2137 posts

Posted 12 October 2012 - 12:49 PM

Muchas gracias Rolphy, voy a probar y te comento.

Un saludo
  • 0

#6 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 12 October 2012 - 01:04 PM

Desconocía eso del CTE.
Eso me pasa por estar con la 1.5, ¡y lo pior es que en Linux estoy con la 2.5 y aún no me puse a estudiar su documentación!  :o

Saludos,
  • 0

#7 fjcg02

fjcg02

    Newbie

  • Miembros
  • Pip
  • 4 posts

Posted 02 November 2012 - 03:11 AM

Hola,
te dejo un  link en el que en su día hablaba de una solución a este caso. EL procedimeinto almacenado te calcula primero las columnas y luego te construye la query. Esta consuklta es la que devuelve el SP, que será  la que debes ejecutar en tu programa o vía EXECSQL.

http://www.clubdelph...highlight=pivot

Espero que te sirva.

Un saludo
  • 0




IP.Board spam blocked by CleanTalk.