Laden...

MSSQL - InnerJoin mit Datumsfilter ist immer leer

Erstellt von RStorm vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.262 Views
R
RStorm Themenstarter:in
16 Beiträge seit 2009
vor 4 Jahren
MSSQL - InnerJoin mit Datumsfilter ist immer leer

Hallo Gemeinde,

ich versuche mich derzeit mit ASP.NET mit SQL.

Soweit so gut, was bis jetzt geht ist:

  • ich kann die Verbindung zum SQL-Server aufbauen.
  • ich kann kann ein einfach SQL Abfrage absetzen und das Result verwerten und im View anzeigen

Allerdings habe ich hier jetzt das Problem, wenn ich ein SELECT mit Inner Join absetze, in dem ich nach einem Datum selektiere, das DataRow leer ist beim Debugging sehe ich dann "Enumeration yielded no results".

Setze ich die gleich Abfrage im HeidiSQL oder MSSM Studio ab, bekomme ich die Daten aber vollständig angezeigt.

" AND (b.DATUM = '{1} 00:00:00.000')", k.NR, DateTime.Now.ToString("yyyy-MM-dd"));" änder ich in dieser Zeile das Datum auf "2019-10-01 00:00:00.000" dann bekomme ich ein Daten zurück aber auch nur mit diesem Datum.

Jemand eine Idee was das sein könnte?

Meine SQL Abfrage:



       [HttpGet]
        public IEnumerable<IEnumerable<ViewUser>> Get()
        {            
            DataSet dataSet = new DataSet();
            status_rueckgabe sr = OpenSQLConnection();
            
            List<Kostenstellen> Kost = new List<Kostenstellen>();
            List<List<ViewUser>> vuAll = new List<List<ViewUser>>();

            if (sr.Result == true)
            {
                //Kostenstellen Abrufen
                dataSet = sr.SQLService.GetDataSetFromStatement(string.Format("SELECT NR, BEZ FROM KOSTSTEL"));
                foreach (DataRow dr in dataSet.Tables[0].Rows)
                {
                    Kost.Add(new Kostenstellen(dr.ItemArray[0].ToString(),
                                                             dr.ItemArray[1].ToString()
                                             ));
                }

                dataSet.Clear();

               //Alle Daten für die jeweilige Kostenstelle abrufen
                foreach (Kostenstellen k in Kost)
                {
                    List<ViewUser> vu = new List<ViewUser>();

                    string sqlquery = string.Format("SET DATEFORMAT ymd;     " +    // Ohne diese Zeile wird das Datum vertauscht zurück gegeben
                                                    "    SELECT Stamm.PNR AS POSITION, " +
                                                    "                Stamm.NAME, " +
                                                    "                Stamm.VNAME, " +
                                                    "                w.BEZ AS Werk, " +
                                                    "                k.BEZ as Kostenstelle, " +
                                                    "                b.DATUM AS Angemeldet " +
                                                    "       FROM STAMM Stamm " +
                                                    "Inner JOIN BUCHUN b ON Stamm.PNR = b.PNR " +
                                                    "Inner JOIN KOSTSTEL k ON Stamm.KOST = k.NR " +
                                                    "Inner JOIN WERK w ON Stamm.WERK = w.NR " +
                                                    "     WHERE k.NR = '{0}' " +
                                                    "       AND (b.DATUM = '{1} 00:00:00.000')", k.NR, DateTime.Now.ToString("yyyy-MM-dd"));
            
                    dataSet = sr.SQLService.GetDataSetFromStatement(sqlquery);
                        

// Hier sind dann keine Daten in dem Datarow
// und als Meldung steht "Enumeration yielded no results".

                    // Daten auswerten
                    foreach (DataRow dr in dataSet.Tables[0].Rows)
                    {
                        vu.Add(new ViewUser(dr.ItemArray[0].ToString(),
                                            dr.ItemArray[1].ToString(),
                                            dr.ItemArray[2].ToString(),
                                            dr.ItemArray[3].ToString(),
                                            dr.ItemArray[4].ToString(),
                                            dr.ItemArray[5].ToString()
                                            ));
                    }
                    vuAll.Add(vu);
                }
            }
            else
            {

            }

            return vuAll;
        }


        private status_rueckgabe OpenSQLConnection()
        {
            status_rueckgabe sr = new status_rueckgabe();
            var ConnectionString = Configuration.GetConnectionString("AZSString");
            DatenbankService.MSSQL ds = new DatenbankService.MSSQL(ConnectionString);

            sr = ds.CheckConnection();
            sr.SQLService = ds;
            return sr;
        }

T
2.224 Beiträge seit 2008
vor 4 Jahren

Folgende Artikel würde ich dir ans Herz legen.

