Laden...

[gelöst] Probleme mit Abfragen bei Firebird

Erstellt von GenesisCL vor 15 Jahren Letzter Beitrag vor 15 Jahren 10.146 Views
G
GenesisCL Themenstarter:in
33 Beiträge seit 2006
vor 15 Jahren
[gelöst] Probleme mit Abfragen bei Firebird

verwendetes Datenbanksystem: Firebird (Dateiversion 2.1)

Guten Abend zusammen,
sitze hier schon etwas bei aber komme nicht recht weiter mit einer Abfrage der Daten. In der SQL Anweisung sollte der Fehler nicht stecken da er bei der manuellen Abfrage(mit dem Datenbanktool FlameRobin) ohne Probleme funktioniert.

DB-Layout


CREATE TABLE diary (
id Integer NOT NULL, 
cat_id Integer NOT NULL, 
title Varchar(50) NOT NULL, 
startDate DATE NOT NULL, 
endDate DATE NOT NULL, 
startTime TIME,
endTime TIME,
wholeDay smallint DEFAULT 0,
PRIMARY KEY (id));

CREATE GENERATOR DIARY_GEN;

CREATE TRIGGER DIARY_ID FOR diary ACTIVE BEFORE INSERT POSITION 0 AS 
BEGIN
IF ((NEW.id IS NULL) OR (NEW.id = 0)) THEN 
NEW.id = GEN_ID(DIARY_GEN, 1);
END;

CREATE TABLE diary_categories ( 
id Integer NOT NULL, 
title varchar(25) NOT NULL,
setting varchar(25) DEFAULT 'black',
PRIMARY KEY (id)
);

Die Abfrage lautet:

SELECT a.*, b.id AS cat_id, b.title, b.setting FROM diary a LEFT JOIN diary_categories b ON (a.cat_id = b.id) WHERE startDate >= @startDate AND endDate <= @endDate AND b.id IN (@cats)

Der C#-Code mit dem ich die Abfrage durchführe:


public static AppointmentsBO[] GetAppointments(DateTime startDate, DateTime endDate, int[] items)
        {
            FbConnection db_con = Globals.Database.Connection;

            String inString = "";
            for(int i = 0; i < items.Length; i++) {
                if (inString == "")
                    inString += items[i];
                else
                    inString += ", " + items[i];
            }

            try
            {
                db_con.Open();
                FbDataAdapter da = new FbDataAdapter(AppointmentsDAL.SelectCommandByDateRangeCategory(), db_con);
                da.SelectCommand.Parameters.AddWithValue("@startDate", startDate.ToString("d"));
                da.SelectCommand.Parameters.AddWithValue("@endDate", endDate.ToString("d"));
                da.SelectCommand.Parameters.AddWithValue("@cats", inString);
                DataSet data = new DataSet();
                da.Fill(data);
                DataTable dt = data.Tables[0];
                DataRowCollection rows = dt.Rows;
                AppointmentsBO[] retData = new AppointmentsBO[rows.Count];

                ....
                ....
                ....

                return retData;
            }
            catch
            {
                throw;
            }
            finally
            {
                db_con.Close();
                db_con.Dispose();
            }
        }

Wobei AppointmentsDAL.SelectCommandByDateRangeCategory() den obigen SQL-String übergibt. Komischerweise liefert es ein leeres Resultat zurück. Jemand Anregungen was ich falsch mache bzw wo das Problem liegt?

M
234 Beiträge seit 2007
vor 15 Jahren

An den fehlenden Tablenamen in der Where-Klausel dürfte es nicht liegen.

Eine Fehlermeldung kommt nicht, richtig?

Entschlack deine Abfrage mal und pack dann immer mehr mit rein. Also erst das einfache Select mit dem Left Join, dann die Where-Bedingung(en) dazu.

G
GenesisCL Themenstarter:in
33 Beiträge seit 2006
vor 15 Jahren

Benutze ich den obigen Code bekomme ich eine FormatException(Die Eingabezeichenfolge hat das falsche Format.) bei da.fill(data) weswegen ich es noch etwas abgeändert habe:


public static AppointmentsBO[] GetAppointments(DateTime startDate, DateTime endDate, int[] items)
        {
            FbConnection db_con = Globals.Database.Connection;

            String inString = "";
            for(int i = 0; i < items.Length; i++) {
                if (inString == "")
                    inString += items[i];
                else
                    inString += ", " + items[i];
            }

            try
            {
                db_con.Open();
                FbDataAdapter da = new FbDataAdapter(AppointmentsDAL.SelectCommandByDateRangeCategory(), db_con);
                da.SelectCommand.Parameters.AddWithValue("@startDate", startDate.ToString("d"));
                da.SelectCommand.Parameters.AddWithValue("@endDate", endDate.ToString("d"));
                da.SelectCommand.Parameters.Add("@cats", FbDbType.Text);
                da.SelectCommand.Parameters.AddWithValue("@cats", inString);
                DataSet data = new DataSet();
                da.Fill(data);
                DataTable dt = data.Tables[0];
                DataRowCollection rows = dt.Rows;
                AppointmentsBO[] retData = new AppointmentsBO[rows.Count];

                ....
                ....
                ....

                return retData;
            }
            catch
            {
                throw;
            }
            finally
            {
                db_con.Close();
                db_con.Dispose();
            }
        }

Die Exception ist weg aber er gibt keine Daten zurück.

Ich habe auch mal die Abfrage geändert in:

SELECT a.*, b.id AS cat_id, b.title, b.setting FROM diary a LEFT JOIN diary_categories b ON (a.cat_id = b.id) WHERE startDate >= @startDate AND endDate <= @endDate

diese funktioniert auch einwandfrei, es liegt also an der IN Abfrage.

