Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Alternative zu dynamic sql-cursor problematik (https://www.delphipraxis.net/151087-alternative-zu-dynamic-sql-cursor-problematik.html)

spaniac 5. Mai 2010 15:35

Datenbank: Mysql • Version: 5.x • Zugriff über: MySQL Query Browser bzw. Java

Alternative zu dynamic sql-cursor problematik
 
Moin moin,

nachdem ich meine ersten Erfahrungen mit Stored Procedures gemacht habe, stecke ich an einer Stelle nun erneut fest:


Ich muss eine Case-Anweisung ausführen, die je nach Fall ein SQL SELECT-Statement zusammenbaut. Aus diesem Grund baut meine SP einen String vom Typ TEXT zusammen, der das SQL SELECT-Statement enthält. Um das darin enthaltene Statement ausführen zu können, müssen die folgenden Befehle verwendet werden:

SQL-Code:
PREPARE stmt_name FROM preparable_stmt
und

SQL-Code:
EXECUTE stmt_name [USING @var_name [, @var_name] ...]
Problem ist jedoch, dass das Resultset des besagten SELECT-Statement danach einem Cursor zugewiesen werden soll, der dies in eine temporäre Tabelle schreibt.

Laut MySQL-Referenz kann ein Cursor jedoch nicht mit dynamischem SQL bzw EXECUTE etwas anfangen:

Zitat:

However, a cursor cannot be used for a dynamic statement that is prepared and executed with PREPARE and EXECUTE. The statement for a cursor is checked at cursor creation time, so the statement cannot be dynamic.

Wie kann ich dieses Problem auf einer andere Weise lösen? Weiss jmd eine andere Lösung, wie ich z.B. innerhalb der Case-Anweisung bereits den Cursor mit dem SELECT-Statement verknüpfe? Dann müsste ich den ganzen Umweg mit Stringkonvertierungen und dynamic sql nicht gehen...


Besten Dank schonmal für die Hilfe, anbei noch mein Code der Stored Procedure (vereinfacht):

SQL-Code:
DELIMITER $$

DROP PROCEDURE IF EXISTS `value_cur` $$

CREATE PROCEDURE `value_cur`(in_domain VARCHAR(45), in_startdate DATE, in_enddate DATE)
    READS SQL DATA
BEGIN
  DECLARE used_pilots       VARCHAR(45);
  DECLARE used_duration       VARCHAR(45);
  DECLARE temp_datum           DATE;
  DECLARE temp_value     FLOAT(7,2);
  DECLARE done               INT DEFAULT 0;
  DECLARE select_statement      TEXT;
 
  /*Has to be 'EXECUTE' instead of 'SELECT', but cursors only support 'SELECT'*/
  DECLARE cur1 CURSOR FOR SELECT sql_stmt;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;

  /*read config, select pilots*/
  SELECT duration, pilots
  INTO used_duration, used_pilots
  FROM config c
  WHERE c.domain=in_domain;

  /*CASE for duration*/
  CASE
    WHEN (used_duration = 5) THEN

   SET select_statement = CONCAT('SELECT datum, ',
      'SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END)AS wert ',
         'FROM element e ',
         'WHERE e.datum BETWEEN ? AND ? ',
         'AND e.pilot_id IN (?) ',
         'GROUP BY datum;');

    WHEN (used_duration = 15) THEN

   SET select_statement = CONCAT('SELECT datum, ',
      'SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END) ',
                '-SUM(CASE WHEN typ_id = 6 THEN wert ELSE 0 END)AS wert ',
         'FROM element e ',
         'WHERE e.datum BETWEEN ? AND ? ',
         'AND e.pilot_id IN (?) ',
         'GROUP BY datum;');

    WHEN (used_duration = 20) THEN

     SET select_statement = CONCAT('SELECT datum, ',
      'SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END) ',
      '+SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 6 THEN wert ELSE 0 END) ',
      '-SUM(CASE WHEN typ_id = 7 THEN wert ELSE 0 END)AS wert ',
         'FROM element e ',
         'WHERE e.datum BETWEEN ? AND ? ',
         'AND e.pilot_id IN (?) ',
         'GROUP BY datum;');

  END CASE;

  /* create tmp variables for dynamic-sql parameters*/
  SET @tmp_sql = select_statement;
  SET @tmp_in_startdate = in_startdate;
  SET @tmp_in_enddate = in_enddate;
  SET @tmp_used_pilots = used_pilots;

  PREPARE sql_stmt FROM @tmp_sql;
  EXECUTE sql_stmt USING @tmp_in_startdate, @tmp_in_enddate, @tmp_used_pilots;

  DROP TEMPORARY TABLE IF EXISTS temp_table_value;
  CREATE TEMPORARY TABLE temp_table_value (datum DATE, offeredcalls FLOAT(7,2));

  OPEN cur1;
  temp_loop:LOOP

    FETCH cur1 INTO temp_datum, temp_value;

    IF done=1 THEN
      LEAVE temp_loop;
    END IF;

    IF done=0 THEN

      INSERT INTO temp_table_value (datum, value)
      VALUES (temp_datum, temp_value);

    END IF;

  END LOOP temp_loop;

  CLOSE cur1;
  DEALLOCATE PREPARE x1;

END $$

DELIMITER ;

omata 5. Mai 2010 19:43

Re: Alternative zu dynamic sql-cursor problematik
 
Dir könnte man bestimmt helfen, aber leider hast du nichts darüber verraten, wie deine Datenbankstruktur aussieht, du hast keine Beispieldaten gezeigt und du hast nicht gezeigt was du eigentlich haben bzw. machen möchtest. Du bist festgefahren in deinem Weg und den willst du weitergehen, obwohl du herausgefunden hast, dass er nicht funktioniert.

Mein erster Ansatz (ohne eigentlich irgendetwas von dem zu wissen, was du da eigentlich vor hast) ist folgender...
SQL-Code:
SELECT datum,
       SUM(CASE WHEN   (used_duration = 5 AND typ_id = 1)
                     OR (used_duration = 15 AND typ_id = 2)
                     OR (used_duration = 20 AND typ_id = 3)
             THEN wert
             ELSE 0 
           END) AS value
FROM element e, config c
WHERE e.datum BETWEEN ? AND ? 
  AND ',' + REPLACE(used_pilots, ' ', '') + ',' LIKE '%,' + e.pilot_id + ',%'
  AND c.domain = :in_domain
GROUP BY datum
Wobei die Sache mit used_pilots einfach nicht klar ist. Und wenn ich das richtig interpretiert haben sollte, dann ist deine Datenbankstruktur an der Stelle total unbrauchbar.

Wie auch immer, diesen Text einfach ignorieren, falls ich mal wieder völlig falsch liege...

nahpets 6. Mai 2010 07:37

Re: Alternative zu dynamic sql-cursor problematik
 
Hallo,

Du hast da doch eine temporäre Tabelle, die Du wegwirfst und neu erstellst und dann per Cursor füllen willst.

Wie wäre denn mit einem
SQL-Code:
Create Table temp_table_value as select ...
also ungefähr so:
SQL-Code:
    SET select_statement = CONCAT('Create Table temp_table_value as SELECT datum, ',
      'SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END) AS value ',
         'FROM element e ',
         'WHERE e.datum BETWEEN ? AND ? ',
         'AND e.pilot_id IN (?) ',
         'GROUP BY datum;');
...
  PREPARE sql_stmt FROM @tmp_sql;
  EXECUTE sql_stmt USING @tmp_in_startdate, @tmp_in_enddate, @tmp_used_pilots;
Das sollte Dir den Cursor ersparen.

Mangels MySQL-Verfügbarkeit ungetestet.

Sofern möglich, ist die von Omata vorgeschlagene Variante vorzuziehen. Wenn MySQL Case im Select-Statement unterstützt, kommst Du mit einem Statement aus und hast damit Deinen Cursor.

spaniac 6. Mai 2010 14:57

Re: Alternative zu dynamic sql-cursor problematik
 
Hallo,

danke erst einmal für die Tipps. Ich hole noch einmal etwas weiter aus, um das Konstrukt zu verdeutlichen:

Ich habe meine Tabellenstruktur aus meinem alten Thread zu Grund liegend:

http://www.delphipraxis.net/internal...t.php?t=172714


DB-Struktur

SQL-Code:
SQL-Code:
Schema: element

SQL-Code:
SQL-Code:
id | datum | intervall | wert | typ_id | bereich_id
1 | 2009-01-01 | 8:00 | 3.0 | 2 | 2
2 | 2009-01-01 | 8:30 | 2.0 | 3 | 1
...
Die Abfrage für used_pilots könnt ihr getrost ignorieren, sie dient lediglich zur Einschränkung der pilot_id bzw. bereich_id! Ich habe die obige SQL-Anweisung noch einmal in den CASE-Schritten erweitert, ich dachte, die einfachere Berechnung trägt zum Verständnis bei, aber jetzt habe ich alle Schritte mit eingebunden (mehrere SUM-Anweisungen in der Abfrage!).

Die stored procedures
Zitat:

xxxx_cur
rechnen für einen bestimmten bereich (also für bestimmte used_pilots) einen Wert aus und packen den in einem temporäre tabelle (datum DATE, wert FLOAT(7,2)). Es gibt von diesen SP ca 5 Stk. die jeweils einen einzelnen Wert ausrechnen und den jeder in eine eigene temporäre Tabelle zusammen mit dem Datum packen.

Eine _main stored procedure ruft die ca 5 stk xxxx_cur stored procedures auf, und macht dann ein join über das datum, so dass am Ende eine _main temporäre Tabelle ensteht mit der Struktur (datum DATE, wert von xxxx1_cur, wert von xxxx2_cur, ...).

Die Problematik, warum ich überhaupt einen Case in der oben gezeigten Abfrage mache ist, dass verschiedene Bereiche (piloten) auch verschiedene Berechnungsmethoden für den eigentlich gleichen Wert haben. Das wird mit
Zitat:

used_duration
bewerkstelligt, die definiert, ob für den Bereich die Berechnung für 5, 15 oder 20s herangezogen wird.

Also, nochmal bildlich:

SP _main:

- ruft alle SP xxxx_cur auf und nimmt deren temp table entgegen
- joint die werte aller xxxx_cur an hand des datums
- format:
datum | xxxx_cur wert1 | xxxx_cur wert2| ...

SP xxxx_cur:

- berechnet einen wert an hand der used_duration (5, 15 oder 20) und den used_pilots (bereich)
- gibt temp table mit datum + einzelwert zurück.

Ist das ganze jetzt klarer geworden? :)

