F# SQLProvider Columns Order Doesn't match the order in the table - postgresql

I select from a postgresql view\table and export the values into excel file.
The excel file column order need to be the same as the table, but the sqlProvider select them with abc order...
My Code is:
module ViewToExcel
open System
open System.IO
//open Microsoft.Office.Interop.Excel
open System.Drawing
open Npgsql
open FSharp.Data.Sql
open OfficeOpenXml
open Casaubon
open NpgsqlTypes
let [<Literal>] connectionString = #"Server=localhost;Database=db;User Id=postgres;Password=;"
let [<Literal>] npgPath = #"..\packages\Npgsql.3.1.7\lib\net451"
type sqlConnection = SqlDataProvider<ConnectionString = connectionString,
DatabaseVendor = Common.DatabaseProviderTypes.POSTGRESQL,
ResolutionPath = npgPath,
IndividualsAmount = 1000,
UseOptionTypes = true>
let functionParseViewToExcel (excelPath:string, serverName:string, dbName:string) =
/////////////////////////////////Get Data Connection///////////////////////
printf "connect to db\n"
let connectionUserString = #"Server="+serverName+";Database="+dbName+";User Id=postgres;Password=;"
let ctx = sqlConnection.GetDataContext(connectionUserString)
let weekCalcView = ctx.Public.CcVibeWeeklyCalculations
// weekCalcView|> Seq.toList
let weekCalcViewSeq = ctx.Public.CcVibeWeeklyCalculations|> Seq.toArray
////////////////////////////////// Start Excel//////////////////////////////
let newExcelFile = FileInfo(excelPath + "cc_vibe_treatment_period_"+ DateTime.Today.ToString("yyyy_dd_MM")+".xlsx");
if (newExcelFile.Exists) then
newExcelFile.Delete();
let pck = new ExcelPackage(newExcelFile);
//Add the 'xxx' sheet
let ws = pck.Workbook.Worksheets.Add("xxx");
//printf "success to start the excel file\n"
let mutable columNames = "blabla"
for col in weekCalcViewSeq.[0].ColumnValues do
let columnName = match col with |(a, _) -> a
//printf "a %A\n" columnName
let columnNamewithPsic = "," + columnName
columNames <- columNames + columnNamewithPsic
ws.Cells.[1, 1].LoadFromText(columNames.Replace("blabla,",""))|> ignore
ws.Row(1).Style.Fill.PatternType <- Style.ExcelFillStyle.Solid
ws.Row(1).Style.Fill.BackgroundColor.SetColor(Color.FromArgb(170, 170, 170))
ws.Row(1).Style.Font.Bold <- true;
ws.Row(1).Style.Font.UnderLine <- true;
let mutable subject = weekCalcViewSeq.[0].StudySubjectLabel.Value // in order to color the rows according to subjects
let mutable color = 0
for row in 1.. weekCalcViewSeq.Length do
let mutable columValues = "blabla"
for col in weekCalcViewSeq.[row-1].ColumnValues do
let columnValue = match col with |(_, a) -> a
//printf "a %A\n" columnValue
match columnValue with
| null -> columValues <- columValues + "," + ""
| _ -> columValues <- columValues + "," + columnValue.ToString()
ws.Cells.[row + 1, 1].LoadFromText(columValues.Replace("blabla,",""))|> ignore
/////////////////////Color the row according to subject///////////////
if (weekCalcViewSeq.[row - 1].StudySubjectLabel.Value = subject) then
if (color = 0) then
ws.Row(row + 1).Style.Fill.PatternType <- Style.ExcelFillStyle.Solid
ws.Row(row + 1).Style.Fill.BackgroundColor.SetColor(Color.FromArgb(255,255,204))
else
ws.Row(row + 1).Style.Fill.PatternType <- Style.ExcelFillStyle.Solid
ws.Row(row + 1).Style.Fill.BackgroundColor.SetColor(Color.White)
else
subject <- weekCalcViewSeq.[row - 1].StudySubjectLabel.Value
if (color = 0) then
color <- 1
ws.Row(row + 1).Style.Fill.PatternType <- Style.ExcelFillStyle.Solid
ws.Row(row + 1).Style.Fill.BackgroundColor.SetColor(Color.White)
else
color <- 0
ws.Row(row + 1).Style.Fill.PatternType <- Style.ExcelFillStyle.Solid
ws.Row(row + 1).Style.Fill.BackgroundColor.SetColor(Color.FromArgb(255,255,204))
pck.Save()
The Excel Output fields is:
bloating_avg,caps_fail,caps_success,date_of_baseline_visit,discomfort_avg and etc...
But the order in the table isn't the same.
Could someone help me?
Thanks!

