Selecting A row range from a query of queries - coldfusion

How would I select a specific range of rows using a query of queries?
e.g
<cfquery name="myQuery" maxrows ="20" startrow="12">
SELECT *
FROM previous_query
WHERE row_numer >= 12
</cfquery>
that sort of thing...

This was a tricky one but your problem intrigued me. I think I may have a solution
I wrote a function that delete everything prior to the rows you want and then deletes everything after the rows you want.
the function rowrange() takes 3 parameters.
1. the queryname you are working with.
2. the starting row you want
3. the number of rows you want.
UPDATED: My friend John Whish pointed out that I actually do not need to do the looping to get this to work. Removing the loops makes this much more scalable.
<cfquery name="myQuery">
SELECT *
FROM previous_query
WHERE row_numer >= 12
</cfquery>
<cfset rowRange(myQuery,7,4)>
<cfdump var="#myQuery#">
<cffunction name="rowRange" hint="return a range of rows from a given query">
<cfargument name="qObj" type="query" required="true">
<cfargument name="start" type="numeric" required="true" default="1" hint="The number of the first row to include">
<cfargument name="range" type="numeric" required="true" default="1" hint="The number of rows">
<cfset var i = arguments.start+arguments.range-1>
<cfset arguments.qObj.removeRows(i,arguments.qObj.recordcount-i)>
<cfset arguments.qObj.removeRows(0,arguments.start-1)>
<cfreturn arguments.qObj>
</cffunction>

Doing this natively in CF isn't supported, so you'll have to add a column in your original record set to do the counting for you.
SELECT ..., row_num AS Counter
Row_Num may vary based on your DBMS.

Related

Can I return columns in text form from a function with sql query in coldfusion

I want to write a function in CF, that has a query that returns multiple columns. I researched and read and could only find examples of functions with sql queries only returning the table view of the struct.
How would I write a function in CF with sql queries and output each column in text format
I been googling it and looking on tutorial websites, with no luck
<cffunction name="queryListEmployee" returntype="query" output="false">
<cfargument name="EMPID" type="numeric" default="1"/>
<cfset var listEmployee = ""/>
<cfquery name="local.listContractors" datasource="DB">
SELECT E.FIRSTNAME, E.LASTNAME
FROM EMPLOYEE E
WHERE E.ID = <cfqueryparam value="#arguments.EMPID#" cfsqltype="cf_sql_decimal" scale="0"/>
</cfquery>
<cfreturn local.listEmployee/>
I want to be able to output column names like queryListEmployee.firstname and queryListEmployee.lastname
You've got the idea right. Just a few tweaks:
<cffunction name="getEmployeeByID" returntype="query" output="false">
<cfargument name="EMPID" type="numeric" default="1"/>
<cfquery name="local.employee" datasource="DB">
SELECT E.FIRSTNAME, E.LASTNAME
FROM EMPLOYEE E
WHERE E.ID = <cfqueryparam
value="#arguments.EMPID#"
cfsqltype="cf_sql_integer"/>
</cfquery>
<cfreturn local.employee/>
</cffunction>
Then call this function like so:
<cfset qEmployee = getEmployeeByID(1)>
and output the data like this:
<cfoutput query="qEmployee">
<li>#qEmployee.FIRSTNAME# #qEmployee.LASTNAME#</li>
</cfoutput>
This function will only ever return one record. You can search and figure out how to dynamically adjust the search criteria in order to return multiple records.
You might check out http://www.learncfinaweek.com/ to get learn more of the basics of ColdFusion.

Using column names from dynamically named variables in Coldfusion [duplicate]

This question already has answers here:
Coldfusion - variable field name when looping through database query results
(2 answers)
Closed 7 years ago.
I want to create a function that will loop through an arbitrary query and perform an insert into another table based on the arbitrary column names.
For instance, the idea here would be to output
(data, data, data...)
(data, data, data...)
Ultimately, I'm going to do an insert query. For now, I just want to output the rows.
EDIT: I can't just do an INSERT/SELECT because the prod data and dev data are on different servers. So I have to first collect the data from the table on the prod server into a CF query object, and then loop through it and insert into the table on the dev server.
Code:
<cffunction name="copyProdToDev">
<cfargument name="devDatasource" >
<cfargument name="prodDataSource" type="string">
<cfargument name="devTableName" type="string">
<cfargument name="prodTableName" type="string">
<cfargument name="dateColumnName" default="none">
<cfquery name="ProdData" datasource="#prodDatasource#" timeout="60">
SELECT *
FROM #prodTableName#
</cfquery>
<cfset columnNames = ProdData.getColumnNames()>
<cfset numColumns = ArrayLen(columnNames)>
<cfloop query="#ProdData#">
(
<cfloop index="colNumber" from="1" to="#ArrayLen(columnNames)-1#">
<cfoutput><dynamic column name for colNumber>,</cfoutput>
</cfloop>
<cfoutput><dynamic column name for numColumns></cfoutput>
)<br />
</cfloop>
</cffunction>
Array notation is your friend.
<cfoutput>
<cfloop query = "ProdData">
<cfloop array = "#ProdData.getColumnList()#" index = columnName>
#prodData[columnName][currentrow]#
closing tags and formatting stuff
You could get the list from this variable
ProdData.columnList
But be aware that the order of the columns is not totally respected,
this article might help: http://www.bennadel.com/blog/644-query-columnlist-does-not-return-true-column-ordering.htm

How to join two queries from different databases without qoq?