omata 6. Mai 2010 19:48

Re: Alternative zu dynamic sql-cursor problematik
 
Vielleicht so...
SQL-Code:
SELECT datum,
       SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END)
      +SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END)
      -SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END)
      -SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END)
      +SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END)
      - CASE WHEN duration IN (15, 20) THEN SUM(CASE WHEN typ_id = 6 THEN wert ELSE 0 END) ELSE 0 END
      - CASE WHEN duration = 20        THEN SUM(CASE WHEN typ_id = 7 THEN wert ELSE 0 END) ELSE 0 END AS wert
FROM element e, config c
WHERE datum BETWEEN :von AND :bis
  AND pilot_id = :pilot_id
  AND domain = :domain
GROUP BY datum

spaniac 7. Mai 2010 10:13

Re: Alternative zu dynamic sql-cursor problematik
 
@omata: allerbest, das klappt schonmal. einziger fehler: die werte werden jedes mal mit dem faktor 6 multipliziert im gegensatz dazu, wenn ich die select-anweisungen wie oben in 3 blöcke aufgeteilt habe. hast du eine idee, woran das liegen kann? Sobald ich die von Dir vorgeschlagene SELECT-Anweisung einzeln laufen lasse, werden die Werte nicht mit 6 multipliziert, also scheinbar hat es etwas mit dem Einlesen durch meinen Cursor zu tun...