Setze ich für inString einfach mal "1,2,3,4,5,6,7,8,9,10" ein, geht es auch nicht(um ausszuschliessen das die Kategorien nicht vorhanden sind).

Bei
da.SelectCommand.Parameters.Add("@cats", FbDbType.Text);
habe ich auch mal versucht einen anderen FbDbType zu setzen, ohne Erfolg.

J
3.331 Beiträge seit 2006
vor 15 Jahren

Hallo,

es spricht vieles dafür, dass die Art der **DbParameter **zu dem Fehler führt. So sollte es gehen:

da.SelectCommand.Parameters.AddWithValue("@startDate", startDate);

Erklärung: Bei Deiner Variante übergibst Du dem Parameter einen String, sagst also ausdrücklich, dass er einen String nach der aktuellen Kultur daraus machen soll und diesen an die DB übergeben soll. Der Parameter wird als String, nicht als DateTime eingetragen. Damit erwartest Du, dass der DbProvider bzw. die DB selbst den String richtig als Datum interpretieren soll; das kann aber wegen unterschiedlicher Formatierungen schief gehen.

Dein Vorgehen widerspricht genau dem Vorteil von DbParameter, dass nämlich der DbProvider die Typen richtig zuordnet sowie überflüssige und fehleranfällige Konvertierungen vermieden werden.

Gewöhne Dir an, mit DbParameter und immer den wirklichen Typen zu arbeiten, und Du ersparst Dir viel Fehlersuche! Jürgen

G
GenesisCL Themenstarter:in
33 Beiträge seit 2006
vor 15 Jahren

Das Problem ist nicht das Datum sondern die Kategorien, also der Parameter @cats. Dieser wird nicht akzeptiert wie ich in dem vorherigen Post schon geschrieben habe. Ich suche also den korrekten Weg inString an den Adapter zu übergeben. Setze ich inString direkt in den SQ-Befehl ein funktioniert es ohne Probleme


String cmd = "SELECT a.*, b.id AS cat_id, b.title AS cat_name, b.setting FROM diary a LEFT JOIN diary_categories b ON (a.cat_id = b.id) WHERE startDate >= @startDate AND endDate <= @endDate AND b.id IN (" + catIDs + ")";

.
Hat noch jemand eine Idee?

J
3.331 Beiträge seit 2006
vor 15 Jahren

Entschuldige, den Hinweis auf den IN-Parameter hatte ich überlesen.

Aber damit ist das Problem klar: Du willst einen String übergeben, wo der IN-Parameter in Firebird eine Liste verschiedener Werte (u.U. erzeugt durch eine innere Abfrage) erwartet.

Ich glaube, dass ich vor einiger Zeit mal etwas zu diesem Problem gelesen habe, habe aber keine richtige Idee, welche Stichwörter zur Forumssuche geeignet sind und in welchem Forum das war.

Versuche einmal die Forumssuche mit parameter liste; darunter gibt es Problem mit IN - Operator ohne richtige Lösung.

Jürgen

X
1.177 Beiträge seit 2006
vor 15 Jahren

Hallo,

jaja, Parameter werden immer als Dateneintrag angesehen und nicht intern (automatisch) in den SQL-String eingebaut.

Ich versuchs mal schnell on the fly:


public class AppointmentsDAL
{
//..
    public string SelectCommandByDateRangeCategory(int[] items)
    {
        String SQL = "SELECT a.*, b.id AS cat_id, b.title AS cat_name, b.setting FROM diary a LEFT JOIN diary_categories b ON (a.cat_id = b.id) WHERE startDate >= @startDate AND endDate <= @endDate AND b.id IN (";
        for (int i = 0; i < items.Length; i++)
        {
            SQL += "@InItem" + i.ToString() + ",";
        }
        SQL = SQL.Remove(SQL.Length - 1, 1) + ")";
        return SQL;
    }
//..
}

public static AppointmentsBO[] GetAppointments(DateTime startDate, DateTime endDate, int[] items)
{
    using (FbConnection db_con = Globals.Database.Connection)
    {
        try
        {
            db_con.Open();
            FbDataAdapter da = new FbDataAdapter(AppointmentsDAL.SelectCommandByDateRangeCategory(), db_con);
            da.SelectCommand.Parameters.Add(new DbParameter("@startDate", DbType.DateTime).Value = startDate);
            da.SelectCommand.Parameters.Add(new DbParameter("@endDate", DbType.DateTime).Value = endDate);
            for (int i = 0; i < items.Length; i++)
            {
                da.SelectCommand.Parameters.Add(new DbParameter("@InItem" + i.ToString(), DbType.Int32).Value = items[i]);
            }
            //...
            return retData;
        }
        catch
        {
            throw;
        }
    }
}


EDIT: sollte eigentlich so hinhauen, da deinem SQL-Statement mehrere zusätzliche Parameter angefügt und diese dann mit den entsprechenden Werten Assoziier werden. Parameter heissen dann:


IN (@InItem0, @InItem1, @InItem2)

🙂

Xynratron

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.

G
GenesisCL Themenstarter:in
33 Beiträge seit 2006
vor 15 Jahren

Danke Xynratron, deine Lösung hat funktioniert auch wenn ich sie etwas anpassen musste.

Bei der Schreibweise

da.SelectCommand.Parameters.Add(new DbParameter("@startDate", DbType.DateTime).Value = startDate);

habe ich ne InvalidCastException(The parameter passed was not a FbParameter.) bekommen während der Laufzeit. Anstatt DbParameter habe ich fbParameter genohmen aber hatte auch nix gebracht. Habe jetzt die etwas längere Variante genohmen die funktioniert.


FbParameter para1 = new FbParameter("@startDate", FbDbType.Date);
para1.Value = startDate;
da.SelectCommand.Parameters.Add(para1);