I have two different queries
<cfquery datasource="#one#" name="GetResults">
SELECT ID, Account, Value
FROM Logger_Events
left join Event_Details
on ID = EventID
where type = '123'
</cfquery>
<cfquery datasource="#two#" name="getSubtotal">
select account from daily
</cfquery>
The first query gives me like 200 records , the second query gives me like
half a million records.
Is there a way i can make the second query get the records from the first query,
without making a query of queries?
I would be using the account column to join.
The tables are in different servers.
This is one of the reasons for a QoQ. You could run the 1st query, then convert the data to XML and pass it as a parameter to a stored proc on the 2nd DB server in order to filter the 2nd query directly on the DB. Just join to the XML or use the XML to populate a temp table.
Since you are using sql server, I suggest linked servers. Pick one of your servers and set up a linked server to the other one. Then set up a stored procedure that does something like this;
declare #TempTable table (field1 datatype1, etc);
insert into #TempTable (field1, field2, etc)
select field1, field2, etc
from openquery
(linkedServerName,
'select field1, field2 etc
from blah blah blah
')
select yourfields
from #TempTable join aTableInThatDB on etc
The details are kind of painful at first, but it works very well. Also, there is lot's of information regarding linked servers and openquery on the internet.
I have done this function to Replace the foreign key of a table for a text field contained in the foreign table. This could instead append new columns to the original query with QueryAddColumn() and QuerySetCell().
The idea is to convert one of the queries into a struct.
My function is pretty basic but at the moment looks something like this:
<cffunction name="joinNameFromIDStructs" returnType="query" hint="Returns the Fund Activity">
<cfargument name="qryMain" type="query" required="Yes" hint='The query which is going to be translated' >
<cfargument name="foreignTable" type="string" required="Yes" hint='table which contains the details of our foreign column' >
<cfargument name="foreignPK" type="string" required="No" default="#arguments.foreignTable#ID" hint="Primary Key in the foreign table" >
<cfargument name="foreignKey" type="string" required="Yes" hint="column in the main table which references another table" >
<cfargument name="foreignText" type="string" required="Yes" hint="the column in the foreing table which hold the required details. It will override the foreign key column in the main table" >
<cfset var idPK = "">
<cfset var qryForeignTable = "">
<cfset var stForeignTable = StructNew()>
<cfset var listForeignPKs = evaluate("ValueList(arguments.qryMain.#arguments.foreignKey#)")/>
<cfif ListLen(listForeignPKs)>
<cfquery name="qryForeignTable" datasource='#application.siteDataSource#' >
SELECT #arguments.foreignPK#, #arguments.foreignText# FROM #arguments.foreignTable#
WHERE #arguments.foreignPK# IN (<cfqueryparam cfsqltype="cf_sql_integer" value='#arrayToList(listToArray(listForeignPKs))#' list="true" />) <!--- CF8 does not support ListRemoveDuplicates , hence we will use the array conversion to remove empties --->
</cfquery>
<cfloop query='qryForeignTable'>
<cfset stForeignTable[qryForeignTable[arguments.foreignPK][qryForeignTable.currentrow]] = qryForeignTable[arguments.foreignText][qryForeignTable.currentrow]/>
</cfloop>
<cfloop query='arguments.qryMain'>
<cfset idPK = arguments.qryMain[arguments.foreignKey]/>
<cfif idPK neq "">
<cfset arguments.qryMain[arguments.foreignKey][arguments.qryMain.currentrow] = stForeignTable[idPK]/>
</cfif>
</cfloop>
</cfif>
<cfreturn arguments.qryMain/>
</cffunction>

Coldfusion OutOfMemoryError (CF9/Wheels)

I have a function which loops over a query and updates a database row for each item. After about 7000 iterations it's throwing an out of memory error - Java heap space.
Is there anything obviously wrong with this code ?
<cfloop query=loc.fixItems>
<cfset loc.count = loc.count + 1>
<cfset var categoryName = loc.fixItems.categoryName>
<cfinvoke component="Item" method="updateCode"
itemId="#loc.fixItems.itemId#" code="#loc.fixItems.newCode#"/>
<!--- Increment counter for category --->
<cfif structKeyExists(categoryMap, categoryName)>
<cfset var inc = structFind(categoryMap, categoryName) + 1>
<cfset structUpdate(categoryMap, categoryName, inc)>
<cfelse>
<cfset structInsert(categoryMap, categoryName, 1)>
</cfif>
</cfloop>
and in the update component:
<cffunction name="updateCode">
<cfargument name="itemId" type="numeric" required="yes">
<cfargument name="code" type="string" required="yes">
<cfset var loc = {}>
<cfquery name="loc.update">
update items
set code = <cfqueryparam value="#code#">
where id = <cfqueryparam value="#itemId#">
</cfquery>
</cffunction>
Don't use cfinvoke to create your Item component every iteration of your fixItems query. Create it once before that using createObject and simply call the updateCode method each time directly on the object.
The following can be done:
Change your <cfqueryparam> to use the appropriate cf_sql type. Are code and id really strings?
Don't give your <cfquery> a name. You are not keeping the result anyway. var loc doesn't help either
Bump up you memory to the JVM Addtional approach Use Java 7 and G1GC
Every 100 to 1000 iterations do a forced Garbage Collect
Update your data in bulk. XML based table variables can do this.
Make your function silent
Consider ORM on this

Can I get a query row by index in ColdFusion?

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) />