SQL-Code:
DELIMITER $$

DROP PROCEDURE IF EXISTS `wert_cur` $$
CREATE PROCEDURE `wert_cur`(in_domain VARCHAR(45), in_startdate DATE, in_enddate DATE)
    MODIFIES SQL DATA
BEGIN
  DECLARE used_pilots       VARCHAR(45);
  DECLARE used_duration       VARCHAR(45);
  DECLARE temp_datum           DATE;
  DECLARE temp_wert      FLOAT(7,2);
  DECLARE done               INT DEFAULT 0;

  /*CASE for used_duration; calculate values*/

  DECLARE cur1 CURSOR FOR
  SELECT datum,
    SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END)
    +SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END)
    -SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END)
    -SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END)
    +SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END)
    -CASE WHEN used_duration IN (15, 20) THEN SUM(CASE WHEN typ_id = 6 THEN wert ELSE 0 END) ELSE 0 END
    -CASE WHEN used_duration = 20 THEN SUM(CASE WHEN typ_id = 7 THEN wert ELSE 0 END) ELSE 0 END AS wert
   FROM element e, config c
   WHERE datum BETWEEN in_startdate AND in_enddate
   AND e.pilot_id IN (used_pilots)
   GROUP BY datum;

  /*create continue handler*/
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;

  /*create temporary table*/
  DROP TEMPORARY TABLE IF EXISTS temp_table_wert;
  CREATE TEMPORARY TABLE temp_table_wert (datum DATE, offeredcalls FLOAT(7,2));

  /*read config, select pilots*/
  SELECT duration, pilots
  INTO used_duration, used_pilots
  FROM config c
  WHERE c.domain=in_domain;

  /*fetch values into temporary table*/
  OPEN cur1;
  temp_loop:LOOP

    FETCH cur1 INTO temp_datum, temp_wert;

    IF done=1 THEN
      LEAVE temp_loop;
    END IF;

    IF done=0 THEN

      INSERT INTO temp_table_wert (datum, offeredcalls)
      VALUES (temp_datum, temp_wert);

    END IF;

  END LOOP temp_loop;

  CLOSE cur1;
 
  SELECT * FROM temp_table_wert;

