Hi,
also entweder Du merkst Dir den Timestamp des letzten bekannten Satzes in Deiner Anwendung und prüfst dann regelmäßig, ob es einen Satz mit jüngerem TS gibt, oder aber Du versuchst die Log-Files zu überwachen. Letzteres halte ich für ein großes Faß, was auch nicht mit jeder DB geht. MySQL scheint da was zu haben
aber ich täte lieber xxMUROxx Lösung nehmen.
Achja - falls Dir nur kein SQL eingefallen ist:
SELECT * FROM TABELLE
WHERE EINSTELL_TS > :merkTimeStamp
ORDER BY EINSTELL_TS DESC
LIMIT 1
sollte den jüngsten Datensatz liefern (ohne Gewähr, da ich MySQL nicht kenne)
Gruß
f_igy
Hi,
gehen tut sowas grundsätzlich mit "bulk insert" z.B.
http://stackoverflow.com/questions/1609153/how-to-do-a-bulk-insert-linq-to-entities
aber ob man das aber mit EF5 machen kann? Ansonsten hilft es durchaus alle 100 - 1000 Inserts einen Commit zu machen, damit die Log-Files nicht so voll werden.
Gruß
f_igy
Hi,
m.E. gar nicht sauber. So wie ich das sehe ist die Zuordnung der Serien-Nr. nur durch die Reihenfolge der Rechnungsposten festgelegt. Da in SQL-Datenbanken die Reihenfolge der Datensätze prinzipiell zufällig ist halte ich jede mögliche Lösung über z.B. Zeilennummer od. dergl. für Kaffeesatzlesen. Bist du ganz sicher, dass Deine "Verkauf"-Tabelle nicht doch eine Postennummer enthält? Evtl. siehst Du ja nur eine View, die dieses Feld nicht anzeigt.
Gruß
f_igy
Aha!
Ich vermute wir dringen grade zum Kern der aktuellen Bankenkrise vor... Kommt eigentlich Zypern in Deinem UML-Diagramm vor?
f_igy
Hm,
kann es eine Bank ohne Konto geben? Oder ist das jetzt das Henne, Hahn und Ei Problem?
f_igy
Hm?
ich dachte an sowas:
public bool AddProducts(string ProductCodenumber, string ProductName, string Producttype,string collectionID)
{
var myProduct = new Product();
myProduct.ProductCodeNumber =ProductCodenumber;
myProduct.ProductName = ProductName;
myProduct.ProductTypeID =Convert.ToDouble (Producttype);
Int32.TryParse(collectionID , out myProduct.CollectionID);
Kann man natürlich beliebig mit 'ner Fehlermeldung oder so aufhübschen...
Gruß
f_igy
Ja genau,
für jedes PDF musst Du m.E. einen eigenen Report mit der/den interessanten Datarows erzeugen und dann den Datenstrom in einer Datei schreiben. Vielleicht gibt es da noch einen anderen Weg, aber ich wüsste nicht wie. Immerhin müssen ja die Namen der PDFs bekannt gemacht werden, denn wie sollte der Reportgenerator das entscheiden?
string deviceInfo =
"<DeviceInfo>" +
" <OutputFormat>PDF</OutputFormat>" +
" <PageWidth>29.7cm</PageWidth>" +
" <PageHeight>21cm</PageHeight>" +
" <MarginTop>0cm</MarginTop>" +
" <MarginLeft>0cm</MarginLeft>" +
" <MarginRight>0cm</MarginRight>" +
" <MarginBottom>0cm</MarginBottom>" +
"</DeviceInfo>";
Warning[] warnings;
string[] streams;
//_nLogLogger.Info("this.reportViewer.LocalReport.Render");
byte[] bytes = reportViewer.LocalReport.Render(
reportType,
deviceInfo,
out mimeType,
out encoding,
out fileNameExtension,
out streams,
out warnings);
using (FileStream fs = new FileStream(reportPfad + _dateiname + "." + fileNameExtension, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
}
Wenn Du ++einzelne ++PDFs als Ergebnisse brauchst ja. Sonst kannst Du natürlich auch ein PDF mit allen Seiten erzeugen. Evtl. haben wir aber aneinander vorbei geschrieben. Im Reportviewer wird jeder _Bericht _auf einer eigenen Seite angezeigt, egal wieviele Seitenumbrüche er enthält. Das liegt daran, dass der Seitenumbruch ab Ausgabemedium hängt. Du kannst ja z.B. ein Excel-File erzeugen, das keine Seitenumbrüche enthält. Bei Seitenbasierten Ausgaben ist ja dann auch das Format des Ausgabemediums wichtig. Das Thema kann istgesamt etwas kniffelig sein. Bei MS gibt es dazu ein eigenes Dokument.
Hm,
kommt drauf an, was Du meinst. Wenn man z.B. ein PDF erzeugt kann man da natürlich die Seite einzeln drucken. Falls Du für jeden Kunden einen eigenen Bericht erzeugen willtst - eben mit seinen Daten- dann musst du dem Report die Kundennummer (bzw. was anderes eindeutiges) als Parameter übergeben und als Filter auf dem Dataset verwenden.
Gruß
f_igy
Hi,
Du musst über die Adresse Gruppieren und beim Gruppenwechsel einen Seitenwechsle machen.
Gruß
f_igy
Lustig,
ich find's umgekehrt. Am besten selber testen.
Gruß
f_igy
Hm,
ich glaube ganz ohne Buch ist das nicht ohne. Versuch mal:
ReportViewer-Steuerelemente (Visual Studio): Beispiele und Anleitungen
SQL Server 2008 R2 Report Builder 3.0
Erste Schritte (Reporting Services)
Page Layout and Rendering (Report Builder 3.0 and SSRS)
SQL Server Reporting Services
Working with Tablix Data Regions
Viel Glück.
f_igy
Nö,
das geht damit - irgendwo gibt es im Forum ein Thema mit Buchempfehlungen.
Gruß
f_igy
Hi,
schonmal nach den db-Statistiken geschaut? Wenn die nicht die aktuelle Datenlage wiederpsiegeln entscheidet sich der Optimizer gerne für nicht so tolle Zugriffspfade. Um dazu was sagen zu können braucht man natürlich die kompletten DDLs, Statisiken und Explains der SQLs.
Ich tät mal update Statistics und ggf. des MSSQL Equivalent von reorg machen.
Allerdings bezweifle ich, dass man mich generiertem SQL aus dem EF gute Chancen auf performante db-Abfragen hat.
Bei vergleichsweise kleinen Datenmengen (wie einer Artikeldatenbank) kann man sicherlich auch versuchen an der Datenbank was zu optimieren. Mit genügend freiem RAM kann man die IOs sicherlich auf 0 senken, die oft das Problem darstellen.
Gruß
f_igy
Teste mal den:
SELECT [T-Fernschüler].[Kurs-Nr]
, [T-Adressen].[NAME]
, [T-Adressen].[VORNAME]
, [T-Verbindungen].[Nummer]
, [T-Fernschüler].[FS-Nr]
, [T-Fernschüler].[Kündigung]
FROM [T-Status]
INNER JOIN [T-Adressen]
ON [T-Status].[Status-Nr] = [T-Status-Adressen].[Status-Nr]
INNER JOIN [T-Fernschüler]
ON [T-Adressen].[Adress-Nr] = [T-Fernschüler].[Adress-Nr]
INNER JOIN [T-Verbindungen]
ON [T-Adressen].[Adress-Nr] = [T-Verbindungen].[Adress-Nr]
INNER JOIN [T-Status-Adressen]
ON [T-Adressen].[Adress-Nr] = [T-Status-Adressen].[Adress-Nr]
WHERE [T-Fernschüler].[Kurs-Nr]) in (6,9)
-- AND (([T-Verbindungen].[Nummer] Is Not Null <- unsinnig da alles was like irgendwas ist nicht NULL sein kann
AND ([T-Verbindungen].[Nummer] Like "%@%" OR [T-Verbindungen].[Nummer]) Like "*@*")
AND [T-Fernschüler].[Kündigung]) Is Null
AND [T-Verbindungen].[Anschluss-Nr])=4
AND [T-Status-Adressen].[Status-Nr])=2;
f_igy
Klammer-Argh!
isjaklar - hatte List.Insert nicht auf dem Schirm...
f_igy
Hi,
ich würde sowas mit einer verketteten Liste machen:
bin aber nicht sicher, ob man die einfach überall dranbinden kann.
Gruß
f_igy
Hi,
gibt es einen Grund, warum Du nicht einfach DateTime.TryParseExact mit einem String-Array der zulässigen Formate verwendest?
DateTime.TryParseExact-Methode (String, String[], IFormatProvider, DateTimeStyles, DateTime)
Die Beispiele unten müssten eigentlich genau passen...
Gruß
f_igy
Hi,
rekursives SQL ist nicht im ANSI Standard, daher gibt es da Zahlreiche Varianten. Die für MS-SQL 2008 kenne ich leider nicht, ist aber hier beschrieben:
http://msdn.microsoft.com/de-de/library/ms186243(v=sql.105).aspx
Offenbar wird da auch ein SelfJoin über eine Art Window Konstruktion gemacht (ist in DB2 recht ähnlich). Wichtig ist m.E. den Level zu begrenzen, da es sonst bei Schleifenbeziehungen zu einer Endlosrekursion kommen kann. Das Ganze ist anfangs immer schwer zu verstehen, also viel Glück!
Evtl. lohnt es auch das Ergebnis der "Area"-Kette in einem String zu verketten, den man dann mit RegEx auf die gewünschten Eigenschaften durchsuchen kann.
Gruß
f_igy
SelfJoin
SELECT T1.CustomerID
FROM Tabelle T1
JOIN Tabelle T2
ON T1.CustomerID = T2.CustomerID
WHERE T1.Area = 'Company'
AND T2.Area = 'SEM'
Gruß
f_igy
Richtig, die Bedingung muß in die ON-clause:
SELECT
Coalesce(A1.Referenz, A2.Referenz, A3.Referenz)
, A1.TeilenummerPosition AS Auftrag1
, A2.TeilenummerPosition AS Auftrag2
, A3.TeilenummerPosition AS Auftrag3
FROM FertigungsAuftraege A1 WITH (NOLOCK)
FULL OUTER JOIN FertigungsAuftraege A2 WITH (NOLOCK)
ON A1.Referenz = A2.Referenz
AND A1.AuftragsNummer= 'Auftrag1'
AND A2.AuftragsNummer= 'Auftrag2'
AND (A1.TeilenummerPosition <> A2.TeilenummerPosition OR A1.TeilenummerPosition is null OR A2.TeilenummerPosition is null)
FULL OUTER JOIN FertigungsAuftraege A3 WITH (NOLOCK)
ON A1.Referenz = A3.Referenz
AND A1.AuftragsNummer= 'Auftrag1'
AND A2.AuftragsNummer= 'Auftrag3'
AND ( A1.TeilenummerPosition <> A3.TeilenummerPosition OR A1.TeilenummerPosition is null OR A3.TeilenummerPosition is null)
Das mit dem NULL ist ja kein Problem:
SELECT COALESCE(A1.Referenz, A2.Referenz,A3.Referenz), A1.TeilenummerPosition, A2.TeilenummerPosition, A3.TeilenummerPosition
FROM FertigungsAuftraege A1
FULL OUTER JOIN FertigungsAuftraege A2 ON A1.Referenz = A2.Referenz AND A1.TeilenummerPosition<>A2.TeilenummerPosition
FULL OUTER JOIN FertigungsAuftraege A3 ON A1.Referenz = A3.Referenz AND A1.TeilenummerPosition<>A3.TeilenummerPosition
WHERE A1.AuftragsNummer= 'Auftrag1' AND A2.AuftragsNummer='Auftrag2' AND A3.AuftragsNummer= 'Auftrag3' AND A1.Referenz <>''
Allerdings musst Du für jede Ausprägung von AuftragsNummer einen eigenen JOIN kodieren, was nur Sinn ergibt, wenn es eine fest definierte Anzahl zu vergleichender Aufträge gibt. Sonst must Du mal nach der PIVOT-Funktion von SQL Server suchen.
Gruß
f_igy
Hi,
verstehe ich Dich recht, dass Du das Ergebniss Pivotieren möchtest? Das geht mit ANSI SQL leider nicht sehr gut. Evtl. hat der SQL-Server aber dafür eine kleine Spracherweiterung (da kochen die DB-Hersteller gerne mal was eigenes).
Bei Deinem JOIN sind übrigends nur Sätze enthalten, die in der Menge "A3.AuftragsNummer= 'Auftrag3' " enthalten ist. Falls auch Aufträge interessieren, deren Referenz nur in "A2.AuftragsNummer= 'Auftrag2' oder A1.AuftragsNummer= 'Auftrag1' enthalten ist brauchst Du einen FULL OUTER JOIN und musst Die Referenz mit COALESCE(A1.Referenz, A2.Referenz,A3.Referenz) bestimmen.
Gruß
f_igy
Hi,
wie wäre ein FULL OUTER JOIN mit JOIN über alle Felder?
SELECT T1.WERT
, T2.WERT
FROM T1
FULL OUTER JOIN T2
ON T1.WERT = T2.WERT
WHERE T1.WERT IS NULL
OR T2.WERT IS NULL
liefert alle unterschiedlichen Zeilen. Natürlich musst Du bei mehreren Werten auch alle in die ON Bedingung mit nehmen. Zu beachten ist dabei, dass NULL nicht gleich NULL ist (nur wichtig, wenn Deine Tabelle NULL Felder enthält).
Gruß
f_igy
schonmal @"1. Spalte" porbiert?
Hi,
ich verstehe Dein Problem leider nicht so ganz. Schick doch bitte mal das SQL mit Antwort aus dem SQL-Developer sowie das DLL der Tabelle. Kann es sein, das REM ein CLOB oder BLOB ist?
Gruß
f_igy
Hi,
schon mal die DDLs der beiden Tabellen verglichen? Evtl. liegt ja das das Häschen im Pfeffer...
Gruß
f_igy
Hi,
ich tät 'nen Join nehmen, da der dem db-System mehr Spielraum beim Zugriffspfad lässt und große in-Listen of lahm werden:
SELECT *
FROM [appl_log]
JOIN [app_table]
ON appl_guid = g
Außerdem ist SELECT * nachteilig weil1.neue Spalten je nach verwendeter Porgrammierung Probleme bereiten 1.evtl. Daten aus der DB gelesen weren, die das Programm gar nicht braucht 1.das DB-System schlechtere Chancen hat den Zugriff "INDEX only" zu gestalten.
Punkt 2 und 3 können erhebliche Auswirkung auf die Ausführungszeti des SQL haben.
Gruß
f_igy
Hi,
während einer offenen Transaktion speichert die Datanbank zusätzlich Informationen für den Rollback. Bei Massenoperationen kann dieser Speicher zu einem (Performance) Problem werden. Eine beliebte Faustregel ist alle 1000 DMLs ein Commit zu setzen, wobei die Zahl eher Folklore denn wissenschaftlich begründeter Wert ist.
Gruß
f_igy
Huhu,
Sinn und Zweck eines gesalzenen Hash Passwortes ist ja gerade, dass es eben nicht wieder zurückgewandelt werden kann. Ich würde mir überlegen, ob Du das brauchst, da Du dadruch viel Sicherheit aufgibst.
Gruß
f_igy
Hi,
ich fand grade unter
dies
[...] Die ImageList verwaltet die Liste der Bilder mithilfe eines Handles.Das Handle wird erst erstellt, nachdem bestimmte Vorgänge für die Bildliste ausgeführt wurden, wie z. B. Abrufen des Handle oder Aufrufen von Draw.[...]
Hört sich für mich an, als ob die Handles erst beim 1. Zugriff erstellt werden. So richtig was sicheres habe ich aber nicht gefunden....
Gruß
f_igy
Hierachische Datenbanken gibt es immer noch (IMS/DB erfreut sich bester Gesundheit, nur die Expertren streben langsam aus...)!
Gruß
f_igy
Hi,
Probier mal "SHOWPLAN_TEXT ON statement". Damit lässt sich der Ausführungsplan ermitteln, wozu das Statement natürlich auch geparsed werden muss.
http://msdn.microsoft.com/en-us/library/ms176058.aspx
Ich habe hier keinen MS-Server, aber der Befehl wird wohl dem db2 explain ähneln.
Alternativ können manche Datenbanken mit einem "prepare"-Befehl zum erzeugen eines Zugriffsplanes aufgefordert werden. Wenn man das SQL dann ausführt steht bereits der Plan, sodass die Ausführungszeit um das erstellen des Planes kürzer wird. Für SQL-Server habe ich da nix gefunden, aber auch nur 15sec. gesucht...
Hab doch noch mal gekuckt, "SET PARSEONLY " könnte auch was sein:
http://msdn.microsoft.com/en-us/library/ms178629.aspx
Gruß
f_igy
Hi,
geht m.E. am einfachsten mit einem Left (outer) Join, der in Linq so geht:
http://code.msdn.microsoft.com/LINQ-Join-Operators-dabef4e9/description#leftouterjoin
Die Ergebnismenge des Join einer temporören Liste zuzuweisen und diese dann mit ..DefaultIfEmpty() auf NULL auzufragen ist etwas sperrig, aber man gewöhnt sich dran.
In Deinem Fall joinst Du alle Frauen mit der Relationstabelle, wobei in der Relationstabelle nur der Mann ausgewählt wird, für den Du Dich interessierst ( 😉)) ). Alle Frauen, die einen NULL Treffer haben kommen in Liste zwei, die Anderen in die 1.
Gruß
f_igy
Hi,
das Thema ist nicht ganz trivial und hat nicht zwigend mit der Menge, sondern der Fragmentierung des Speichers zu tun. Siehe auch
Verhindern einer OutOfMemoryException, wenn die Datei als ganzes zu groß für den Hauptspeicher ist
Als Hintergrundinfo empfehle ich diese Artikel
http://blogs.msdn.com/b/tess/archive/2006/09/06/net-memory-usage-a-restaurant-analogy.aspx
http://blogs.msdn.com/b/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx
Ich könnte mir vorstellen, dass es in Deinem Fall hilft, wenn Du beim Auftreten des Fehlers darauf wartest, dass alle Threads fertig sind und dann dem GC die Chance gibst, den freien Speicher wieder zu einem Chunk zusammenzuschieben.
Einige Mitmenschen berichten auch von einer Verbesserung durch 64bit.
Gruß
f_igy
Stimmt,
SQLs sollten im Client nicht vorkommen. Dadurch kannt Du jederzeit die Datenbank wechseln, SQL-Statements optimieren oder einzelne Zugriffe durch andere Methoden wie Zugriffe auf Dienste Dritter etc. umstellen, ohne einen neuen Client ausrollen zu müssen.
Falls eine Form des Logins gewünscht oder erfoderlich ist muss dass natürlich irgendwie gemacht werden. Naheliegend ist dann eine uid/pwd, die der User selber ändern kann und die als gesalzener Hash in der Ziel-DB liegt.
Gruß
f_igy
Hi,
typisch ist sicherlich die Varaiante 1. Deine 2. Idee hat den Nachteil, dass von außen DB-Zugriffe möglich sind. Wenn also jemand doch uid und pwd herausbekommt kann er damit bliebige SQLs auf der DB ausführen. In Varaiante 1 kann er nur mit deiner API Reden, die dann auch nichts anderes tun sollte, als wenn er mit dem original Programm zugreift.
Bzgl. Performance kann das Ganze sogar Vorteile haben, z.B. wenn Du häufig benötigte Daten oder Ergebnisse lang laufender SQLs in einem Cache lagerst. Außerdem kannst Du die Ergebnisse komprimiert übertragen, wass evtl. auch was bringt.
Gruß
f_igy
Huhu,
wenn man ein Bisschen Geld in die Hand nimmt gibt's da von IBM was schickes:
InfoSphere Guardium Data Encryption for DB2 and IMS Databases
Läuft aber nur auf Rechnern der z-Serie...
Gruß
f_igy
Nö,
1:n geht ohne Zwischentabelle in 3NF, nur für n:m Beziehung braucht man das Mapping. Aber Du schreibst ja, dass eine Task in mehreren Projekten vorkommen und ein Projekt mehrere Tasks haben kann (also n:m) - wobei Dein Mengengerüst nach einer anderen Datenlage aussieht...
Gruß
f_igy
Hi,
einfach im Katalog nach den Spalten zu suchen und die anzufügen, die Du noch nicht hast, erscheint mir etwas fragwürdig. Je nach Update sind ja weiter Aktionen nötig, wie zum Beispiel das Einfügen von Schlüsselverweisen auf andere Tabellen oder das Berechnen von Werten für die neuen Spalten, anlegen oder Droppen von Indexen etc..
Ich würde daher für jeden Versionssprung eigenen Migrationskode erzeugen und dann in einer Schliefe alle notwendigen Versionssprünge ausführen. Das mag bei einfachen Tabellenänderungen noch etwas übertrieben erscheinen, aber es liegt ja in der Natur der Sache, das sowas schnell mal koplizierter wird....
Gruß
f_igy
Hi,
als erstes ist die Frage wichtig, ob alle drei Spalten für sich unique sind, oder erst die Kombination der drei. Dann stellt sich die Frage, was Du eingentlich ereichen möchtest. Sicherstellen, dass die Kombination der Werte einzigartig ist (dann einen Unique Constraint / Index auf die drei Felder), oder tatsächlich einen Primärschlüssel für die Referenzierung aus einer anderen Tabelle erzeugen (dann ist eine forlaufende ID ganz gut).
Ach ja: das ist m.E. der Sinn eines PrimaryKey: er dient als ForeignKey in einer anderen Tabelle. Das sieht Wikipedia auch so:
Wenn man sich dafür entscheidet kann man auch weitere Constraints auf die referentielle Integrität auf der DB erzeugen, was Vor- und Nachteile hat. Dafür ist natürlich interessant, was Du als Optimierung ansiehst (Datenqualität, Lese- oder Schreibgeschwindigkeit, ect.)
Gruß
f_igy
Hm,
hinzufügen von Spalten geht in SQL/DDL mit "ALTER TABLE ADD COLUMN". Allerdings hört sich das, was Su da vorhast etwas komisch an...
Gruß
f_igy
Hi,
auch wenn ich den SQL-Server nicht kenne sollte er doch wohl so eine Art Import Utility für csv-Dateien haben.
Google verweist auf:
http://msdn.microsoft.com/de-de/library/ms188609.aspx
das Werzeug heist wohl bcp.
Vielleicht hilft auch
http://www.codeproject.com/Articles/290242/Import-Data-from-a-Text-or-CSV-file-into-SQL-Serve
Gruß
f_igy
Hi,
da würde ich den Kunden aber mal fragen, ob eine Abweichung von der altehrwürdigen 360-Tage-Regel zulässig ist...
Gruß
f_igy
Hi,
ohne SQL-Server gut zu kennen würde ich bei 100tsd Datensätzen auch mal über einen BULK INSERT
http://msdn.microsoft.com/de-de/library/ms188365.aspx
http://msdn.microsoft.com/de-de/library/ms175915.aspx
nachdenken und ggf. alle Tausende Datensätze mal ein Commit setzten, damit das Undo-Log nicht überhitzt.
Und die ID Vorher zu vergeben ist - wenn möglich - sicherlich auch nicht dumm.
Gruß
f_igy
Hi,
der Normalfall ist sicherlich den Mandanten als Feld mit in allen Tabellen aufzunehmen und bei den SQLs zu verwenden. Zentrale Tabellen zu Duplizieren führt dazu, dass diese auseinanderlaufen und Chaos entsteht.
Wenn Du überhaupt mit unterschiedlichen Schemata pro Mandant arbeiten möchtest (was ich nicht empfehle) solltest Du die zentralen Tabellen über Synonnyme (bzw. Aliase) oder schlimmstenfalls Views einblenden, um diese nur einmal vorzuhalten. Das spircht m.E. gegen unterschiedliche DBen, da man beim Zugriff über DB-Grenzen gerne mal "Überraschungen" erlebt.
Gruß
f_igy
Hi,
Du bindest gegen die Ergebnismenge des Linq-Statements. Die wird sich auch ändern, hat allerdings keine Bezeihung mehr zur Datenbank.
Gruß
f_igy
Gern geschehen,
im Übrigen sollten für diese Abfrage die DB-Statistiken representativ sein, vor allem, wenn Du die Abfrage nur auf Teilmengen der Kabine machst. Ich kenne den SQL Server nicht, aber wenn es da so etwas wie Datenhistogramme gibt könnte das auch hilfreich sein.
Hintergrund sind die unterschiedlichen JOIN Methoden wie z.B. merge scan (bei allen Werten) oder nested loop (bei einer Kabine) bzw. die Wahl der führenden Tabelle, die der Optimizer je nach Statisik wählt.
Gruß
f_igy