here is the sample that i want to ask:
FOR EACH table-name.... NO LOCK BY (IF TRUE THEN sort-this ELSE sort-that + sort-that2).
END.
This would result in an error.
if it is just
FOR EACH .. NO LOCK BY (IF TRUE THEN sort-this ELSE sort-that).
END.
then there is no error. Progress would accept the code
What is need is if condition is true then sort by one field else sort by two or more fields
If you are in a modern enough version of Progress, then you could construct a dynamic query. This will be more efficient in terms of run time as well as getting you round your problem as having IF statements in your query predicate will make index selection hard.
QueryString = "for each table no-lock...".
if true then
QueryString = QueryString + " by sort-this".
else
QueryString = QueryString + " by sort-that by sort-other".
create query QueryHandle.
QueryHandle:add-buffer(buffer table:handle).
QueryHandle:query-prepare(QueryString).
QueryHandle:query-open.
do while QueryHandle:get-next():
/*some stuff*/
end.
QueryHandle:query-close.
delete object QueryHandle.
As per the previous reply, this is not supported.
Typically, you'd have to prepare the result into a temp-table first, using a logical field in the temp-table for the result of your IF THEN ELSE expression.
Unfortunately, this syntax is not supported. As per the documentation, BREAK/BY expects an expression following it but not a statement.
I am very new to EPL queries.
Wrote this and it is throwing syntax error.
#Name('ExpressionTotalQuantitySoFar')
#Description('Gets the total quantity of a symbol so far')
create expression totalQuantitySoFar{ (TAX) =>
(Select sum(T.quantity) from TaxlotWindow as T where T.symbol = TAX.symbol and T.taxlotId < TAX.taxlotId)
};
create variable double totQty = 5.0 ;
#Name('ExpressionLongDebitBalanceTaxlotNoBox')
#Description('Check is if a trade side is invalid, returns rue for invalid statements')
create expression longDebitBalanceTaxlotNoBox{ (SECUR,TAX,ORD,AUE,FX) =>
totQty = totalQuantitySoFar(TAX)
case when (totQty > 0)
then cashImpactBase(SECUR,TAX,ORD,AUE,FX)*(-1)
else
0.0
end
};
It gives syntax error near case.
Any help?
Always include the syntax error text when posting. Else how is one supposed to be able to help.
My tip would be to simplify until the syntax is fine. Then add back stuff.
Most likely this strange declaration "totQty=.." is the cause as its wrong. EPL expressions are not a programming language and don't allow variable declarations like in Java or Scala. Perhaps just use a Java static method to compute instead of you need a programming language.
I'm struck by Haskell's terseness and elegance. But I work in a .Net house, so I use F# when I can get away with it--I may be the only one of hundreds across the country who uses it.
Does ADO.NET or F# offer something as terse and elegant as HDBC's executeMany? I'm making my way through Real World Haskell. In chapter 21 it offers this example:
ghci> conn <- connectSqlite3 "test1.db"
ghci> stmt <- prepare conn "INSERT INTO test VALUES (?, ?)"
ghci> executeMany stmt [[toSql 5, toSql "five's nice"], [toSql 6, SqlNull]]
ghci> commit conn
ghci> disconnect conn
I'd like to get this elegance and terseness in my F#. I've seen a lot of hype around using parameterized queries to avoid SQL injection attacks. I'm not using them in this case for three reasons:
I find parameterized queries in .Net ugly and burdensome.
My data comes from the corporate office, so it's (mostly) clean.
My table has 34 columns. I despise the idea of parameterizing a query with 34 columns.
Here's my F# code:
module Data
open System
open System.Data
open System.Data.OleDb
open System.Text.RegularExpressions
type Period = Prior | Current
let Import period records db =
use conn = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + db + ";Persist Security Info=False;")
let execNonQuery s =
let comm = new OleDbCommand(s, conn) in
comm.ExecuteNonQuery() |> ignore
let enquote = sprintf "\"%s\""
let escapeQuotes s = Regex.Replace(s, "\"", "\"\"")
let join (ss:string[]) = String.Join(",", ss)
let table = match period with
| Prior -> "tblPrior"
| Current -> "tblCurrent"
let statements =
[| for r in records do
let vs = r |> Array.map (escapeQuotes >> enquote) |> join
let vs' = vs + sprintf ",\"14\",#%s#" (DateTime.Now.ToString "yyyy-MM-dd") in
yield sprintf "INSERT INTO %s ( [Field01], [Field02], [Field03] [Field04], [Field05], [Field06], [Field07], [Field08], [Field09], [Field10], [Field11], [Field12], [Field13], [Field14], [Field15], [Field16], [Field17], [Field18], [Field19], [Field20], [Field21], [Field22], [Field23], [Field24], [Field25], [Field26], [Field27], [Field28], [Field29], [Field30], [Field31], [Field32], [Field33], [Field34] ) VALUES (%s)" table vs' |] in
do conn.Open()
execNonQuery (sprintf "DELETE FROM %s" table)
statements |> Array.iter execNonQuery
I've renamed the fields of the table(s) for security reasons.
Because all the fields on the table are text, I can easily Array.map them to escape and quote the values.
At between 9,000 and 10,000 records per day to import to each of the two tables, I want to do this as efficiently as possible. Hence my interest in the executeMany of Haskell. Too, though, I like the idea behind parameterized queries, and I like the way Hasekll has implemented them. Is there something equivalent in terseness and elegance in F#?
I agree with #JonnyBoats comment that generally using an F# SQL type provider like SqlDataConnection (LINQ-to-SQL) or SqlEntityConnection (Entity Framework) would be far more elegant than any kind of solution involving building insert statement strings by hand.
But, there is one important qualifier to your question: "At between 9,000 and 10,000 records per day to import to each of the two tables, I want to do this as efficiently as possible." In a scenario like this, you'll want to use SqlBulkCopy for efficient bulk inserts (it leverages native database driver features for much faster inserts than you are likely getting with HDBC's executeMany).
Here's a small example that should help you getting started using SqlBulkCopy with F#: https://stackoverflow.com/a/8942056/236255. Note that you'll be working with a DataTable to stage the data which though old and somewhat awkward to use from F#, is still superior to building insert statement strings in my opinion.
Update in response to comment
Here's a generalized approach to using SqlBulkCopy which is improved for your scenario (we pass in a column specification separately from the row data, and both are dynamic):
//you must reference System.Data and System.Xml
open System
open System.Data
open System.Data.SqlClient
let bulkLoad (conn:SqlConnection) tableName (columns:list<string * Type>) (rows: list<list<obj>>) =
use sbc = new SqlBulkCopy(conn, SqlBulkCopyOptions.TableLock, null, BatchSize=500, BulkCopyTimeout=1200, DestinationTableName=tableName)
sbc.WriteToServer(
let dt = new DataTable()
columns
|> List.iter (dt.Columns.Add>>ignore)
for row in rows do
let dr = dt.NewRow()
row |> Seq.iteri(fun i value -> dr.[i] <- value)
dt.Rows.Add(dr)
dt)
//example usage:
//note: since you know all your columns are of type string, you could define columns like
//let columns = ["Field1", "Field2", "Field3"] |> List.map (fun name -> name, typeof<String>)
let columns = [
"Field1", typeof<String>
"Field2", typeof<String>
"Field3", typeof<String>
]
let rows = [
["a"; "b"; "c"]
["d"; "e"; "f"]
["g"; "h"; "i"]
["j"; "k"; "l"]
["m"; "n"; "o"]
]
//a little funkiness to transform our list<list<string>> to list<list<obj>>,
//probably not needed in practice because you won't be constructing your lists literally
let rows = rows |> List.map (fun row -> row |> List.map (fun value -> value :> obj))
bulkLoad conn "tblPrior" columns rows
You could get even fancier / more terse using an approach involving reflection. e.g. create a type like
type RowData = { Field1:string; Field2:string; Field3:string }
and make a bulkLoad with a signature that takes a list<'a> argument such that it reflects over the property names and types of typeof<'a> to build the DataTable Columns, and similarly uses reflection to iterate over all the properties of a row instance to create and add a new row to the DataTable. In fact, this question shows how to make a generic ToDataTable method that does it (in C#).
I am following the example here
http://www.postgresql.org/docs/current/interactive/sql-fetch.html
And then looping the following command manually
FETCH FORWARD 5 FROM liahona;
in java. I have the above in an infinite loop and would like to know how I detect I'm at the end of the data set so I can break the loop
You get an empty result set when running FETCH FORWARD and you are at the end of the cursor's total result set. (This is described in slightly different words in the documentation.)
In use JDBC for this kind of SQL - it's for postgres command-line only.
For JDBC, you need something like this:
ResultSet rs = connection.createStatement().executeQuery("select * from mytable");
while(rs.next()) { // next() returns false if there are no more rows
int col1 = rs.getInt(1);
String col2 = rs.getString(2);
}
Is it possible to get the text of an OleDbCommand with all parameters replaced with their values? E.g. in the code below I'm looking for a way to get the query text
SELECT * FROM my_table WHERE c1 = 'hello' and c2 = 'world'
after I finished assigning the parameters.
var query = "SELECT * FROM my_table WHERE c1 = ? and c2 = ?";
var cmd = new OleDbCommand(query, connection);
cmd.Parameters.Add("#p1", OleDbType.WChar).Value = "hello";
cmd.Parameters.Add("#p2", OleDbType.WChar).Value = "world";
No: you have to iterate through the parameters collection yourself, doing a string.Replace() to get the equivalent. It's particularly painful when you have to use the ? syntax rather than the #parametername syntax.
The reason for this is that the full string is never assembled. The parameters and sent to the server and treated as data, and are never included in the string.
All the same, I for one understand your pain. It would have been nice if they included some kind of .ComposeSQL() method you could call for debugging purposes, that perhaps also produces a compiler warning to help avoid use in production.
If you just need to see what query was executed and dont need to work with it programmatically, you can use SQL Profiler.