END $$

DELIMITER ;

omata 7. Mai 2010 10:46

Re: Alternative zu dynamic sql-cursor problematik
 
Zitat:

Zitat von spaniac
...Sobald ich die von Dir vorgeschlagene SELECT-Anweisung einzeln laufen lasse, werden die Werte nicht mit 6 multipliziert...

Und warum lässt du dann die Prozedur nicht einfach weg und nimmt nur die SQL-Anweisung?

Was macht die Prozedur denn so tolles in der Schleife? Ich verstehe die einfach nicht.

spaniac 7. Mai 2010 11:12

Re: Alternative zu dynamic sql-cursor problematik
 
die prozedur liest es in einem temporären table ein, der von der hauptprozedur xxxx_main genutzt wird. Leider geht das nicht anders, da ich mit der xxxx_main kein "call()" der untermethode machen kann.

das einlesen unten macht eigentlich nichts anderes als alle werte aus dem cursor in die tabelle zu packen, solange bis der continue handler = 1 ist... (also die abfrage keine werte mehr liefert...)

spaniac 7. Mai 2010 12:12

Re: Alternative zu dynamic sql-cursor problematik
 
nachtrag bzw. korrektur: wenn ich die von omata vorgeschlagene select-anweisung einzeln laufen lasse, tritt der fehler mit dem *6 ebenfalls auf. ich hatte nur eine falsche anweisung kopiert...

omata 7. Mai 2010 22:30

Re: Alternative zu dynamic sql-cursor problematik
 
Wie viele zeilen hat die config-Tabelle pro domain? Zufällig sechs? Das Konstrukt (die config) verstehe ich auch nicht wirklich.

Das Umkopieren von allen Zeilen geht auch einfacher, da ist kein Cursor nötig...
SQL-Code:
DELETE FROM temp_tabelle;
INSERT INTO temp_tabelle
SELECT *
FROM ...SQL-Abfrage...;

omata 9. Mai 2010 16:16

Re: Alternative zu dynamic sql-cursor problematik
 
Hier nochmal ein neuer Versuch...
SQL-Code:
SELECT datum,
       SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END)
      +SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END)
      -SUM(CASE WHEN typ_id = 3 THEN wert ELSE 0 END)
      -SUM(CASE WHEN typ_id = 4 THEN wert ELSE 0 END)
      +SUM(CASE WHEN typ_id = 5 THEN wert ELSE 0 END)
      - CASE WHEN duration IN (15, 20) THEN SUM(CASE WHEN typ_id = 6 THEN wert ELSE 0 END) ELSE 0 END
      - CASE WHEN duration = 20        THEN SUM(CASE WHEN typ_id = 7 THEN wert ELSE 0 END) ELSE 0 END AS wert
FROM element e, (SELECT DISTINCT duration
                 FROM config
                 WHERE domain = :domain) c
WHERE datum BETWEEN :von AND :bis
  AND pilot_id = :pilot_id
GROUP BY datum

spaniac 25. Mai 2010 09:20

Re: Alternative zu dynamic sql-cursor problematik
 
hi,

werde mich der thematik nachher noch einmal annehmen, war bis heute im urlaub. vielen dank schonmal für die hinweise!

Nachtrag: Tatsache, die *6-Problematik scheint an der Anzahl der Config-Einträge zu liegen, da ich jetzt einen Testeintrag angelegt habe und das Ganze jetzt *7 genommen wird...


