​Hi,

evtl. benötigt man mal den ersten und/oder den letzten Tag eines Monats in einer Stored Procedure, View oder einem Datengesteuerten Abonnement. Da ich keine Standard Funktion gefunden habe, habe ich dafür nun zwei kleine Snippets entwickelt:

Erster Tag:

DATEADD(
 dd, -- der Tag soll verändert werden
 CASE DAY(@CurrentDate) WHEN 1 THEN 0 ELSE -DAY(@CurrentDate-1) END, -- aktueller Tageswert -1 soll abgezogen werden
 @CurrentDate -- Berechnung ab diesem Tag
 )

Letzter Tag:

DATEADD(
 dd, -- der Tag soll verändert werden
 -DAY(@CurrentDate ), -- aktueller Tageswert soll abgezogen werden
 DATEADD(mm,1,@CurrentDate )-- Berechnung ab diesem berechneten Tag
 )

Das @CurrentDate muss natürlich vorher gefüllt werden. Wenn es das aktuelle Datum sein soll, verwendet man am besten GETDATE();.

Alternativen, Kritiken und bessere Ideen nehme ich gerne auf :)

Mit freundlichen Grüßen Mattias König

Im NAV Tabellen-Designer Felder suchen

Posted: 18. Oktober 2011 in Tipp

Hi,

ich habe die Tage folgenden Blog Eintrag gelesen: http://navisionary.com/2011/10/how-do-you-search-for-a-field-in-dynamics-nav-table-designer/

Dieser beschreibt sehr gut und detailliert wie man in NAV die schon lange gewünschte Funktion Im-Tabellen-Designer-Felder-suchen „freischaltet“.

Kurzfassung:

  1. In einen Feldnamen klicken
  2. Shift gedrückt halten
  3. Einen Datensatz mit der Pfeiltaste Hoch oder Runter markieren
  4. Shift weiterhin gedrückt halten
  5. Mit dem Anfangsbuchstaben des Feldnamens durch die Felder klicken

Mit freundlichen Grüßen, Matthias König

 

edit: Dieser Trick zieh sich durch ganz NAV! Man kann so auch nach Variablen suchen oder Dataitems.

Excel Export

Posted: 7. Oktober 2011 in Tipp

Eine Regelmäßige Anforderung: „Können wir diesen Report auch nach Excel exportieren?“ und die Antwort ist natürlich „Ja“ :) Das ist sogar, sehr einfach!

Wie benötigen folgende Variablen:

ShowInExcel: Boolean;
ExcelBuf: TEMPORARY Record 370;

Die boolean ShowInExcel ist sinnvoll um den Export optional einzurichten zu können und diesen nicht grundsätzlich als Excel zu exportieren. So besteht also die Wahl zwischen „Ich Drucke aus“ und „ich exportiere in  Excel“. Des Weiteren benötigen wir die folgenden drei Proceduren:

