Einzelnen Beitrag anzeigen

Jürgen Thomas

Registriert seit: 13. Jul 2006
Ort: Berlin
750 Beiträge
 
#5

Re: SProc misslungen: multiple rows in singleton select

  Alt 29. Jul 2006, 17:27
Bitte sehr:
SQL-Code:
/*  im ersten SQL-Skript:  */
CREATE PROCEDURE Logbuch_Start
        ( Daten_Nr INTEGER, Selektion_Nr INTEGER, Formular_Nr SMALLINT )
RETURNS ( neu_ID INTEGER, Neuer_Monat BOOLEAN ) AS
BEGIN
  EXIT;
END
/*  in einem späteren SQL-Skript:  */
ALTER PROCEDURE Logbuch_Start
        ( Daten_Nr INTEGER, Selektion_Nr INTEGER, Formular_Nr SMALLINT )
RETURNS ( neu_ID INTEGER, Neuer_Monat BOOLEAN ) AS
  DECLARE VARIABLE Computer_Name VARCHAR(35);
  DECLARE VARIABLE Nutzer_Name VARCHAR(35);
  DECLARE VARIABLE Nutzer_Nr INTEGER;
  DECLARE VARIABLE b1 BOOLEAN;
  DECLARE VARIABLE t1 TIME;
  DECLARE VARIABLE d1 DATE;
  DECLARE VARIABLE d2 DATE;
BEGIN
  /*  alle frueheren Eintraege, die nicht beendet wurden, werden
      beim Programmstart mit dem Vermerk 'Programmabsturz?' versehen  */

  IF ( Formular_Nr IS NULL )
  THEN Formular_Nr = 0;
  IF ( Formular_Nr = 0 )
  THEN BEGIN
    t1 = '23:59:59';
    d1 = CURRENT_DATE;
    UPDATE Logbuch
       SET Ende = CAST( Ende AS DATE ) + :t1,
           Bemerkung = 'Programmabsturz?'
     WHERE ( ( Start = Ende )
         AND ( Ende < :d1 )
         AND ( Bemerkung = '' ) );
  END

  /*  Nutzer-ID wird durch USER aus der Tabelle Nutzer geholt  */
  Nutzer_Name = USER;
  Nutzer_Nr = NULL;
  EXECUTE PROCEDURE ID_Suchen_Nutzer ( '', NULL, :Nutzer_Name )
                   RETURNING_VALUES :Nutzer_Nr, :Nutzer_Name;
  /*  sicherheitshalber ersatzweise auf 0 setzen  */
  IF ( ( Nutzer_Nr IS NULL ) OR ( Nutzer_Nr < 0 ) )
  THEN Nutzer_Nr = 0;

  /*  Computer-Name von Interbase holen  */
  Computer_Name = NULL;
  SELECT TMP$USER_HOST FROM TMP$ATTACHMENTS WHERE TMP$USER = USER
                               INTO :Computer_Name;
  IF ( Computer_Name IS NULL )
  THEN Computer_Name = '';

  /*  andere Angaben werden auf Standards gesetzt, sofern erforderlich  */
  IF ( Daten_Nr IS NULL )
  THEN Daten_Nr = 0;
  IF ( Selektion_Nr IS NULL )
  THEN Selektion_Nr = 0;
  neu_ID = GEN_ID( Logbuch_id, 1 );
  INSERT INTO Logbuch ( ID, Nutzer_ID, Daten_ID, Selektion,
                        Computer, Formular, Start, Ende, Bemerkung )
               Values ( :neu_ID, :Nutzer_Nr, :Daten_Nr, :Selektion_Nr,
                        :Computer_Name, :Formular_Nr,
                        CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '' );

  /*  Einstellungen aktualisieren  */
  Neuer_Monat = False;
  IF ( Formular_Nr = 0 )
  THEN BEGIN
    EXECUTE PROCEDURE Einstellungen_Computerstart
               ( Computer_Name, Nutzer_Name, neu_ID );
    /*  kontrolliere, ob ein neuer Monat begonnen hat und
        folglich die monatlichen Anpassungen zu erledigen sind  */

    SELECT Datum1 FROM Einstellungen WHERE Bezeichnung = 'Interna-DB'
                               INTO :d2;
    IF ( d2 < d1 )
    THEN Neuer_Monat = True;
  END
  SUSPEND;
END
Wie früher bereits gesagt: Aus der IBConsole heraus durch
SELECT * FROM Logbuch_Start(0,0,0) wird genau eine Zeile zurückgegeben.

Hilft diese Angabe? (Ich hoffe, dass es nicht nötig ist, auch die anderen Prozeduren und die Tabellen zu erläutern.) Jürgen

Nachtrag zu @Hansa

Zitat von Hansa:
Inwiefern ist hier ... sichergestellt, daß die Datenmenge nur aus einem Element besteht ? :shock:
Siehe auch den vollständigen Code; 'Bezeichnung' ist PrimaryKey von Einstellungen.

Nachtrag 2 zu @Hansa

Zitat von Hansa:
Öfter mal was neues : Erläuterung zu später gestellter Nachfrage wird vor diese gesetzt. Jaja, die Kausalität.
Ich habe den Eindruck, dass die Moderatoren sauer werden, wenn ein neuer Eintrag hinzugefügt wird, statt dass ein vorheriger Eintrag mit Edit geändert wird...
Zitat von Hansa:
'Bezeichnung' ist PrimaryKey von Einstellungen. - Das ist doch dem primary Key alles egal. Du kriegst (siehe Fehlermeldung) eben definitiv NICHT nur ein Element zurück !
Das kann doch nicht sein (und ist in der IBConsole auch nicht so)! PrimaryKey ist automatisch unique. Wenn ich also
SELECT Datum1 FROM Einstellungen WHERE Bezeichnung = 'Interna-DB' abfrage, gibt es definitiv nur den eindeutigen (= unique) Datensatz.

Nachtrag zu @Dataspider
Zitat von dataspider:
Paramteter mismatch kommt von Formular_Nr -> Int32 statt Int16 (im ersten Beitrag richtig).
 SELECT TMP$USER_HOST FROM TMP$ATTACHMENTS WHERE TMP$USER = USER INTO :Computer_Name; Erst mal nur als Frage:
TMP$ATTACHMENTS erzeugt für jede Verbindung einen Datensatz.
Wenn sich der gleiche User 2 mal verbindet, liefert dann dein Select evtll 2 Records?
Frank
Au ja, beides muss ich prüfen: (1) Formular_Nr habe ich vielleicht im C#-Code bei einem Parameter falsch eingetragen. (2) Es ist denkbar, dass zu diesem Zeitpunkt eine Verbindung über IBConsole (zur Kontrolle) und eine durch die Anwendung (mit dem o.g. Problem) besteht; ich muss die Abfrage nach dem Computer_Name verfeinern.

Dann ist dies natürlich nicht in Ordnung. Aber kann es wirklich Auswirkung auf den Suspend-Befehl und die eigentliche Fehlermeldung haben?

Mit diesen Hinweisen komme ich wenigstens weiter. Jürgen

PS. Das ist eines meiner Probleme als Einzelkämpfer: Manchmal erkennt man solche Situationen nicht selbst, sondern muss darauf hingestoßen werden.
#D mit C# für NET, dazu Firebird
früher: Delphi 5 Pro, Delphi 2005 Pro mit C# (also NET 1.1)
Bitte nicht sauer sein, wenn ich mich bei Delphi-Schreibweisen verhaue; ich bin inzwischen an C# gewöhnt.
  Mit Zitat antworten Zitat