EDIT: Erneuter Nachtrag: Wenn man aus der FROM-Klausel einfach das "FROM config c" entfernt, dann funktioniert die Funktion einwandfrei. used_duration wird an anderer Stelle eingelesen, somit ist "FROM config c" komplett überflüssig...

:wall:

spaniac 26. Mai 2010 11:57

Re: Alternative zu dynamic sql-cursor problematik
 
Liste der Anhänge anzeigen (Anzahl: 1)
so, wie gesagt, das obere problem ist gelöst worden, vielen dank für den input.

dennoch würde ich gerne noch einmal omatas anmerkung bezüglich des füllens der tabelle aufgreifen:

die von mir oben gezeigt funktion liefert nur die daten für die berechnung eines wertes (sagen wir wert1), ich habe jedoch eine hauptmethode, die alle werte zusammenfasst:


SQL-Code:
procedure main

ruft mehrere, verschiedene untermethoden auf, die jeweils eine tabelle mit der struktur

SQL-Code:
|datum|berechneter wert|
zurückliefern, also genau wie die oben bereits besprochene stored procedure.


SQL-Code:
procedure main
liefert also eine tabelle mit der struktur

SQL-Code:
|datum|berechneter wert von unterprocedure1|berechneter wert von unterprocedure2|berechneter wert von unterprocedure3|...

Dies mache ich eigentlich analog der oberen procedure:

SQL-Code:
DELIMITER $$

DROP PROCEDURE IF EXISTS `main_os` $$
CREATE PROCEDURE `main_os`(in_startdate DATE, in_enddate DATE)
    MODIFIES SQL DATA
BEGIN

  /*Declare variables*/
  DECLARE done_offeredcalls INT DEFAULT 0;
  DECLARE done_handledcalls INT DEFAULT 0;
  DECLARE done_answerquota INT DEFAULT 0;

  DECLARE temp_datum DATE;
  DECLARE temp_offeredcalls FLOAT(7,2);
  DECLARE temp_handledcalls FLOAT(7,2);
  DECLARE temp_answerquota FLOAT(7,2);

  /*Declare cursor to access temporary tables from underlying stored procedures*/

  DECLARE cur_offeredcalls CURSOR FOR
    SELECT *
    FROM temp_table_offeredcalls;

  DECLARE cur_handledcalls CURSOR FOR
    SELECT e.datum, SUM(e.wert)
    FROM element e WHERE e.pilot_id = 1 AND e.typ_id=1 AND e.datum BETWEEN in_startdate AND in_enddate GROUP BY e.datum;

  DECLARE cur_answerquota CURSOR FOR
    SELECT *
    FROM temp_table_answerquota;


  /*Declare continue handler to exit loop on empty row*/
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_offeredcalls=1, done_handledcalls=1, done_answerquota=1;

  /*Create temporary table to store all values from underlying stored procedures*/
  DROP TEMPORARY TABLE IF EXISTS temp_table_complete_os;
  CREATE TEMPORARY TABLE temp_table_complete_os (datum DATE, offeredcalls FLOAT(7,2), handledcalls FLOAT(7,2), answerquota FLOAT (7,2));


  /*Call stored procedure*/
  CALL offeredcalls_cur ('OS', in_startdate, in_enddate);

  /*Fetch offeredcalls-cursor values into temporary-table - uses sql-update-command to just add the values for the offeredcalls-column to the temporary table*/
  OPEN cur_offeredcalls;
  offeredcalls_loop:LOOP

    FETCH cur_offeredcalls INTO temp_datum, temp_offeredcalls;

    IF done_offeredcalls=1 THEN

      LEAVE offeredcalls_loop;

    END IF;

    IF done_offeredcalls=0 THEN

      INSERT INTO temp_table_complete_os (datum, offeredcalls)

      VALUES (temp_datum, temp_offeredcalls);

    END IF;

  END LOOP offeredcalls_loop;

  CLOSE cur_offeredcalls;


   /*Reset continue handler*/
  SET done_handledcalls=0;

  /*Fetch handledcalls-cursor values into temporary-table - no sql-update command needed*/
  OPEN cur_handledcalls;
  handledcalls_loop:LOOP

    FETCH cur_handledcalls INTO temp_datum, temp_handledcalls;

    IF done_handledcalls=1 THEN

      LEAVE handledcalls_loop;

    END IF;

    IF done_handledcalls=0 THEN

      UPDATE temp_table_complete_os

      SET handledcalls = temp_handledcalls

      WHERE datum = temp_datum;

    END IF;

  END LOOP handledcalls_loop;

  CLOSE cur_handledcalls;

  /*Reset continue handler*/
  SET done_answerquota=0;

  /*Call stored procedure*/
  CALL answerquota_cur ('OS', in_startdate, in_enddate);

  /*Fetch answerquota-cursor values into temporary-table - no sql-update command needed*/
  OPEN cur_answerquota;
  answerquota_loop:LOOP

    FETCH cur_answerquota INTO temp_datum, temp_answerquota;

    IF done_answerquota=1 THEN

      LEAVE answerquota_loop;

    END IF;

    IF done_answerquota=0 THEN

      UPDATE temp_table_complete_os

      SET answerquota = temp_answerquota

      WHERE datum = temp_datum;

    END IF;

  END LOOP answerquota_loop;

  CLOSE cur_answerquota;


  /*Returning the full temporary table*/
  SELECT *
  FROM temp_table_complete_os;