[Artikel] Drei-Schichten-Architektur
[Artikelserie] SQL: Parameter von Befehlen

Letztes dürfte dein Problem ggf. auch lösen, wenn die Werte korrekt sind.
Bitte niemals die Werte in einen String schreiben und so gegen die Datenbank schicken.
Damit öffnest du SQL Injections Tür und Tor!

In deine Api gehört auch kein Code zur Abfrage gegen die Datenbank.
Hier musst du dringend saubere Schichten zur Trennung des Codes einbauen.
Datenbankabfragen haben weder in der UI noch in der API was verloren!

Zuletzt empfehle ich dir auch mal mit dem DataReader zu arbeiten.
Auf DataTable solltest du soweit wie möglich verzichten.
Über den DataReader kannst du deine Objekte direkt in einer Schleife auslesen.
Alternativ kannst du auch auf OR Mapper wie Dapper oder Entity Framework Core aufsetzen, diese nehmen die solche Dinge ab.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

R
RStorm Themenstarter:in
16 Beiträge seit 2009
vor 4 Jahren

Hallo T-Virus,

Sorry für die verspätete Antwort und danke für die Lehrreichen Links.

Normalerweise, unter WPF, verwende ich MVVM und kapsle meine Klassen nach Schichten. Wie aber schon gesagt hier versuche ich mit ASP.NET und React einzusteigen und um etwas zu Probieren da hatte ich da mit rein gepackt wo ich gerade war.

Vielen vielen Dank für den Support, es klappt jetzt so, ich bekomme die richtigen Daten zurück.
Ich hab meine ganze Funktionen für SQL angepasst und umgeschrieben, dadurch habe ich auch meine SQL LIB angepasst und Optimiert, das ist super.

Was ich noch nicht weiß ob ich das etwas automatisieren kann, das ich bei den Parameter die auch über ein Array übergeben kann und durchlaufen so könnte ich eine Funktion mehr mal benutzen.
Mein Problem ist bis jetzt wie übergebe ich die Parameter Bezeichnung (@parametername), da muss ich mir mal als nächstes anschauen.

Dankeschön noch mal für den Tip und die Links.

Gruß

Rudolf

T
2.224 Beiträge seit 2008
vor 4 Jahren

Kommt darauf an, was du damit meinst.
Wenn du z.B. eine Methode brauchst um einen DataReader für unterschiedliche Abfragen zu bekommen, kannst du dir dafür auch eine entsprechende Klasse anlegen und pro Datentypen dann von dieser ableiten.
Damit kannst du grundlegende Operationen in eine Basis Klasse auslagern mit denen du dann in deinen davon abgeleiteten Klassen arbeiten kannst.
Diese bietet dir dann z.B. eine Methode GetDataReader(string queryString, params SqlParameter[] parameters);



// Methode aus Klasse BaseDataLayer
public SqlDataReader GetDataReader(string, queryString, params SqlParameter[] parameters)
{
    // TODO:
    // Hier SqlConnection öffnen, SqlCommand anlegen und SqlCommand.Parameters mit parameters befüllen
    // Am Ende SqlDataReader über SqlCommand.ExecuteReader an den Aufrufer zurück geben.
}


// Methode in abgeleieteter Klasse
public DataEntry LoadDataEntry(Guid id)
{
    string queryString = "SELECT Id, ... FROM DataEntries WHERE ID=@ID";

    // Code deiner Abgeleiteten Klasse
    using(IDataReader reader = this.GetDataReader(sql, new SqlParameter("@ID", id)))
    {
        return reader.Read() ? LoadDataEntryFromDataReader(reader) : null;
    }
}

public List<DataEntry> LoadDataEntry()
{
    string queryString = "SELECT Id, ... FROM DataEntries";
    List<DataEntry> entries = new List<DataEntry>();

    // Code deiner Abgeleiteten Klasse
    using(IDataReader reader = this.GetDataReader(sql)
    {
        while(reader.Read())
            entries.Add(LoadDataEntryFromDataReader(reader));
    }

    return entries;
}

Wenn du dir aber sowas sparen willst, schau dir Dapper/Entity Framework Core an.
Da entfallen solche Ansätze fast.
Dort gibt es schon fertige Lösungen für solche Probleme, die vermutlich auch besser sind als das Rad neu zu entwickeln 😃

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.842 Beiträge seit 2008
vor 4 Jahren

Bitte bei sowas immer Why is SELECT * considered harmful? beachten, wenn man es schon exemplarisch zeigt.

T
2.224 Beiträge seit 2008
vor 4 Jahren

@Abt
Hab ich angepasst 😃
Hatte den Code nur schnell runter getippt und da solche Kleinigkeiten einfach ignoriert.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.