LOCAL PROCEDURE CreateCaption@1();
BEGIN
  ExcelBuf.NewRow;
  ExcelBuf.AddColumn(.FIELDCAPTION("),FALSE,'',TRUE,FALSE,TRUE,'@');
  ExcelBuf.AddColumn(.FIELDCAPTION(.FIELDCAPTION(),FALSE,'',TRUE,FALSE,TRUE,'@');
  ExcelBuf.AddColumn(.FIELDCAPTION(),FALSE,'',TRUE,FALSE,TRUE,'@');
END;
PROCEDURE CreateNewDataRow@2();
BEGIN
  ExcelBuf.NewRow;
  ExcelBuf.AddColumn(.,FALSE,'',FALSE,FALSE,TRUE,'@'); // das @ steht für Textwerte
  ExcelBuf.AddColumn(.,FALSE,'',FALSE,FALSE,TRUE,'@');
  ExcelBuf.AddColumn(.,FALSE,'',FALSE,FALSE,TRUE,'@');
  ExcelBuf.AddColumn(.,FALSE,'',FALSE,FALSE,TRUE,'@');
END;
PROCEDURE CreateExcelFile@3();
BEGIN
  ExcelBuf.CreateBook;
  ExcelBuf.CreateSheet('Unser Excel Export', '129', COMPANYNAME,USERID); // nur wenn ein Info Sheet existieren soll
  ExcelBuf.GiveUserControl; // spricht fuer sich oder? ;)
  ERROR('');
END;

Diese müssen nun nurnoch an die entsprechenden Stellen implementiert werden:

  1. CreateCaption: Dies kann in den OnPreDataItem der Exportiert werden soll, um die Überschriften zu füllen
  2. CreateNewDataRow: In den passenden OnAfterGetRecord
  3. CreateExcelFile: ans Ende des Reports oder des DataItems (OnPostDataItem)

Bitte beachten Sie noch dass Sie dies mit der IF-Anweisung…

IF ShowInExcel THEN ...

… umschliessen damit der Export auch, wie gewünscht, Optional bleibt. Dieser Wert sollte nun noch in der Request Form veränderbar sein. Daraufhin kann der Export getestet werden.

Eigentlich ganz einfach oder?

Mit freundlichen Grüßen Matthias König

Hi,

a:Microsoft.Dynamics.Nav.Types.Exceptions.NavNCLMetadataCompileErrorException Fehler beim Kompilieren von Assembly ‘CodeUnit’. Dies kann auf Unterschiede zwischen Binärdateien in der Installation oder der Datenbank zurückzuführen sein. Stellen Sie sicher, dass alle Installationskomponenten konsistent und auf dem neuesten Stand sind. Fehlerdetails: ’50200′

So lautete eine kurioser Web Service Fehlermeldung die bearbeitet werden musste. Nach Ausschlussverfahren konnte dann festgestellt werden, dass das Problem folgendes ist:

OptionValue += 1; // … ist eine Variable vom Typ Option.

Sobald in eines der ausgeführten Objekte in einem Web-Service-Vorgang diese Zeile auch nur enthält (brauch nicht ausgeführt werden) kommt der oben beschriebene Fehler.Hingegen funktioniert der folgende Aufruf: OptionValue := OptionValue  + 1;

Es scheint so, als wenn der Interpreter, der die Objekte für die Web Services und RTC in C# aufbereitet seine Probleme mit Option += x hat, diese aber nicht beim kompilieren kundtun möchte.

Mit freundlichen Grüßen, Matthias König

SETFILTER Text größer als 30 Zeichen

Posted: 14. April 2011 in Tipp

Heute brauchte ich alle Kreditoren mit mehr als 30 Zeichen im Namen. Das heisst, es sollte nicht manuell gesucht werden, welcher Name weniger Zeichen hat sondern dies sollte schon relativ automatisch geschehen. Wie ermittle ich also diese? Erster Gedanke war der des Entwicklers: „REPORT!!!“

Aber dann hatte ich eine bessere Idee, die ich (so glaube ich zumindest) vor ein-zwei Jahren mal gelesen habe: Setze den Filter ‘??????????????????????????????*’ auf das Feld Name und es werden nur noch Kreditoren mit Namen die länger sind als 30 angezeigt :)

 

Gruß,

Matthias König

Hi Leute,

einigen mag es schon vorher bekannt gewesen sein, doch ich dachte bis heute, dass der Standarddrucker des Systems ausschlaggebend für die Ansicht der Seitenansicht wäre. Aber nein, er lädt den Druckertreiber aus der Druckerauswahl für die Kombination Report/Benutzer. Das bedeutet z.B. wenn ein Label-Drucker ausgewählt wurde und dieser entsprechend konfiguriert wurde, dann wird die Seitenansicht auch auf diese Größe reduziert. Dies gilt natürlich auch für die SAVE-AS-HTML Variante. Oder anders: die Seitenansicht und Ausdruck sind unterschiedlich!

Hinweis 1: achtet darauf das ihr den Drucker ausgewählt habt, mit dem der Kunde drucken möchte. Vor allem wenn der Druck sehr genau dargestellt werden muss.

Hinweis 2: So ist mir das hier aufgefallen! Falls ihr die Maximale Seitenanzahl anzeigen wollt, gibt es ja fast keine andere Möglichkeit als den Bericht einmal vorher laufen zu lassen. Falls ihr in etwa diesen (Quelle die MSDynamics :) ) verwendet, wird für den Druck der Seitenanzahl, der Druckertreiber aus der Druckerauswahl geladen. Nun könnte die Seitenanzahl also unterschiedlich sein, wenn der Report auf einem anderen Drucker ausgedruckt wird, als in der Druckerauswahl eingerichtet wurde da jeder Drucker die Ausgabe etwas anders interpretiert.

Mit freundlichen Grüßen,

Matthias König

 

Seitenansicht und Ausdruck unterschiedlich

Datensatzwert in SQL vergleichen

Posted: 2. März 2011 in SQL, Trick

Wie schon angekündigt, hier der SQL Befehl um Datensätze, bzw. bestimmte Felder zweier zusammengehörender (selber Primary Key) Datensätze in unterschiedlichen Tabellen auf Differenzen zu überprüfen:

(Beispiel der Customer Tabelle in Live und Dev Datenbank)

SELECT
 'DevDatabse' TableID
 ,[No_]       
 ,[Name]       
 ,[Quantity]
FROM [DataBase_Dev].[dbo].[Company$Customer] as TableOne
WHERE
 BINARY_CHECKSUM(
 TableOne.[Name]
 ,TableOne.[Post Code]
 ,TableOne.[City]
 ,TableOne.[Fax No_]
 ,TableOne.[E-Mail]
 ,TableOne.[Home Page]
 <>
 (SELECT BINARY_CHECKSUM(
 TableTwo.[Name]
 ,TableTwo.[Post Code]
 ,TableTwo.[City]
 ,TableTwo.[Fax No_]
 ,TableTwo.[E-Mail]
 ,TableTwo.[Home Page]
 )
 FROM DataBase_Live].[dbo].[Company$Customer] as TableTwo
 WHERE TableTwo.[No_]  = TableOne.[No_]

Hier wurde die Build-in-Function BINARY_CHECKSUM verwendet. Diese errechnet ein Prüfsummenwert aus den angegebenen Werten, der zum Vergleich verwendet werden kann. Innerhalb dieser Funktion, können die zu überprüfenden Felder eingetragen werden. Leider kann man sich hier das Leben nicht einfach machen in dem man ‘*’ eingibt weil hier der in SQL intern verwendete Timestamp fast immer unterschiedlich sein wird ;) .

Mit freundlichen Grüßen,

Matthias König

Und wieder was dazugelernt!

Falls bei einem Datei-Import (oder Export) jemand mal den Datentypen File verwendet und dort mit Tabulatoren (Tabs) arbeiten sollte, könnte es passieren das Tabs nicht erkannt werden! Hier ist also folgendes zu beachten:

Wenn man ein Textfile mit TEXTMODE(TRUE) öffnet/erstellt wird, werden Tabulatoren in Leerzeichen umformatiert. Beispielsweise, um Texte mit Tabulatoren einlesen zu können, kann über die Textdatei.CREATEINSTREAM ein Stream erstellt werden und die Zeilen dann in Kombination mit READTEXT eingelesen werden. In den Streams werden Tabs auch als solche verarbeitet. Was eine Fehlersuche :D

hier ein Code-Ausschnitt:

...
OpenFile();
// wegen Tabs
InputFile.CREATEINSTREAM(InStream);
// skip header
InStream.READTEXT(currentLineValue);
// OnAfterImportRecord
WHILE (InStream.READTEXT(currentLineValue) > 0) DO BEGIN
...

Mit freundlichen Grüßen, Matthias König

Tabelleninhalt in SQL vergleichen

Posted: 9. Februar 2011 in SQL, Tipp, Trick

Oder auch „Ist der Datensatz in beiden Tabellen vorhanden?“

Um einen Automatismus per Webservice zu steuern, musste ich DataPorts in Codeunits umschreiben (NAS und Webservice :D ) und in diesem Zuge wollte ich am Ende die Importierten Daten im Vergleich zum DataPort überprüfen. Zu allerersteinmal wollte ich kontrollieren ob alle Datensätze importiert wurden, also ob beide Varianten die selben Datensätze erzeugen. Dafür habe ich den Dataport in einem Mandanten gestartet und die Codeunit in einem anderen Mandanten. Nun können diese per SQL einfach gegenübergestellt werden, sodass verglichen werden kann, wo ein Datensatz fehlt. Da dies allerdings (meines Wissens nach) nicht mit einem Script geht, habe ich zwei kleine gebastelt. Mit den nun folgenden SQL Scripten (natürlich abgeändert ;) ) können Daten zweier Tabellen verglichen werden:

