Problem Datatable Select

  • VB.NET
  • .NET 4.5

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von Westerwälder.

    Problem Datatable Select

    Hallo und guten Abend,

    habe ein Problem mit folgender Select-Anweisung:

    Jahr=2020 AND Monat=6 AND MH=100 OR MH=101 OR MH=102

    Bekomme nicht die Daten, welche ich möchte.
    Jahr und Monat müssen eingehalten werden.

    Feld MH kann 100, 101 oder 102 sein.
    Alle Felder sind vom Type Integer.

    Was mache ich da falsch?
    Gruß Markus
    Auch wenn ich überhaupt keine Ahnung habe, in welcher Syntax Du Dich gedanklich befindest oder was MH bedeutet, könnte es daran liegen, dass Du schreiben musst:
    Jahr=2020 AND Monat=6 AND (MH=100 OR MH=101 OR MH=102), da Du AND wie eine Multiplikation sehen solltest und OR wie eine Addition. Und ohne Klammern käme da Punktrechnung vor Strichrechnung. Nach der von Dir getroffenen Aussagenlogik ist das Ganze wahr, wenn Jahr=2020 AND Monat=6 AND MH=100 oder MH = 101 oder 102, also letzterer Bereich unabhängig von Jahr und Monat.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Hallo,

    habe mal wieder ein Problem mit Datatable und dem Select.

    Hier der Code:

    VB.NET-Quellcode

    1. Dim Filter = From Order In DAB.DataTabelle.AsEnumerable
    2. Where Order.Field(Of Integer)("Nummer") = 100
    3. Where CDate(Order.Field(Of String)("Bis") & " 12:00:00") <= CDate(Datum.ToShortDateString & " 12:00:00")
    4. Where CDate(Order.Field(Of String)("Von") & " 12:00:00") >= CDate(Datum.ToShortDateString & " 12:00:00")
    5. Select Order


    Es sind zur Zeit nur zwei Datensätze in der Tabelle enthalten.

    1.) Nummer 100; Von 01.01.1949; Bis 31.01.2001
    2.) Nummer 100; Von 01.01.2002; Bis 23.06.2020

    Egal welches Datum ich abfrage, es werden immer beide Datensätze gefunden.
    Auch ein And ändert nichts:

    VB.NET-Quellcode

    1. Dim Filter = From Order In DAB.DataTabelle.AsEnumerable
    2. Where Order.Field(Of Integer)("Nummer") = 100 And
    3. CDate(Order.Field(Of String)("Bis") & " 12:00:00") <= CDate(Datum.ToShortDateString & " 12:00:00") And
    4. CDate(Order.Field(Of String)("Von") & " 12:00:00") >= CDate(Datum.ToShortDateString & " 12:00:00")
    5. Select Order

    Gruß Markus

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Westerwälder“ ()

    Keiner eine Idee?

    Muss dann wohl die gesamte Tabelle durchlaufen und
    expliziert auf die Bedingungen verweisen.
    Wollte ich eigentlich vermeiden.

    Edit:
    Hintergrund des Gedanken ist, die bevorstehende Änderung der Mehrwertsteuersätze zum 01.07.2020, welcher ja im Voraus schon befristet ist, abzufragen.
    Hier soll nach Übergabe des Rechnungsdatum automatisch der reguläre MwSatz übergeben werden.
    Im Prinzip soll dieses dann auch für Haben- und Sollzinssätze, oder auch für die aktuelle Währung gelten.

    Gruß Markus

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Westerwälder“ ()

    Westerwälder schrieb:

    Hintergrund des Gedanken ist, die bevorstehende Änderung der Mehrwertsteuersätze zum 01.07.2020, welcher ja im Voraus schon befristet ist, abzufragen.

    [OffTopic]
    als ich das in den Nachrichten hörte dachte ich daran, dass damit Tausende von Programmierern mit Eilaufträgen überlastet werden.
    Naja, gut für die Branche.
    Wohl dem, der die MwSt-Sätze nicht hart codierte, sondern mit Gültigkeits-Zeitspanne in der Datenbank liegen haben.
    SCNR
    [/OffTopic]

    Westerwälder schrieb:

    Muss dann wohl die gesamte Tabelle durchlaufen
    Warum liegen die Datumsangaben in der Auftragstabelle eigentlich in String-Form vor?
    Und dann auch noch in unsortierbarem Format?
    Hier rächt sich wohl das unsaubere Datenbank-Design.

    CDate(Order.Field(Of String)("Bis") & " 12:00:00") <= CDate(Datum.ToShortDateString & " 12:00:00")
    Vegleiche nur den Datumsanteil des Zeitstempels anstatt künstlich irgendwelche Zeitstempel anzuhängen.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    Da kommt's wohl drauf an, was in Deiner DataTable steht. Ich hab's testweise damit probiert:

    VB.NET-Quellcode

    1. Dim DT As New Data.DataTable
    2. DT.Columns.Add("Nummer", GetType(Integer))
    3. DT.Columns.Add("Bis", GetType(String))
    4. DT.Columns.Add("Von", GetType(String))
    5. DT.Rows.Add(100, "01.01.1949", "31.01.2001")
    6. DT.Rows.Add(100, "01.01.2002", "23.06.2020")
    7. Dim Datum = Date.Today.AddYears(-20)'oder -19 oder -18
    8. Dim Filter = From Order In DT.AsEnumerable
    9. Where Order.Field(Of Integer)("Nummer") = 100 And
    10. CDate(Order.Field(Of String)("Bis") & " 12:00:00") <= CDate(Datum.ToShortDateString & " 12:00:00") And
    11. CDate(Order.Field(Of String)("Von") & " 12:00:00") >= CDate(Datum.ToShortDateString & " 12:00:00")
    12. Select Order
    Funktioniert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Die Tabelle ist aufgebaut, wie von VaporiZed getestet.

    Aber aus irgendeinem Grund will es nicht funktionieren.

    VB.NET-Quellcode

    1. Dim Zeile As DataRow
    2. Public Property Waehrung_Lang(Datum As Date) As String
    3. Get
    4. Dim Filter = From Order In DAB.DataTabelle.AsEnumerable
    5. Where Order.Field(Of Integer)("Nummer") = 100 And
    6. CDate(Order.Field(Of String)("Bis") & " 12:00:00") <= CDate(Datum.ToShortDateString & " 12:00:00") And
    7. CDate(Order.Field(Of String)("Von") & " 12:00:00") >= CDate(Datum.ToShortDateString & " 12:00:00")
    8. Select Order
    9. For Each Zeile In Filter
    10. Next Zeile 'Hier darf nur eine Zeile enthalten sein, kann man sicher noch ander ermitteln
    11. Return Zeile("TextwertLang").ToString 'Keine Zeile vorhanden
    12. End Get
    13. Private Set(value As String)
    14. End Set
    15. End Property


    VB.NET-Quellcode

    1. MsgBox(Abfragen.Standard.Waehrung_Lang(Now))
    2. MsgBox(Abfragen.Standard.Waehrung_Lang(CDate("28.12.1964")))


    Edit:
    Nach kleiner Umstellung funktioniert es nun.

    VB.NET-Quellcode

    1. Dim Filter As EnumerableRowCollection(Of DataRow)
    2. Dim Zeile As DataRow
    3. Public Property Waehrung_Lang(Datum As Date) As String
    4. Get
    5. Filter = From Order In DAB.DataTabelle.AsEnumerable
    6. Where Order.Field(Of Integer)("Nummer") = 100 And
    7. CDate(Datum.ToShortDateString & " 12:00:00") >= CDate(Order.Field(Of String)("Von") & " 12:00:00") And
    8. CDate(Datum.ToShortDateString & " 12:00:00") <= CDate(Order.Field(Of String)("Bis") & " 12:00:00")
    9. Select Order
    10. For Each Zeile In Filter
    11. Next Zeile
    12. Return Zeile("TextwertLang").ToString
    13. End Get
    14. Private Set(value As String)
    15. End Set
    16. End Property


    Gruß Markus

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Westerwälder“ ()

    Ja gut, Datum sollte tatsächlich zwischen von und bis liegen. Da ich das allerdings doppelt vertauscht hatte, funktionierte es. Post#7, Z#3-4 und Z+10-11.
    Wozu eigentlich eine ne Property? Reicht da nicht ne Function? Hier eine mögliche Verbesserung.

    VB.NET-Quellcode

    1. Public Property Waehrung_Lang(Datum As Date) As String
    2. Get
    3. Dim Filter = From Order In DT.AsEnumerable
    4. Where Order.Field(Of Integer)("Nummer") = 100 AndAlso CDate(Order.Field(Of String)("Von") & " 12:00:00") >= Datum AndAlso Datum <= CDate(Order.Field(Of String)("Bis"))
    5. Select Order
    6. Dim LastRow = Filter.LastOrDefault
    7. Return LastRow?("TextwertLang").ToString
    8. End Get
    9. Private Set(value As String)
    10. End Set
    11. End Property
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Vielen Dank für die Verbessung. Klappt gut.

    Warum ein Property. Gute Frage. Erschien mir als das sinnvollste.

    Kommen ja noch mehr Sachen, was die Datentabelle verwaltet. Deswegen auch die Abfrage auf Nummer.

    - Waehrung_Kurz
    - MwSt_A
    - MwSt_B
    - Sollzinsen
    - Habenzinsen
    Gruß Markus

    VaporiZed schrieb:

    Wozu eigentlich eine ne Property? Reicht da nicht ne Function?
    Ich kann mal beschreiben, wie ich das üblicherweise handhabe.
    Wenn die Routine für sich alleine lauffähig ist, verwende ich eine Funktion.
    Wenn die Routine noch andere Informationen als die übergebenen Parameter benötigt, mache ich eine (ReadOnly) Property daraus.

    Da im obigen Beispiel eine Datatable angesprochen wird, die nicht übergeben wird, sondern sich wohl innerhalb der Klasse befindet, hätte ich hier auch eine Property verwendet, allerdings ReadOnly, der Setter ist obsolet.


    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Auch vielen Dank an petaod.

    Hier nun die Endfassung:

    VB.NET-Quellcode

    1. Public ReadOnly Property Waehrung_Lang(ByVal Datum As Date) As String
    2. Get
    3. Filter = From Order In DAB.DataTabelle.AsEnumerable
    4. Where Order.Field(Of Integer)("Nummer") = 100 And
    5. CDate(Datum.ToShortDateString & " 12:00:00") >= CDate(Order.Field(Of String)("Von") & " 12:00:00") And
    6. CDate(Datum.ToShortDateString & " 12:00:00") <= CDate(Order.Field(Of String)("Bis") & " 12:00:00")
    7. Select Order
    8. Zeile = Filter.LastOrDefault
    9. Return Zeile("TextwertLang").ToString
    10. End Get
    11. End Property
    Gruß Markus
    Warum wandelst Du ein Datum in einen String und dann wieder in ein Datum um?
    Wenn es Dir um Mittags geht, dann: Datum.Date.AddHours(12) anstatt CDate(Datum.ToShortDateString & " 12:00:00")
    Datum.Date gibt Dir das Datum um Mitternacht an, 12 Stunden drauf -> mittags
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Schreibe in die Spalte "Bis" nichts rein, wenn die Kategorie (z.Bsp. MwSt_A) zur Zeit mit 19 % noch gültig ist.
    Beim Start befülle ich diese Spalte mit dem heutigem Datum.

    VB.NET-Quellcode

    1. Public Sub New()
    2. DAB = New MBC_Daten.CDatenBank
    3. With DAB
    4. .Laden(1, "Standardwert")
    5. For .I = 0 To .DataTabelle.Rows.Count - 1
    6. .DataZeile = .DataTabelle.Rows(.I)
    7. If .DataZeile("Bis").ToString = Nothing Then
    8. .DataZeile("Bis") = Now.ToShortDateString
    9. End If
    10. Next .I
    11. .I = 0
    12. .DataZeile = Nothing
    13. End With
    14. End Sub


    Hatte "Von" und "Bis" erst in der Datenbank auf Datum/Zeit eingestellt. Kam dann immer eine Uhrzeit mit rein. Bin dann wieder auf KurzerText gewechselt.
    Irgendwie ist das Date-Format nicht mein Ding.
    Gruß Markus