i'm using clojure with jdbc, compojure, cheshire, postgresql, c3p0, tryin make REST. When i'm using this code as handler
(defn get-document [id]
(sql/query (db-connection)
["select * from document where id = cast(? as integer)" id]
{:row-fn
(fn [first]
(if (empty? first )
(response "empty")
(response first)
))}))
If reslutset is not empty i have response as i need, but if its empty i got empty brackets [].
Also this is my project dependencies
:dependencies [[org.clojure/clojure "1.8.0"]
[compojure "1.5.1"]
[ring/ring-json "0.4.0"]
[c3p0/c3p0 "0.9.1.2"]
[ring/ring-defaults "0.2.1"]
[org.clojure/java.jdbc "0.7.3"]
[org.postgresql/postgresql "42.1.4"]
[cheshire "5.8.0"]]
The :row-fn function is executed for each row in the result set. When your result set is empty, row-fn is not called.
You may need to use the result of sql/query to handle the response of the query. When there is no result an empty vector is returned (this is []). You can check if the result is empty by calling empty?. Something like this:
(defn get-document [id]
(let [query ["select * from document where id = cast(? as integer)" id]
rows (sql/query (db-connection) query)]
(if (empty? rows)
(response "empty")
(response (first rows)))))
Related
I want to select several records from Tarantool in one call, but don't see how can I pass several keys to space:get or space:select
You can do it using Lua as well as SQL.
1) Use a stored procedure in Lua, like this one:
function select_several(space_name, index_name, keys)
local obj = index_name == nil and box.space[space_name] or box.space[space_name].index[index_name]
local result = {}
for _, key in pairs(keys) do
table.insert(result, obj:get(key))
end
return result
end
...
select_several('test', nil, {1, 2})
2) Starting with Tarantool 2.0, you can use SQL (provided that you have space format):
box.execute('select * from "test" where "id" in (1, 3);')
One more variant equivalent to the SQL query select * from "test" where "id" in (1, 3) using LuaFun:
tarantool> box.space.test:pairs():filter(function (tuple) return tuple.id == 1 or tuple.id == 3 end):totable()
It is a generic variant if there is no 'id' index in the space, and it implies performing fullscan.
If a unique index named "id" exists, a more efficient variant is possible:
tarantool> fun.iter({1, 3}):map(function (value) return box.space.test.id:get(value) end):totable()
Otherwise if the index is not unique, then it will look like
tarantool> fun.iter({1, 3}):map(function (value) return box.space.test.id:select(value) end):reduce(function (result, data) for _, rec in ipairs(data) do table.insert(result, rec) end return result end, {})
I decided to learn how to use query expressions in F# and found the official Microsoft documentation. The caveats don't seem spelled out so I'm sure I've hit a problem with a simple fix but don't know why I'm getting the error it shows.
My thought was to write a query that did both a join and grouping in the same go. For example, using their sample 'MyDatabase' I thought I would try to find the number of classes that each student is enrolled in. After writing the following query, the compiler flags no warning, but when I go to run it it gives an error.
My query expression:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
groupBy student into group
select (group.Key, group.Count())
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student.Name classCount)
The error:
System.InvalidOperationException: Could not format node 'New' for execution as SQL.
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
> at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitAlias(SqlAlias alias)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitRow(SqlRow row)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.VisitSelect(SqlSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlFormatter.Visitor.Format(SqlNode node, Boolean isDebug)
at System.Data.Linq.SqlClient.SqlFormatter.Format(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0008>.$FSI_0008.main#() in C:\Users\JDKS\Library\query expressions.fsx:line 129
Stopped due to error
I even thought I could get out of this issue by using a subquery:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for s in student.Name do
select course.CourseID
count
}
select (student.Name, count)
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
but that gave an even larger error:
> System.NotSupportedException: Sequence operators not supported for type 'System.String'.
at System.Data.Linq.SqlClient.SqlBinder.Visitor.ConvertToFetchedSequence(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSequence(SqlSelect sel)
at System.Data.Linq.SqlClient.SqlVisitor.VisitScalarSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSubSelect(SqlSubSelect ss)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.FetchExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitNew(SqlNew sox)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope(SqlIncludeScope scope)
at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node)
at System.Data.Linq.SqlClient.SqlBinder.Bind(SqlNode node)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection`1 parentParameters, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source)
at <StartupCode$FSI_0015>.$FSI_0015.main#() in C:\Users\JDKS\Library\query expressions.fsx:line 144
Stopped due to error
My guess is that I don't truly understand what's going on under the hood enough to work out the error or lead myself to a solution. Is it possible to query for what I want here? Is there a workaround?
When I tried running it locally I got this exception
System.Exception: Grouping over multiple tables is not supported yet
I am not sure why you would be getting the less pretty version of that error. But if you pull the GroupBy out of the query, things seem to work fine.
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
select (student.Name, course.Id)
}
|> Seq.countBy snd
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
I believe that the reason why your first query is not working is because of the groupBy student into group.
I think what you actually want to write is groupBy student.StudentID into group.
I found an answer from a similar question:
query {
for student in db.Student do
join course in db.CourseSelection
on (student.StudentID = course.StudentID)
let count = query {
for c in db.CourseSelection do
where (c.StudentID = student.StudentID)
select c
count
}
select (student.Name, count)
distinct
}
|> Seq.iter (fun (student, classCount) -> printfn "Student %s has %i classes" student classCount)
The underlying paradigm of these query expressions still eludes me.
EDIT:
I found that you can join implicitly without needing to use the join operator
query {
for student in db.Student do
let count = query {
for course in student.CourseSelection do
count
}
select (student.Name, count)
}
|> Seq.iter (fun (name, count) -> printfn "%s has %i courses" name count)
I have an ontology Model. I am inserting integer data in one of the class instance through Sparql update. The model is storing the data randomly with out any order. Now when I want to extract this data through Sparql Query I want it in order of the time of insertion. How could i achieve this? Any idea?
P.S: My ontology Model is made in Protege software.
My Query for inserting Data is below one.
PREFIX test:<http://www.semanticweb.org/muhammad/ontologies/2017/2/untitled-ontology-14#>
INSERT {
?KPI_Variables test:hasValue_ROB1 10
} WHERE {
?KPI_Variables test:hasValue_ROB1 ?Newvalue
FILTER(?KPI_Variables= test:Actual_Production_Time)
}
And For Getting the data I am using the following Query:
PREFIX test:<http://www.semanticweb.org/muhammad/ontologies/2017/2/untitled-ontology-14#>
SELECT ?KPI_Variables ?Newvalue WHERE {
?KPI_Variables test:hasValue_ROB1 ?Newvalue
FILTER(?KPI_Variables = test:Actual_Production_Time)
} LIMIT 25
Data in RDF is simply triples. There's no notion of when a triple is added to a graph. If you want that kind of information, you'll need to make it explicit in your data model. SPARQL does include a now function that lets you get a timestamp for when a query is run. That means that you could do something like this:
prefix : <urn:ex:>
insert {
[] :hasSubject ?s ;
:hasPredicate ?p ;
:hasObject ?o ;
:hasTime ?now .
}
where {
#-- Fake a couple of triples
values (?s ?p ?o) {
(:a :p :b)
(:c :q :d)
}
#-- Get the current time
bind (now() as ?now)
}
Now your graph contains data like:
#prefix : <urn:ex:> .
[ :hasObject :d ;
:hasPredicate :q ;
:hasSubject :c ;
:hasTime "2017-04-28T13:32:11.482+00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime>
] .
[ :hasObject :b ;
:hasPredicate :p ;
:hasSubject :a ;
:hasTime "2017-04-28T13:32:11.482+00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime>
] .
Which you can query like:
prefix : <urn:ex:>
select ?s ?p ?o ?time {
[] :hasSubject ?s ;
:hasPredicate ?p ;
:hasObject ?o ;
:hasTime ?time
}
order by ?time
s,p,o,time
urn:ex:c,urn:ex:q,urn:ex:d,2017-04-28T13:32:11.482+00:00
urn:ex:a,urn:ex:p,urn:ex:b,2017-04-28T13:32:11.482+00:00
Once you've inserted some things at different times, you'd have different time values, so sorting would be meaningful. I'd suggest that you don't just reify the triples like I did (and if you are going to go with a straightfoward reification, you should probably use the standard vocabulary for it), but rather have some meaningful structure that actually has timestamps as part of it.
I am using clojure.java.jdbc, and want to get the column name list from a table, but how should I do it in clojure? I found there is a function of result-set-read-column, and I guess I could use it, but I don't understand the function fully, could any one give an example?
result-set-read-column is for transforming values, not what you want in this case.
This is the easiest way I can think of right now:
(defn column-names [db table]
(let [rs (clojure.java.jdbc/query db (str "select * from " table " limit 1"))]
(-> rs first keys)))
The :as-arrays? option of query returns the resultset as arrays, with the first array being the column names, the next arrays having the field information. This also works without results
(j/query db-spec
["select TOP 1 * from person"]
:as-arrays? true)
[[:surname :first-name :age :gender]
["Doe" "John" 32 "male"]]
(j/query db-spec
["select TOP 0 * from person"]
:as-arrays? true)
[[:surname :first-name :age :gender]]
If you want to process the resultset yourself, you can use db-with-resultset which takes a db-spec, a query vector, and a function to process the resultset. Be sure to realise everything in that function with a doall or mapv to prevent lazy processing and the resultset being closed before processing has finished.
(defn get-field-info
[rs]
(let [m (.getMetaData rs)]
(into {} (mapv (fn [c] [(.getColumnName m c)
(.getColumnTypeName m c)])
(range 1 (inc (.getColumnCount m)))))))
(j/db-query-with-resultset db-spec
["select TOP 0 * from person"]
get-field-info)
{"surname" "nvarchar","first-name" "nvarchar","age" "int","gender" "nvarchar"}
Be aware these options only return the metadata of the query resultset, not of the table itself !
(j/query db-spec
["select TOP 0 surname, first-name from person"]
:as-arrays? true)
[[:surname :first-name]]
If you want to query the metadata of the database structure itself without using queries, you can use with-database-metadata and metadata-query from clojure.java.jdbc. The following will give all column names from the "person" table:
(j/with-db-metadata [m db-spec]
(->> (.getColumns m "mycatalog" nil "person" nil)
(j/metadata-query)
(map :column_name)))
["surname" "first-name" "age" "gender"]
The with-db-metadata binds the DataBaseMetaData of a db-spec to a var, so it only needs to be evaluated once, and the metadata-query processes the returns of a Java DatabaseMetaData method call into a clojure data structure.
I have the following query:
tblVAL tblval = db.tblVALs.Where(p => p.PID == pid);
Note that I expect to get a list of items that should be returned.
tblVAL is a table in Entity Framework. NOTE THAT I NEED A LIST OF ITEMS TO BE RETURNED AS THERE CAN BE MORE THAN 1 ITEMS THAT IS RETURNS. AS SUCH, I DO NOT WANT TO USE First(), etc.
I get the following message
Cannot implicitly convert type 'System.Linq.IQuerable to wa.Models.tblVAL'. An implicit converion exist (are you missing a cast? )
Your query is returning a collection. You need to call SingleOrDefault, Single, First, or FirstOrDefault to get a single record.
tblVAL tblval = db.tblVALs.Where(p => p.PID == pid).SingleOrDefault();
If you want a collection, change your variable type to a collection:
IEnumerable<tblVAL> tblval = db.tblVALs.Where(p => p.PID == pid);
You can also call ToList to force query execution:
List<tblVAL> tblval = db.tblVALs.Where(p => p.PID == pid).ToList();
If you can get many results back, the simple thing to do is to call ToList.
Become familiar with the methods of System.Linq.Enumerable and you will be an expert at linq.