Casablanca: Group by

Hallo Form,

ich habe folgendes Problem.

Ich habe eine Tabelle mit mehreren (hier zwei) Spalten, Datum und MonatsWert.

  
---------------------------------------------  
|Datum                  | MonatsWert  
---------------------------------------------  
2014-01-01 17:23:11.000 | 0  
---------------------------------------------  
2014-01-02 17:27:10.000 | 487,339996337891  
---------------------------------------------  
2014-01-05 17:27:09.000 | 723,289978027344  
---------------------------------------------  
2014-02-01 18:19:42.000 | 1507,22998046875  
---------------------------------------------  
2014-02-03 18:18:41.000 | 1507,22998046875  
---------------------------------------------  
2014-02-04 18:21:40.000 | 2635,26000976563  
---------------------------------------------  
2014-03-02 19:07:18.000 | 1542,73999023438  
---------------------------------------------  
2014-03-03 19:13:17.000 | 1589,21997070313  
---------------------------------------------  
2014-03-04 19:11:16.000 | 2860,86987304688  
---------------------------------------------  

Ich brauche nun eine SQL-Anweisung oder besser LINQ-Statement, die folgendes ausgibt:

  
|Datum                  | MonatsWert  
---------------------------------------------  
2014-01-03 17:27:09.000 | 723,289978027344  
---------------------------------------------  
2014-02-04 18:21:40.000 | 2635,26000976563  
---------------------------------------------  
2014-03-03 19:11:16.000 | 2860,86987304688  
---------------------------------------------  

Das heißt, die muss goupiert nach Jahr und Monat die größte MonatsWert für jede Gruppe ausgeben.

Danke im Voraus

  1. [LINQ]
    from row in rows
    group row by new { MonthYear=row.Dt.ToString("yyyyMM") } into grp
    let gx = grp.OrderByDescending(g=>g.MonatsWert).First()
    select new { MonthYear = g.Key.MonthYear, MaxMonatsWertDt = gx.Dt, MaxMonatsWert = gx.MonatsWert }

    [SQL]
    SELECT T.YYYYMM, W.Dt, W.MonatsWert
    FROM (SELECT DISTINCT (YEAR(Dt)*100)+MONTH(Dt)) AS YYYYMM FROM table) AS T
    CROSS APPLY (SELECT TOP 1 Dt, MonatsWert FROM table T2 WHERE T.YYYYMM =  (YEAR(T2.Dt)*100)+MONTH(T2.Dt)) ORDER BY T2.MonatsWert DESC) W

    ... irgendwas so in der Art, würd ich sagen, den Rest darfst du selbst zusammenbasteln. :)

    P.S. Scheiss auf auf Vollzitate

    1. Hi,

      danke für deine Antwort. Die SQL-Anweisung hat nach ein paar Änderungen funktioniert. Ich verstehe aber nicht ganz, welche Rolle "((YEAR(TimeStamp)*100)+(MONTH(TimeStamp))" und "WHERE T.YYYYMM =  (YEAR(T2.Dt)*100)+MONTH(T2.Dt))" an dieser Stelle spielt. Benutzt du das nur als eine Art Id? Kannst du bitte das kurz erklären.

      Die Linq-Anweisung wird so nicht fuktionieren, weil die Methode "ToString" von Linq nicht unterstützt wird. Kann man diese ohne "ToString" hinbekommen?

      Gruß

      1. Du musst aus dem Datum das Jahr und den Monat rausholen, denn danach willst du gruppieren.

        1. Hallo,

          vielen Dank. Ich brauche das Ganze Datum zur späteren Anzeige auch. Wenn ich mich bei der Select/Linq-Anweisung nur auf Jahr und Monat beziehe, Kann ich das Datum-Feld nicht mehr als ganzes in der Anweisung angeben, oder geht das doch?

          Gruß

          1. Hi Casablanca,

            deine Anforderung war beinahe woertlich: "gruppiere nach Jahr und Monat".

            Um dies zu tun musst du einen Datumswert im Stil yyyyMMdd (Jahr, Monat UND Tag) auf yyyyMM reduzieren. in SQL geht das am einfachsten indem du daraus einen INTEGER Wert machst (Jahr mit 100 multiplizieren und den Wert fuer Monat (1-12) hinzuaddieren.

            Die Linq-Anweisung wird so nicht fuktionieren, weil die Methode "ToString" von Linq nicht unterstützt wird.

            "wird nicht" - ist das deine Annahme? Interessante These.

            Lustigerweise habe ich dir beide Code Fragmente gestern abend aus der "la main" geschrieben ohne Gelegenheit zum Testen. Jetzt nach deinen Fragen hab ich die doch tatsaechlich mal ausprobiert und siehe da, funktionieren auf Anhieb. Da muss nichts geaendert werden damit die Loesungen "funktionieren".

            1. Hallo Frank,

              danke. Ja das ist richtig. Es sollte nach dem Jahr und Minat Gruppiert werden. Aber das Datum muss hinterher auch erhalten beliben, ich gruppiere die Datensätze ja danach. Was nutzt eine Gruppierung nach einem Feld, wenn das Feld selber am Ende nicht mehr rekonstruiert werden kann.

              Ich arbeite mit VisualStudio 2013/EF und da habe ich die Ganze Zeit probleme mit "ToSting" und alles, was die Werte in LINQ in String umandeln will. Daher muss ich leider immer wieder die Abfragen so gestalten, so dass die auch ohne ToString auskommen. Das ist sehr mühsam. Manche Frameworks sind halt toleranter als andere. Oder ich mache da was falsch und weiß ich selber nicht.

              Gruß

              1. Du sagst

                Aber das Datum muss hinterher auch erhalten beliben, ich gruppiere die Datensätze ja danach.

                und direkt davor steht aber

                Es sollte nach dem Jahr und Minat Gruppiert werden.

                Was denn nun, mit Tag im Datum oder ohne?

                Wenn du Gruppen bildest die nur aus Jahr und Monat bestehen, hast du keinen Tag mehr. Es sind ja alle Tage in diesem Monat in den Daten der Gruppe enthalten.

                1. Hallo,

                  sorry, mein Fehler. Ich habe drauf nicht geachtet, dass das Datum selbst bereits in der Anweisung drin steht. Das Ganze muss nach Jahr und Monat gruppiert werden, das ist richtig und ihr habt alles richtig gemacht. MeinProblem ist nun mit der LINQ-Anweisung. Leider ich habe nocht keine Lösung dür "ToString" gefunden. Die Fehlermeldung: "Für die System.String ToString(System.String)-Methode gibt es keine unterstützte Übersetzung in SQL". Alles kann man hier nachlesen: http://msdn.microsoft.com/de-de/library/bb882672%28v=vs.110%29.aspx

                  Gruß

                  1. Ah, da liegt der Hund begraben, EF möchte das LinQ statement in SQL umsetzen, ein ToString() wäre eigentlich nur ein billiger CAST(wert as varchar). In dem Fall sollte es aber mit der Umwandlung des Datums in integer funktionieren, vorausgesetzt dein EF kann DateTime.Year und DateTime.Month in die jeweilige DATEPART Funktion umwandeln. Aber mit der SQL Abfrage hattest du doch schon das Ergebnis bekommen. Und das eigentliche Datum blieb dir doch dort auch erhalten.

                    Gruss, Frank

            2. Hallo Frank,

              die Sache mit dem Datum in deiner SQL-Anweisung hat sich erledigt.

              Gruß