2009-12-17 5 views
2

J'ai récemment appris la programmation F # et fonctionnelle. Une application que j'ai trouvée très utile est la génération d'insertions SQL pour un chargement de données à partir d'un fichier CSV (ou d'une table excel) avec des ID associés.F # Générer du code SQL à partir de CSV

Le code suivant est mon résultat, que je crois que je trouverai très utile à l'avenir. Je pensais que d'autres pourraient également bénéficier de cela et je me réjouis de suggestions et d'autres scripts les gens ont trouvé une valeur inestimable dans leur collection:

// Returns some dataload SQL for area mapping. 
open System 
open System.IO 

// Read and split CSV into lists 
let map_ngo_area = File.ReadAllLines(@"P:\MY_TABLE.csv") 
         |> Array.to_list 
         |> List.map(fun x -> (x.Split([|','|]) 
               |> Array.map(fun y -> y.Trim())) 
               |> Array.to_list) 

// Output Formatting function 
let format_sql_record = "INSERT INTO MyTable 
    (ID, REF1_ID, REF2_ID, CreatedUser, CreatedDateTime, LastModifiedUser, LastModifiedDateTime) 
    VALUES 
    ({0}, {1}, {2}, 'system', getDate(), 'system', getDate())" 

// Generate the SQL for the given list. 
let generate_sql list = list |> List.mapi(fun index row -> 
              match row with 
               | [ngo_id; area_id] -> String.Format(format_sql_record, ((int index)+1), ngo_id, area_id) |> printfn "%s" 
               | _ -> printfn "") 

// Main Execution 
map_ngo_area |> generate_sql |> ignore 

// End of program, pause to view console output. 
System.Console.ReadKey() |> ignore 

Toutes les suggestions sur l'amélioration de mon code F # ou processus? Les commentaires sont également les bienvenus, car je suis relativement nouveau à ce paradigme et la pensée changeante n'est pas aussi claire que je le pensais.

Merci :)

Répondre

6

Voici quelques suggestions:

  • Ne pas utiliser la List.mapi avec des fonctions qui reviennent unit, car il n'y a pas grand chose que vous pouvez faire avec le résultat unit list. Vous devriez plutôt utiliser List.iteri, ce qui vous permettra d'omettre le |> ignore à la fin de votre section d'exécution principale. En outre, plutôt que d'avoir generate_sql imprimer les lignes générées une à la fois, il vaudrait peut-être mieux générer une liste de chaînes à la place. Notez que dans ce cas, vous reviendrez à List.mapi car la fonction que vous appliquez retournera un résultat pour chaque ligne. Utilisez le format d'impression F # plutôt que String.Format. Par exemple, plutôt que d'avoir format_sql_record être une chaîne, ont-il une fonction de type int->string->string->string: let format_sql_record = sprintf "INSERT INTO ... VALUES (%i, %s, %s, ...)"
  • En fonction de la version de F # que vous utilisez, vous devriez probablement utiliser la fonction renommé Array.toList au lieu de Array.to_list, puisque c'est le nom qui sera utilisé dans la version finale de F #.
+0

Impressionnant, grâce KVB ils sont quelques conseils! :) – Russell

4

Vous pouvez utiliser la correspondance de motif sur des tableaux aussi:

let map_ngo_area = File.ReadAllLines(@"P:\MY_TABLE.csv") 
        |> Array.to_list 
        |> List.map(fun x -> (x.Split([|','|]) 
              |> Array.map(fun y -> y.Trim())) 

let generate_sql list = list |> List.mapi(fun index row -> 
              match row with 
              | [| ngo_id; area_id |] -> printfn ... 
              | _ -> printfn "") 
Questions connexes