check resultset for emptiness in clojure jdbc - jdbc

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

How do I select several keys from tarantool at once, like with SELECT IN in SQL?

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, {})

F# Query Expression using join & groupBy in same query

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)

Sort the Inserted data on basis of Time in Ontology Model

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.

how to get the column name list from a table in clojure

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.

linq Cannot implicitly convert type 'System.Linq.IQuerable

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.

Resources