END $$

DELIMITER ;
Wie kann ich die nach der Erzeugung des temp_table_complete_os die Werte aus den anderen temporären Tabellen bzw. Cursorn einfacher einlesen bzw. in einem Durchlauf? Ich würde gerne vermeiden, für jede einzelne Subprocedur einen neuen LOOP zu machen.

Wie immer schon einmal vielen Dank im Voraus!

EDIT: Hier das ganze noch einmal grafisch dargestellt (siehe anhang)

spaniac 15. Jun 2010 08:36

AW: Alternative zu dynamic sql-cursor problematik
 
Hallo,

ich möchte noch kurz meinen Lösungsweg skizzieren, den ich jetzt für die ganzen Unterberechnungen angestellt habe:

Der Wert wird mit der Untermethode wie folgt berechnet. Hierbei wird ein temporary table erzeugt, der aus einem Datum+einem Wert besteht.

SQL-Code:
DELIMITER $$

DROP PROCEDURE IF EXISTS `slacd_cur` $$
CREATE PROCEDURE `slacd_cur`(in_domain VARCHAR(45), in_startdate DATE, in_enddate DATE)
    MODIFIES SQL DATA
BEGIN

    /*Call procedure to create temporary table with all pilots used in the specific domain*/
    /*get_used_pilots creates temporary table temp_table_used_pilots*/
    CALL get_used_pilots(in_domain);


      DROP TEMPORARY TABLE IF EXISTS temp_table_slacd;
      CREATE TEMPORARY TABLE temp_table_slacd AS SELECT datum,
           (SUM(CASE WHEN typ_id = 1 THEN wert ELSE 0 END)
           /SUM(CASE WHEN typ_id = 2 THEN wert ELSE 0 END))*100 AS slacd
      FROM element e, temp_table_used_pilots t
      WHERE e.datum BETWEEN in_startdate AND in_enddate
      AND e.pilot_id = t.pilot
      GROUP BY datum;

END $$

DELIMITER ;
Die Hauptmethode ruft danach mehrere dieser Unterprozeduren auf, füllt ein temporary table damit und gibt diesen table zurück:

SQL-Code:
DELIMITER $$

DROP PROCEDURE IF EXISTS `test_main_os` $$
CREATE DEFINER=`pentaho`@`%` PROCEDURE `test_main_os`(in_domain VARCHAR(45), in_agg VARCHAR(45),in_startdate DATE, in_enddate DATE)
    MODIFIES SQL DATA
BEGIN

  /*Create temporary table to store all values from underlying stored procedures*/

  /*Call stored procedure*/
  CALL slacd_cur (in_domain, in_agg, in_startdate, in_enddate);

    DROP TEMPORARY TABLE IF EXISTS temp_table_test_full;
    CREATE TEMPORARY TABLE temp_table_test_full
    AS SELECT a.datum, a.slacd, b.slcd
    FROM temp_table_slacd a
    JOIN temp_table_slacd b
    ON a.datum=b.datum;

  /*Returning the full temporary table*/
  SELECT *
  FROM temp_table_test_full;

END $$

DELIMITER ;
Ergebnis:

|datum | slacd1 | slcad2 |
|01.01.2010 | 11 | 23 |
|02.01.2010 | 12 | 27 |


Die Lösung ist DEUTLICH performanter als die zuerst genutzt Variante mit Cursorn und zudem durch einfacheren, reduzierteren Code zu erreichen :)

Besten Dank für die Hilfe! :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:22 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz