I am trying to use the following link to get enhancement suggestions in RDF/XML format in ColdFusion.
http://dev.iks-project.eu:8081/engines
My problem is that the list contains the words repeatedly. Can I set some option to get the unique enhancements?
You need to use and be familiar with Jena and know how to use Java inline. Then it is simply a case of:
<cfset oldModel = createObject("java", "com.hp.hpl.jena.rdf.model.ModelFactory").createDefaultModel().read("http://dev.iks-project.eu:8081/engines")>
<cfset newModel = createObject("java", "com.hp.hpl.jena.rdf.model.ModelFactory").createDefaultModel()>
<cfset sparqlQuery = "SELECT DISTINCT ?s ?p ?o WHERE {?s ?p ?o}">
<cfset triples = createObject("java", "com.hp.hpl.jena.query.QueryExecutionFactory").create(sparqlQuery, rdfModel).execSelect()>
<cfloop condition="triples.hasNext()">
<cfset nextTriple = triples.nextSolution()>
<cfset newModel.add(newModel.createStatement(nextTriple.getResource("s"), newModel.createProperty(nextTriple.getResource("p").getURI()), nextTriple.get("o")))>
</cfloop>
<cfset outputStream = createObject("java", "java.io.ByteArrayOutputStream")>
<cfset newRdfXmlContent = newModel.write(outputStream, "RDF/XML-ABBREV").toString()>
Essentially, the best way to do this in ColdFusion is to loop through the list and create a ColdFusion struct. Assuming your web service returns a valid delimited list, here's an example how:
<cfset enhancements = "item1,item2,item3,item4,item1,item2,item3,item4">
<cfset objEnhancement = structNew()><!---- CREATE STRUCT--->
<cfloop index="item" list="#enhancements#"><!---- LOOP THROUGH RESPONSE TEXT--->
<cfset objEnhancement[item] = ""><!---- CREATE STRUCT KEYS, THESE WILL AUTO DE-DUPE --->
</cfloop>
<cfset uniqueEnhancements = StructKeyList(objEnhancement)> <!---- DUMP THE STRUCT KEYS TO A NEW LIST---->
Related
I have a query-of-queries that performs a LIKE condition on a variable string:
When the variable contains a single word that includes a single quote, some results are returned, but not all:
<cfset _myVar = "Women's" />
<cfquery name="_qData" dbtype="Query">
SELECT
ID
FROM MyQoQ
WHERE NAME LIKE '%#_myvar#%'
OR DESCRIPTION LIKE '%#_myvar#%'
</cfquery>
When the variable contains more than one word, and one of those words includes a single quote, no records are returned:
<cfset _myVar = "Women's Initiative" />
<cfquery name="_qData" dbtype="Query">
SELECT
ID
FROM MyQoQ
WHERE NAME LIKE '%#_myvar#%'
OR DESCRIPTION LIKE '%#_myvar#%'
</cfquery>
I've tried PreserveSingleQuotes() as well as wrapping the varaibles with CFQUERYPARAM, but, to no avail - I get the same results.
Is there a way to make this work?
Adding in a repro case
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfquery name="res" dbtype="query">
SELECT *
FROM myQuery
WHERE hello LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%$what's up%">
</cfquery>
<cfdump var="#res#">
Railo 4.1.1.009 - returns both results (rows 2 and 3)
ColdFusion 10,0,13,287689 - returns no results
If I change my SQL to
WHERE hello LIKE '%what''s up%'
I still get no results
aarh!! a classic case of royal pain in the rear.
To solve this, you have to add an extra ' to every ' in your search term, there by escaping it.
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfset x = "what's up" />
<cfquery name="res" dbtype="query">
SELECT *
FROM myQuery
WHERE hello LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="#replace(x, "'", "''", "all")#%">
</cfquery>
<cfdump var="#res#">
if you do this directly, as you mentioned,
WHERE hello LIKE '%what''s up%'
the parser is going bonkers. But, if you pass the value via a function return value, the run time assignment of values via a variable somehow makes the parser happy.
I remember using such tricks in sending multiple SQL statements delimited with ';' in cfquery. Directly writing
"DECLARE x NUMBER; SELECT 2 INTO x FROM DUAL;"
inside cfquery fails, but assigning them to a string and then sending the string as a return value for any string manipulator function (lcase, ucase, etc) worked perfectly.
Note: the problem is solved, but if my explanation and approach is diff, feel free to correct and comment.
I'm running ColdFusion 10 u13.
Modifying your repo code this seemed to work:
<cfset myQuery = queryNew('hello')>
<cfset queryAddRow(myQuery,5)>
<cfset querySetCell(myQuery,"hello","what up",1)>
<cfset querySetCell(myQuery,"hello","what's up",2)>
<cfset querySetCell(myQuery,"hello","what's up friends",3)>
<cfset querySetCell(myQuery,"hello","what u",4)>
<cfset querySetCell(myQuery,"hello","what",5)>
<cfdump var="#myQuery#">
<cfquery name="res" dbtype="query">
SELECT *
FROM [myQuery]
WHERE [hello] LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%what''s up%">
</cfquery>
Note the double single quotes in the <cfqueryparam> tag. Like Dan I would have thought that the <cfqueryparam> tag would have taken care of this for you automatically. Perhaps this is a bug in QoQ?
I am trying to set a variable dynamically into a structure via CFLOOP. I have read Ben Nadal's blog post but cant seem to get the assignment correct. I would like to use dot notation and make the VIN a sub structure of values.
Here is my code:
<cfloop query="VINs">
<cfquery name="carsQue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
WHERE (VIN = #VIN#)
</cfquery>
<cfset carsStruct= StructNew()>
<cfset carsStruct.[VIN].MAKE = '#carsQue.MODEL#'>
<cfset carsStruct.[VIN].MODEL = '#carsQue.MAKE#'>
</cfloop>
Any guidance would be greatly appreciated,
Thanks
Running a query inside a loop is almost always a bad idea. In your case, a better option would be:
<cfif ListLen(valuelist(vins.vin)) gt 0>
<cfquery name=CarsQue datasource = "carsData">
select vin, model, make, etc
from carsDB
where vin in (<cfqueryparam cfsqltype="cf_sql_varchar"
value="#valuelist(vins.vin)#" list="true">)
</cfquery>
<cfset carsStruct = StructNew()>
<cfloop query="carsQue">
code for your struct
</cfloop>
<cfelse>
code for vins query returning no data
</cfif>
Better yet would be to get all the data with one query. You didn't provide enough information to determine if this was possible, but it often is.
Create a structure outside loop and and setting variable within loop can solve the problem. in a current scenario each time loop run its create a new structure.
you can do some thing like this
<cfset carsStruct= StructNew()>
<cfloop query="VINs">
<cfquery name="carsQue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
WHERE VIN = <cfqueryparam cf_sql_type="cf_sql_varchar" value="#VINs.VIN#">
</cfquery>
<cfset carsStruct[VINs.VIN].MAKE = carsQue.MODEL>
<cfset carsStruct[VINs.VIN].MODEL = carsQue.MAKE>
</cfloop>
Based on the limited information you've given you should be able to run one query and loop through that to add to your struct.
<cfset carsStruct= {}> //new struct
<cfif VINs.RecordCount> //your VINs query has records
<cfquery name="carsQueue" datasource="carsData">
SELECT VIN, MODEL, MAKE, etc
FROM CarsDB
// Quoted list of all your VINs. cfqueryparam prevents against SQL injection
WHERE VIN IN (<cfqueryparam cf_sql_type="cf_sql_varchar" value="#ValueList(VINs.VIN)#" list="true">
</cfquery>
<cfloop query="carsQueue">
<cfset carsStruct.[carsQueue.VIN].MAKE = carsQueue.MODEL>
<cfset carsStruct.[carsQueue.VIN].MODEL = carsQueue.MAKE>
</cfloop>
<cfelse>
// if VINs query return nothing a blank struct will be returned.
//You do NOT need this <cfelse> unless you are returning something when the query is blank
</cfif>
I have a database that has four columns id,languageid,name,text
Depending on the users' default language, I create a query that has all the texts for the set language (where languageid=#user.defaultlanguageid#)
What's the easiest way of retrieving these when it comes to displaying the required string.
Seems like creating a subquery every time is a bit much work.
Is creating a function the best way to go?
You could just have a single query that populates a struct (perhaps an application-level struct) - something like this:
<cfif not IsDefined("application.langMap")>
<cfquery name="langNames" datasource="...">SELECT * from langTable</cfquery>
<cfset application.langMap = {}>
<cfloop query="langNames">
<cfif not StructKeyExists(application.langMap, languageid)>
<cfset application.langMap[languageid] = {}>
</cfif>
<cfset application.langMap[languageid][name] = text>
</cfloop>
</cfif>
And then as you need the particular string within the display:
#application.langMap[mylanguageid][name]#
If a series of queries are created like so:
<cfloop list="#platform_list#" index="x">
<cfquery name="#trim(x)#" dbtype="query">
<!--- stuff to build the query --->
</cfquery>
</cfloop>
and I then return the queries in a struct like so:
<cfset queries_RET = StructNew() />
<cfloop list="#platform_list#" index="x">
<cfif StructKeyExists(args, #trim(x)#)>
<!--- here's where I think things go horribly wrong --->
<cfset queries_RET[x] = #x# />
</cfif>
</cfloop>
<cfreturn queries_RET />
And then when returned to the calling function as "graphData", I try to access it like so:
<cfloop list="#platform_list#" index="x">
<cfif StructKeyExists(url, x) and StructKeyExists(graphData, x)>
<cfloop query="graphData[x]">
I get an error at the last line:
Attribute validation error for tag cfloop.
The value of the attribute query, which is currently graphData[x], is invalid.
The value of the struct at graphData[x] is a string having the same value as the element name... so what do I do to assign the query with that name instead? I'm sure it's ridiculously obvious. :(
EDIT:
I'll give the answer to Shawn, although I finally figured out what my underlying issue(s) are. First, I didn't realize that
<cfset queries_RET[x] = #x# />
doesn't actually assign the query to the element at x, but instead a reference to it. To assign the actual query object, I need to do this:
<cfset queries_RET[x] = #Evaluate(x)# />
Second, when the struct is returned to the calling function, calling
<cfloop list="#Application.platform_list#" index="x">
<cfloop query="#graphData[x]#">
didn't work because the query attribute of cfloop is looking for a reference to a query object --- and the query object it was looking for didn't exist since it hadn't been returned.
Finally, now that I am actually returning a valid query object, that query attribute still doesn't work, because now graphData[x] isn't a reference. To make it work, I have to first assign a reference, and use that as the query attribute in the cfloop:
<cfloop list="#Application.platform_list#" index="x">
<cfset thisQuery = #graphData[x]#>
<cfloop query="thisQuery">
I think that my fundamental problem was not understanding the the query attribute isn't an actual query object, but a reference to one instead. It's been a learning curve!
Try
<cfloop list="#platform_list#" index="x">
<cfif StructKeyExists(url, x) and StructKeyExists(graphData, url[x])>
<cfset q = graphData[x]>
<cfloop query="q">
If this throws
The value of the attribute query, which is currently q, is invalid
Then you should cfdump the q make sure it is a query object.
The <CFLOOP> query attribute takes the name of a query (string), not an actual query object.
When you pass something into that attribute, CF expects it to be a string.
If it's a literal, CF will expect it to be the name of a valid query.
If it's a variable, CF will expect the value of the variable to be equal to the name of the query.
Therefore, the output you ultimately want is:
<cfloop list="#platform_list#" index="x">
<cfloop query="#x#">
Here is a full snippet of code that confirms this, which you may refer to/compare to for your own code:
<cfset query_a = QueryNew('id,name,pass') />
<cfset QueryAddRow(query_a)>
<cfset QuerySetCell(query_a,'id',1)>
<cfset QuerySetCell(query_a,'name','joe')>
<cfset QuerySetCell(query_a,'pass','joe123')>
<cfset query_b = QueryNew('id,name,pass') />
<cfset QueryAddRow(query_b)>
<cfset QuerySetCell(query_b,'id',4)>
<cfset QuerySetCell(query_b,'name','pete')>
<cfset QuerySetCell(query_b,'pass','pete123')>
<cfset query_c = QueryNew('id,name,pass') />
<cfset QueryAddRow(query_c)>
<cfset QuerySetCell(query_c,'id',7)>
<cfset QuerySetCell(query_c,'name','frank')>
<cfset QuerySetCell(query_c,'pass','frank123')>
<cfset platform_list = 'query_a,query_b,query_c' />
<cfloop list="#platform_list#" index="x">
<cfloop query="#x#">
<cfoutput>#id# #name# #pass#</cfoutput><br/>
</cfloop>
</cfloop>
You'll notice in this snippet that if you change the query attribute back to "x" (rather than #x#) you'll produce the exact same error you are encountering now.
Why?
Answer: platform_list is a comma-delimited list of strings (which x becomes via the loop), not a comma-delimited list of Query objects.
I want to get a specific row in a ColdFusion Query object without looping over it.
I'd like to do something like this:
<cfquery name="QueryName" datasource="ds">
SELECT *
FROM tablename
</cfquery>
<cfset x = QueryName[5]>
But it's giving me an error saying that the query isn't indexable by "5". I know for a fact that there are more than 5 records in this query.
You can't get a row in CF <= 10. You have to get a specific column.
<cfset x = QueryName.columnName[5]>
It's been 8 years since I posted this answer, however. Apparently CF11 finally implemented that feature. See this answer.
This can now be accomplished in coldfusion 11 via QueryGetRow
<cfquery name="myQuery" result="myresult" datasource="artGallery" fetchclientinfo="yes" >
select * from art where ARTID >
<cfqueryparam value="2" cfsqltype="CF_SQL_INTEGER">
</cfquery>
<cfdump var="#myQuery#" >
<cfset data = QueryGetRow(myQuery, 1) >
<cfdump var="#data#" >
I think there is a simpler solution...
I am guessing you know your column names and only want this column or that one. Then you don't need to put the whole row in a struct. You can reference the query by row number (remember its 1 based not 0).
yourQueryName["yourColumnName"][rowNumber]
<cfoutput>
#mycontacts["Name"][13]#
#mycontacts["HomePhone"][13]#
</cfoutput>
You have to convert the query to a struct first:
<cfscript>
function GetQueryRow(query, rowNumber) {
var i = 0;
var rowData = StructNew();
var cols = ListToArray(query.columnList);
for (i = 1; i lte ArrayLen(cols); i = i + 1) {
rowData[cols[i]] = query[cols[i]][rowNumber];
}
return rowData;
}
</cfscript>
<cfoutput query="yourQuery">
<cfset theCurrentRow = GetQueryRow(yourQuery, currentRow)>
<cfdump var="#theCurrentRow#">
</cfoutput>
Hope this points you in the right direction.
I know I come back to this thread any time I Google "cfquery bracket notation". Here's a function I wrote to handle this case using bracket notation. Hopefully this can help someone else too:
<cffunction name="QueryGetRow" access="public" returntype="array" hint="I return the specified row's data as an array in the correct order">
<cfargument name="query" required="true" type="query" hint="I am the query whose row data you want">
<cfargument name="rowNumber" required="true" hint="This is the row number of the row whose data you want">
<cfset returnArray = []>
<cfset valueArray = []>
<cfset cList = ListToArray(query.ColumnList)>
<cfloop from="1" to="#ArrayLen(cList)#" index="i">
<cfset row = query["#cList[i]#"][rowNumber]>
<cfset row = REReplace(row, "(,)", " ")>
<cfset returnArray[i] = row>
<cfset i++>
</cfloop>
<cfreturn returnArray>
</cffunction>
The REReplace is optional, I have it in there to cleanse commas so that it doesn't screw up the arrayToList function later on if you have to use it.
I wanted to extract a single row from a query, and keeping the column names (of course). This is how I solved it:
<cffunction name="getQueryRow" returntype="query" output="no">
<cfargument name="qry" type="query" required="yes">
<cfargument name="row" type="numeric" required="yes">
<cfset arguments.qryRow=QueryNew(arguments.qry.columnlist)>
<cfset QueryAddRow(arguments.qryRow)>
<cfloop list="#arguments.qry.columnlist#" index="arguments.column">
<cfset QuerySetCell(arguments.qryRow,arguments.column,Evaluate("arguments.qry.#arguments.column#[arguments.row]"))>
</cfloop>
<cfreturn arguments.qryRow>
</cffunction>
Methods previously described for obtaining query data by column name and row number (variables.myquery["columnName"][rowNumber]) are correct, but not convenient for getting a full row of query data.
I'm running Railo 4.1. And this is a cool solution. Too bad this can't be done the way we would want outright to get a full row of data, but the following method allows us to get what we want through a few hoops.
When you serializeJSON(variables.myquery) it changes the query to a JSON formatted cfml struct object with two items: "Columns" and "Data". Both of these are arrays of data. The "data" array is a two-dimensional array for rows and then columnar data.
The issue is that now we have an unusable string. Then if we re-serialize it it's NOT a query, but rather usable regular struct in the format described above.
Assume we already have a query variable named 'variables.myquery'. Then look at the following code:
<cfset variables.myqueryobj = deserializeJSON(serializeJSON(variables.myquery)) />
Now you get the two dimensional array by getting this:
<cfset variables.allrowsarray = variables.myqueryobj.data />
And you get one query row array by getting this:
<cfset variables.allrowsarray = variables.myqueryobj.data[1] />
OR the last row this way:
<cfset variables.allrowsarray = variables.myqueryobj.data[variables.myquery.recordCount] />
And you can get individual column values by column order number iteration:
<cfset variables.allrowsarray = variables.myqueryobj.data[1][1] />
Now this might be slow and possibly unwise with large query results, but this is a cool solution nonetheless.
Check out the documentation for queryGetRow. It accepts a query object and an index of the row with the first row being referenced with the index of 1 (NOT 0) The index used this way is required to be a positive integer.
<cfquery name="QueryName" datasource="ds">
SELECT *
FROM tablename
</cfquery>
<!---
This would retrieve the first record of the query
and store the record in a struct format in the variable 'x'.
--->
<cfset x = queryGetRow(QueryName, 1) />
<!---
This is an alternative using the member method form of queryGetRow
--->
<cfset x = QueryName.getRow(1) />