You can write a small helper function to extract the field (column) names via npgqsl. After that you can just use this list of column names to create your excel table. The getColNames function gets it from a DataReader. Obviously you can refactor it further, to get at the tablename as parameter, etc.
#r #"..\packages\SQLProvider.1.0.33\lib\FSharp.Data.SqlProvider.dll"
#r #"..\packages\Npgsql.3.1.7\lib\net451\Npgsql.dll"
open System
open FSharp.Data.Sql
open Npgsql
open NpgsqlTypes
let conn = new NpgsqlConnection("Host=localhost;Username=postgres;Password=root;Database=postgres;Pooling=false")
conn.Open()
let cmd = new NpgsqlCommand()
cmd.Connection <- conn
cmd.CommandText <- """ SELECT * FROM public."TestTable1" """
let recs = cmd.ExecuteReader()
let getColNames (recs:NpgsqlDataReader) =
let columns = recs.GetColumnSchema() |> Seq.toList
columns |> List.map (fun x -> x.BaseColumnName)
let colnames = getColNames recs
//val colnames : string list = ["ID"; "DT"; "ADAY"]
rec.Dispose()
conn.Dispose()
You can see that the column names are not in alphabetical order. You could use this column name list to get at the records in the correct order. Or just use the Reader object directly without the type provider.
Edit: Using records to map the table
It is also possible to extract the data, using the type provider, in the required format, by wiring up the types, and then using .MapTo<T>:
type DataRec = {
DT:DateTime
ADAY:String
ID:System.Int64
}
type sql = SqlDataProvider<dbVendor,connString2,"",resPath,indivAmount,useOptTypes>
let ctx = sql.GetDataContext()
let table1 = ctx.Public.TestTable1
let qry = query { for row in table1 do
select row} |> Seq.map (fun x -> x.MapTo<DataRec>())
qry |> Seq.toList
val it : DataRec list = [{DT = 2016/09/27 00:00:00;
ADAY = "Tuesday";
ID = 8L;}; {DT = 2016/09/26 00:00:00;
ADAY = "Monday";
ID = 9L;}; {DT = 2016/09/25 00:00:00;
ADAY = "Sunday";

Related

How to create subset groups by identifying unique strings within column names

I have a dataframe:
`df <- data.frame(Year = 1940:2000,
sp99_002_04A_01 = rnorm(61, 1:100),
sp99_002_04B_01 = rnorm(61, 1:100),
sp99_002_05A_01 = rnorm(61, 1:100),
sp99_006_01A_14 = rnorm(61, 1:100),
sp99_023a_02B_06 = rnorm(61, 1:100),
sp99_023a_05B_06 = rnorm(61, 1:100),
sp99_010_03B_03 = rnorm(61, 1:100))`
Each name is formatted: speciesyear_plot#(subset)_sample#_trial#, as shown above.
I need to group columns for further analysis by plot number. That means all columns sharing the same unique character string in xxxx_THIS_xxxx_xx location of the column names, without having to call each plot # by name.
I ended up doing this:
'mydt <- fread("data.csv")
mydt <- melt.data.table(mydt, id.vars = "Year", value.name = 'measure', variable.name
= "ID")
mydt <- na.omit(mydt)
mydt[, ID := as.character(ID)]
splitNames <- lapply(mydt$ID, FUN = function(x) {
splitUpID <- strsplit(x, split = "_")
plot <- splitUpID[[1]][2]
return(plot)
})
plots <- unlist(splitNames)
mydt[, plot := plots]'

F# type class persistent counter

Gentlefolk,
Old time procedural/deterministic programmer battling with F# functional....
I require some counters to record counts from various areas of a program.
The following code compiles clean and appears to work but "ctr" is never incremented.
Any help appreciated, Ian
type Count() as this =
let mutable ctr = 0
do
printfn "Count:Constructor: %A" ctr
member this.upctr : int =
let ctr = ctr + 1
printfn "inCount.upctr %d" ctr
ctr
let myCount = new Count()
printfn "MyCtr1 %d" (myCount.upctr)
let fred = myCount.upctr
let fred = myCount.upctr
The value ctr is mutable. Use:
ctr <- ctr + 1 // this will mutate the value contained in ctr
instead of
// this will create a new binding which is not mutable
// and will shadow the original ctr
let ctr = ctr + 1
Also notice the warning that is telling you that you don't need as this in the type declaration.
You could also create a threadsafe counter like this:
let counter() =
let c = ref 0
fun () ->
System.Threading.Interlocked.Increment(c)
and use
let countA = counter()
let countB = counter()
countA() |> printfn "%i" // 1
countA() |> printfn "%i" // 2
countB() |> printfn "%i" // 1
Wrap this in a type or module, if needed.

Confusion with classes and global variables

I've come to a halt in the making of my first project. I'm trying to make a timecard program. I decided to use class object to handle the variables locally, but I can't figure out how to create a class object from user input.
import time
import datetime
import sqlite3
class Employee(object):
def __init__(self, name, position, wage=0, totalpay=0, totalhours=0):
self.name = name
self.position = position
self.wage = wage
self.totalpay = totalpay
self.totalhours = totalhours
def HourlyPay(self):
if self.position not in range(1, 4):
return "%s is not a valid position" % self.position
elif self.position == 1:
self.wage = 105.00
elif self.position == 2:
self.wage = 112.50
elif self.position == 3:
self.wage = 118.50
return "%s at position %i is making %i DKK per hour" % (self.name, self.position, self.wage)
def Salary(self, hours):
self.hours = hours
self.totalpay += self.wage * self.hours
self.totalhours += self.hours
return "%s next salary will be %i DKK" % (self.name, self.totalpay)
# This is out Employee object
EmployeeObj = Employee('John Doe', 1) # Our Employee object
EmployeeObj.HourlyPay()
EmployeeObj.Salary(43) # Takes 'hours' as argument
# Temporary Database config and functions below
conn = sqlite3.connect('database.db')
c = conn.cursor()
# For setting up the database tables: name, position and total.
def Create_table():
c.execute('CREATE TABLE IF NOT EXISTS EmployeeDb(name TEXT, position INTEGER, total REAL)')
# Run to update values given by our Employee object
def Data_entry():
name = str(EmployeeObj.name)
position = int(EmployeeObj.position)
total = float(EmployeeObj.totalpay)
c.execute('INSERT INTO EmployeeDb (name, position, total) VALUES (?, ?, ?)',
(name, position, total))
conn.commit()
c.close()
conn.close()
return True
What I'm trying to achieve is to create this variable from user input:
EmployeeObj = Employee('John Doe', 1) # Our Employee object
May be you can do something like this:
name = input("Enter employee name:")
position = int(input("Enter employee position:"))
EmployeeObj = Employee(name, position)

How to validate some of the dynamic table cells in asp.net

As the code below, I need to create a dynamic table in which each cell gets validated. If there is any wrong input, error message will pop up for that specific cell. Now our BA doesn’t want to display multiple error messages for each column. Only simply display one error message for each column like last name like “Last Name is invalid” no matter how many last names are invalid. How can I accomplish this? Is that possible?
Thanks in advance. I will really appreciate your response.
Thanks,
Dev2016
Protected Sub ShowBoxes(ByVal startRow As Integer, ByVal nRowsAdd As Integer)
Dim d As Integer = 10
For d = startRow To (startRow + nRowsAdd - 1)
Dim row As New HtmlTableRow()
row.VAlign = "center"
row.Attributes("class") = "bgA"
row.ID = "IndivRow_" & d.ToString
Dim col1 As New HtmlTableCell()
col1.Align = "center"
col1.Width = 29
col1.InnerHtml = (d + 1).ToString
Dim col2 As New HtmlTableCell()
col2.Width = 53
col2.VAlign = "left"
Dim txt2 As New TextBox()
txt2.ID = "Last_" & d.ToString
txt2.Columns = "29"
txt2.MaxLength = "30"
Dim reg2 As New RegularExpressionValidator()
reg2.ID = "regLast_" & d.ToString
reg2.ControlToValidate = "Last_" & d.ToString
reg2.ValidationExpression = "^[a-zA-Z0-9""()-. '\s]{1,50}$"
reg2.ErrorMessage = "Last Name on line " & (d + 1).ToString & " contains invalid characters."
reg2.Text = "*"
reg2.Display = ValidatorDisplay.Static
reg2.ValidationGroup = "SubmitFormClient"
reg2.SetFocusOnError = True
col2.Controls.Add(txt2)
col2.Controls.Add(reg2)
Dim col3 As New HtmlTableCell()
col3.Width = 53
col3.VAlign = "left"
Dim txt3 As New TextBox()
txt3.ID = "First_" & d.ToString
txt3.MaxLength = "30"
Dim reg3 As New RegularExpressionValidator()
reg3.ID = "regFirst_" & d.ToString
reg3.ControlToValidate = "First_" & d.ToString
reg3.ValidationExpression = "^[a-zA-Z0-9""()-. '\s]{1,50}$"
reg3.ErrorMessage = "First Name on line " & (d + 1).ToString & " contains invalid characters."
reg3.Text = "*"
reg3.Display = ValidatorDisplay.Static
reg3.ValidationGroup = "SubmitFormClient"
reg3.SetFocusOnError = True
col3.Controls.Add(txt3)
col3.controls.add(reg3)
row.Cells.Add(col1)
row.Cells.Add(col2)
row.Cells.Add(col3)
tableIndiv.Rows.Add(row)
Next d
End Sub

Coffeescript memoization?

I have a function that displays a number as a properly formatted price (in USD).
var showPrice = (function() {
var commaRe = /([^,$])(\d{3})\b/;
return function(price) {
var formatted = (price < 0 ? "-" : "") + "$" + Math.abs(Number(price)).toFixed(2);
while (commaRe.test(formatted)) {
formatted = formatted.replace(commaRe, "$1,$2");
}
return formatted;
}
})();
From what I've been told, repeatedly used regexes should be stored in a variable so they are compiled only once. Assuming that's still true, how should this code be rewritten in Coffeescript?
This is the equivalent in CoffeeScript
showPrice = do ->
commaRe = /([^,$])(\d{3})\b/
(price) ->
formatted = (if price < 0 then "-" else "") + "$" + Math.abs(Number price).toFixed(2)
while commaRe.test(formatted)
formatted = formatted.replace commaRe, "$1,$2"
formatted
You can translate your JavaScript code into CoffeeScript using js2coffee. For given code the result is:
showPrice = (->
commaRe = /([^,$])(\d{3})\b/
(price) ->
formatted = ((if price < 0 then "-" else "")) + "$" + Math.abs(Number(price)).toFixed(2)
formatted = formatted.replace(commaRe, "$1,$2") while commaRe.test(formatted)
formatted
)()
My own version is:
showPrice = do ->
commaRe = /([^,$])(\d{3})\b/
(price) ->
formatted = (if price < 0 then '-' else '') + '$' +
Math.abs(Number price).toFixed(2)
while commaRe.test formatted
formatted = formatted.replace commaRe, '$1,$2'
formatted
As for repeatedly used regexes, I don't know.