-- es fehlt etwas in TabelleEins
SELECT *
FROM [DatenBank].[dbo].[MandantEins$Tabelle XYZ] AS TabelleInEins
LEFT JOIN [DatenBank].[dbo].[MandantZwei$Tabelle XYZ] AS TabelleInZwei
ON TabelleInEins.ID = TabelleInZwei.ID
WHERE TabelleInZwei.ID is null
-- es fehlt etwas in TabelleZwei
SELECT *
FROM [DatenBank].[dbo].[MandantEins$Tabelle XYZ] AS TabelleInEins
RIGHT JOIN [DatenBank].[dbo].[MandantZwei$Tabelle XYZ] AS TabelleInZwei
ON TabelleInEins.ID = TabelleInZwei.ID
WHERE TabelleInEins.ID is null

Die Tage wird wohl noch ein „Datensatzwert in SQL vergleichen“ Artikel erscheinen, da ich natürlich noch die Richtigkeit der restlichen importierten Daten überprüfen muss.

Diese Scripte mögen nicht das non-plus Ultra seien aber sie haben mir ihren Dienst erwiesen :) Verbesserungsvorschläge/Alternativ-Scripte gern als Kommentar.

Mit freundlichen Grüßen, Matthias König

Letztens habe ich eine Form benötigt, die den Modify-Trigger einer Tabelle nicht ausführt. Daraufhin habe ich (nach kurzer Recherche) mir die zur Verfügung stehenden Trigger angeschaut und konnte folgende Lösung erarbeiten:

Über die ersten Zeilen in den entsprechenden Triggern in der Form, wird der (z.B.) Modify mit FALSE ausgeführt. Dann wird der Form-Trigger mit FALSE verlassen, sodass der eigentliche Tabellen-Trigger nicht noch zusätzlich ausgeführt wird. Das wars schon :) .

Gruß, Matthias König