I have an array "varray" which needs to be split into four structures. The first of each four elements should be in structure 1, the second in structure 2, etc. I have some working code to do this, but it feels to me like there should be a less cumbersome way. Here is the code:
<cfset xord = StructNew()>
<cfset xsort = StructNew()>
<cfset xsel = StructNew()>
<cfset xmer = StructNew()>
<cfloop from = '1' to = "#ArrayLen(varray)#" index = 'i'>
<cfset fieldname = farray[i]> <!---farray previously defined --->
<cfset val = varray[i]> <!---varray previously defined --->
<cfset j = i%4>
<cfif j EQ 1>
<cfset xord[fieldname] = val>
<cfselseif j EQ 2>
<cfset xsort[fieldname]= val>
<cfelseif j EQ 3>
<cfset xsel[fieldname] = val>
<cfelseif j EQ 0>
<cfset xmer[fieldname] = val>
</cfif>
</cfloop>
Can anyone suggest a better way to do this?
It's been ages i did some CF, but a tag based approach by making use of local scope:
<cfset keys = ['xord', 'xsort', 'xsel', 'xmer'] />
<cfset farray = ['f1','f2','f3','f4','f5','f6','f7','f8']>
<cfset varray = ['v1','v2','v3','v4','v5','v6','v7','v8']>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset local[keys[i%4+1]][farray[i]] = varray[i]>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
Now you have xord, xsort, xsel and xmer filled with the right key-value pairs within your local scope.
How about cfscript?
<cfscript>
function groupByOp(values, fieldnames) {
var ops = ['mer', 'ord', 'sort', 'sel'];
var byOp = {};
arrayEach(values, function (val, i) {
byOp["x#ops[i % 4 + 1]#"][fieldnames[i]] = val;
});
return byOp;
}
</cfscript>
This makes use of the fact that CF will automagically create structs when you mention a non-existing member.
Test:
<cfset v = ListToArray('1,2,3,4,5,6')>
<cfset f = ListToArray('a,b,c,d,e,f')>
<cfoutput>
<pre>#SerializeJSON(groupByOp(v, f))#</pre>
</cfoutput>
outputs
{
"xsel": {
"c": "3"
},
"xord": {
"e": "5",
"a": "1"
},
"xsort": {
"b": "2",
"f": "6"
},
"xmer": {
"d": "4"
}
}
(You didn't mention your version, so I don't know if you have access to newer functions like array each(). Keep in mind there's slicker options in newer versions)
Instead of creating separate variables, create a single structure containing the 4 variables, and an array of names. Then use the array and MOD to populate the substructures. Note, the example below creates the subsubstructures up front to ensure they always exist - even if the field/value arrays are empty or contain less than 4 elements.
TryCF.com Example
<cfset farray = ["A","B","C","D","E","F","G","Q","T"]>
<cfset varray = ["11","22","33","RR","55","NN","77","68","46"]>
<cfset data = {xOrd={},xSort={},xSel={},xMer={}}>
<cfset names = ["xOrd","xSort","xSel","xMer"]>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset fieldName = farray[i]>
<cfset fieldValue = varray[i]>
<cfset structName = names[i%4+1]>
<cfset data[structName][fieldName] = fieldValue>
</cfloop>
The substructures can be accessed through the parent, data.
<cfdump var="#data.xOrd#" label="data.xOrd">
<cfdump var="#data.xSort#" label="data.xSort">
<cfdump var="#data.xSel#" label="data.xSel">
<cfdump var="#data.xMer#" label="data.xMer">
Another couple of approaches.
I wouldn't necessarily say that these are better, but just different:
Requires field array length to match value array length
<cfset farray = ['field1','field2','field3','field4','field5']>
<cfset varray = ['apple','orange','pear','kiwi','pineapple']>
<cfset xord = {}>
<cfset xsort = {}>
<cfset xsel = {}>
<cfset xmer = {}>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset j =
((i%4 EQ 1) ? (StructInsert(xord,farray[i],varray[i])):
((i%4 EQ 2) ? (StructInsert(xsort,farray[i],varray[i])):
((i%4 EQ 3) ? (StructInsert(xsel,farray[i],varray[i])):
((i%4 EQ 0) ? (StructInsert(xmer,farray[i],varray[i])): 0))))>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
OR:
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfswitch expression="#i%4#">
<cfcase value="0">
<cfset xmer[farray[i]] = varray[i]>
</cfcase>
<cfcase value="1">
<cfset xord[farray[i]] = varray[i]>
</cfcase>
<cfcase value="2">
<cfset xsort[farray[i]] = varray[i]>
</cfcase>
<cfcase value="3">
<cfset xsel[farray[i]] = varray[i]>
</cfcase>
</cfswitch>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
Field array length does not have to match value array length
<cfset farray = ['field1','field2','field3','field4']>
<cfset varray = ['apple','orange','pear','kiwi','pineapple']>
<cfset xord = {}>
<cfset xsort = {}>
<cfset xsel = {}>
<cfset xmer = {}>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset j =
((i%4 EQ 1 AND ArrayIsDefined(farray,i)) ? (StructInsert(xord,farray[i],varray[i],true)) :
((i%4 EQ 2 AND ArrayIsDefined(farray,i)) ? (StructInsert(xsort,farray[i],varray[i],true)) :
((i%4 EQ 3 AND ArrayIsDefined(farray,i)) ? (StructInsert(xsel,farray[i],varray[i],true)) :
((i%4 EQ 0 AND ArrayIsDefined(farray,i)) ? (StructInsert(xmer,farray[i],varray[i],true)) : 0))))>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
OR:
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfswitch expression="#i%4#">
<cfcase value="0">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xmer,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="1">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xord,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="2">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xsort,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="3">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xsel,farray[i],varray[i],true)) : 0)>
</cfcase>
</cfswitch>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
Related
I have this function to generate slugs in Coldfusion:
<cffunction name="generateSlug" output="false" returnType="string">
<cfargument name="str">
<cfargument name="spacer" default="-">
<cfset var ret = "" />
<cfset str = lCase(trim(str)) />
<cfset str = reReplace(str, "[àáâãäå]", "a", "all") />
<cfset str = reReplace(str, "[èéêë]", "e", "all") />
<cfset str = reReplace(str, "[ìíîï]", "i", "all") />
<cfset str = reReplace(str, "[òóôö]", "o", "all") />
<cfset str = reReplace(str, "[ùúûü]", "u", "all") />
<cfset str = reReplace(str, "[ñ]", "n", "all") />
<cfset str = reReplace(str, "[^a-z0-9-]", "#spacer#", "all") />
<cfset ret = reReplace(str, "#spacer#+", "#spacer#", "all") />
<cfif left(ret, 1) eq "#spacer#">
<cfset ret = right(ret, len(ret)-1) />
</cfif>
<cfif right(ret, 1) eq "#spacer#">
<cfset ret = left(ret, len(ret)-1) />
</cfif>
<cfreturn ret />
</cffunction>
and then i am calling it using this:
<cfset stringToBeSlugged = "This is a string abcde àáâãäå èéêë ìíîï òóôö ùúûü ñ año ñññññññññññññ" />
<cfset slug = generateSlug(stringToBeSlugged) />
<cfoutput>#slug#</cfoutput>
But this is output me this slug:
this-is-a-string-abcde-a-a-a-a-a-a-e-e-e-e-i-i-i-i-o-o-o-o-u-u-u-u-n-a-no-n-n-n-n-n-n-n-n-n-n-n-n-n
it seems that all the accented characters are correctly replaced but this function is inserting a '-' after replacing them. Why?
Where is the error?
PD: i am expecting this output:
this-is-a-string-abcde-aaaaaa-eeee-iiii-oooo-uuuu-n-ano-nnnnnnnnnnnnn
Thanks.
Does this work for you? (I've adapted a similar script that we use internally.) I believe that we used this with ColdFusion 8 as we are still use it w/CF9.
<cffunction name="generateSlug" output="false" returnType="string">
<cfargument name="str" default="">
<cfargument name="spacer" default="-">
<cfset var ret = replace(arguments.str,"'", "", "all")>
<cfset ret = trim(ReReplaceNoCase(ret, "<[^>]*>", "", "ALL"))>
<cfset ret = ReplaceList(ret, "À,Á,Â,Ã,Ä,Å,Æ,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,Ø,Ù,Ú,Û,Ü,Ý,à,á,â,ã,ä,å,æ,è,é,ê,ë,ì,í,î,ï,ñ,ò,ó,ô,õ,ö,ø,ù,ú,û,ü,ý, ,&", "A,A,A,A,A,A,AE,E,E,E,E,I,I,I,I,D,N,O,O,O,O,O,0,U,U,U,U,Y,a,a,a,a,a,a,ae,e,e,e,e,i,i,i,i,n,o,o,o,o,o,0,u,u,u,u,y, , ")>
<cfset ret = trim(rereplace(ret, "[[:punct:]]"," ","all"))>
<cfset ret = rereplace(ret, "[[:space:]]+","!","all")>
<cfset ret = ReReplace(ret, "[^a-zA-Z0-9!]", "", "ALL")>
<cfset ret = trim(rereplace(ret, "!+", arguments.Spacer, "all"))>
<cfreturn ret>
</cffunction>
<cfset stringToBeSlugged = "This is a string abcde àáâãäå èéêë ìíîï òóôö ùúûü ñ año ñññññññññññññ" />
<cfoutput>"#stringToBeSlugged# = #generateSlug(stringToBeSlugged)#</cfoutput>
Support for more International Character
If you want to widen your support for international characters, you could use ICU4J (java) and Paul Hastings' Transliterator.CFC to transliterate all of the characters and then replace any remaining spaces, dashes, slashes, etc with dashes.
https://gist.github.com/JamoCA/ec4617b066fc4bb601f620bc93bacb57
http://site.icu-project.org/download
After installing both, you can convert non-Latin characters by identifying the language id (to be converted to) and pass the string to be converted:
<cfset Transliterator = CreateObject("component","transliterator")>
<cfoutput>
<cfloop array="#TestStrings#" index="TestString">
<h3>TestString = "#TestString#"</h3>
<blockquote>
<div>CFC-1 = #Transliterator.transliterate('Latin-ASCII', TestString)#</div>
<div>CFC-2 = #Transliterator.transliterate('any-NFD; [:nonspacing mark:] any-remove; any-NFC', TestString)#</div>
</blockquote>
<hr>
</cfloop>
</cfoutput>
<h2>Available Language IDs</h2>
<cfdump var="#Transliterator.getAvailableIDs()#" label="Language IDs">
I have a txt file and would like to order all the rows according to a value in each row.
What is the best and fastest possible way to achieve this?
Below is the code that I use to compile my txt documents:
<!---CSV FILE--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/debitorders.csv" variable="csvfile">
<cfoutput>
<!---LOOP THROUGH CSV FILE--->
<cfloop index="index" list="#csvfile#" delimiters="#chr(10)##chr(13)#">
<!---SET VALUES--->
<cfset accountholder = "#listgetAt('#index#',1)# #listgetAt('#index#',2)#">
<cfset accountholderlname = "#listgetAt('#index#',2)#">
<cfset accountnumber = "#listgetAt('#index#',3)#">
<cfset accounttype = "#listgetAt('#index#',4)#">
<cfset bankname = "#listgetAt('#index#',5)#">
<cfset branch = "#listgetAt('#index#',6)#">
<cfset amount = "#listgetAt('#index#',7)#">
<cfset date = "#listgetAt('#index#',8)#">
<!---SET INITIAL--->
<cfset initial = "#left(accountholder,1)#">
<!---SET LAST NAME--->
<cfset lname_final = "#replace("#accountholderlname#"," ","","all")#">
<!---GET AND SET ACC TYPE--->
<cfif accounttype eq "cheque">
<cfset accounttype_final = "CH">
<cfelseif accounttype eq "savings">
<cfset accounttype_final = "SAV">
<cfelseif accounttype eq "credit">
<cfset accounttype_final = "CR">
<cfelse>
<cfset accounttype_final = "OTH">
</cfif>
<!---SET AMOUNT--->
<cfset amount_final = #round(amount * 100)#>
<cfset amount_final = #NumberFormat(amount_final,"0000000")#>
<!---SET DATE--->
<cfset date_final = "#DateFormat(Date,"ddyyyymm")#">
<!---TRIM VALUES--->
<cfset initial = "#Left(initial, 1)#">
<cfset lname_final = "#Left(lname_final, 14)#">
<cfset accountnumber = "#Left(accountnumber, 13)#">
<cfset accounttype_final = "#Left(accounttype_final, 3)#">
<cfset branch = "#Left(branch, 9)#">
<cfset amount_final = "#Left(amount_final, 7)#">
<cfset date_final = "#Left(date_final, 8)#">
<!---SET STRING LENGTH FOR EACH--->
<cfset initial = "#LJustify(initial, 1)#">
<cfset lname_final = "#LJustify(lname_final, 15)#">
<cfset accountnumber = "#LJustify(accountnumber, 14)#">
<cfset accounttype_final = "#LJustify(accounttype_final, 3)#">
<cfset branch = "#LJustify(branch, 10)#">
<cfset amount_final = "#LJustify(amount_final, 7)#">
<cfset date_final = "#LJustify(date_final, 8)#">
<!---SET TOTAL STRING--->
<cfset total_string = "#initial##lname_final##accountnumber##accounttype_final##branch##amount_final##date_final#">
<pre>
#accountholder#<br>
#accountnumber#<br>
#accounttype#<br>
#bankname#<br>
#branch#<br>
#amount#<br>
#date#<br>
#initial#<br>
#lname_final#<br />
#accounttype_final#<br>
#amount_final#<br />
#date_final#<br>
123456789012345678901234567890123456789012345678901234567890<br />
#total_string#<br>
<br />
<br />
</pre>
<!---IF FILE FOR BANK EXISTS--->
<cfif FileExists(ExpandPath("#listgetAt('#index#',5)#.txt"))>
<!---READ EXISTING FILE HEADER--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/#bankname#.txt" variable="bankheader">
<!---SPLIT UP THE HEADER TO ADD NEW VALUES ONTO IT--->
<cfset numericvalue = listfirst(bankheader,chr(13))>
<cfset numericvalue = #Right(numericvalue, 13)#>
<cfset RecordCountvalue = #Left(numericvalue, 3)#>
<cfset RecordCountvalue = #RecordCountvalue# + 1>
<cfset RecordCountvalue = #NumberFormat(RecordCountvalue,"000")#>
<cfset RecordCountvalue = #Left(RecordCountvalue, 3)#>
<cfset RecordCountvalue = #RJustify(RecordCountvalue, 3)#>
<cfset TotalRecordvalue = #Right(numericvalue, 10)#>
<cfset TotalRecordvalue = (#TotalRecordvalue# + #amount#) * 100000>
<cfset TotalRecordvalue = #NumberFormat(TotalRecordvalue,"0000000000")#>
<cfset TotalRecordvalue = #Left(TotalRecordvalue, 10)#>
<cfset TotalRecordvalue = #RJustify(TotalRecordvalue, 10)#>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank##RecordCountvalue##TotalRecordvalue#">
<pre>
#numericvalue#<br />
#RecordCountvalue#<br />
#TotalRecordvalue#<br />
#newfile_header#
</pre>
<!---APPEND FILE AND ADD UPDATED HEADER--->
<cfset bankheader = listSetAt(bankheader,1,"#newfile_header#","#chr(13)#")>
<cffile action="write"
fixnewline="no"
addnewline="no"
file="#getDirectoryFromPath(getTemplatePath())#/#listgetAt('#index#',5)#.txt"
output="#bankheader#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
<!---IF FILE FOR BANK DOES NOT EXIST--->
<cfelse>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank#001000#amount_final#">
<!---CREATE NEW FILE WITH BANK NAME--->
<cffile action = "write"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#newfile_header#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
</cfif>
</cfloop>
</cfoutput>
I am not sure if it would be better if I start using an Array to do this, if so please advise.
I am not sure if it is possible to check as I insert each row to insert it into the correct place, I have never heard of this before.
I could also loop through the txt files at the end of the process if need be.
Read the csv file using cfhttp. The name attribute creates a query object. You can use Q of Q to do your sort and then carry on.
The details are in the documentation for cfhttp.
Given the following list (#oldList#):
category1_item1, category1_item2, category2_item1, category3_item1, category3_item2"
How can I create the following list (#newList#)?:
category1[item1&item2],category2[item1],category3[item1&item2]?
This is what I have so far:
<cfset newList = "">
<cfset category = "">
<cfloop list="#oldList#" index="listElement">
<cfset endPos = find("_", listElement)>
<cfset listElementCategory = left(listElement, endPos)>
<cfset listElementItem = replace(listElement, listElementCategory, "")>
<cfif listElementCategory is not category>
<cfset modifiedElement = replace(listElementCategory, "_", "") & "[" & listElementItem>
<cfelse>
<cfset modifiedElement = "&" & listElementItem>
</cfif>
<cfset category = listElementCategory>
<cfset newList = newList & modifiedElement>
</cfloop>
This code results in:
category1[item1&item2category2[item1category3[item1&item2
I just can't figure out how to close each "grouping" of items with "],".
<cfset newList = "">
<cfset category = "">
<cfloop list="#oldList#" index="listElement">
<cfset endPos = find("_", listElement)>
<cfset listElementCategory = left(listElement, endPos)>
<cfset listElementItem = replace(listElement, listElementCategory, "")>
<cfif listElementCategory is not category>
<cfif category is not "">
<!--- category has changed and this isn't the first record, so close previous category --->
<cfset newList = newList & "],">
</cfif>
<cfset modifiedElement = replace(listElementCategory, "_", "") & "[" & listElementItem>
<cfelse>
<cfset modifiedElement = "&" & listElementItem>
</cfif>
<cfset category = listElementCategory>
<cfset newList = newList & modifiedElement>
</cfloop>
Note I just added this block:
<cfif category is not "">
<!--- category has changed and this isn't the first record, so close previous category --->
<cfset newList = newList & "],">
</cfif>
Edit:
Almost forgot the end of the loop! After the </cfloop> close the brackets like:
<cfif category is not "">
<!--- close the final bracket since we have at least one record --->
<cfset newList = newList & "]">
</cfif>
I'm running the following two statements:
First is A) which does what it needs to do and works:
SELECT
itemColumn
,valueColumn
,label
FROM
rstCombinedChartData
UNION ALL
SELECT
itemColumn
,CAST(valueColumn AS INTEGER) AS valueColumn
,label
FROM
rstChartData
This gives me the following results:
Next I need to take these results and get back total of itemcolumn for each value in this case yes and no i.e.
i.e.
Yes 200
No 400
B) This is the query I have for to achieve this:
SELECT
itemColumn
,SUM(valueColumn) AS valueColumn
,label
FROM
rstCombinedChartData (this is above result set)
GROUP BY
label
,itemColumn
ORDER BY
label DESC
,itemColumn DESC
However, I get the following result which is not correct:
Whats going on here with query B it should be yes = x and no = x, instead I'm getting false and all the totals?
CF function:
<cffunction name="getAverageChartData" hint="I return the data required to render an average chart." returntype="array" output="false">
<cfargument name="surveyList" hint="I am a record set of Surveys." required="true" type="query" />
<cfargument name="filter" hint="I am the optional filter which is to be applied to all results." required="false" default="" type="string" />
<cfset var local=structNew() />
<cfset var rstChartData="" />
<cfset var rstChartDataTotal="" />
<cfset var rstCombinedChartData=queryNew("itemColumn,valueColumn,label","varchar,integer,varchar") />
<cfset local.objQuestion=objQuestionService.get(arguments.surveyList.question_ID[1]) />
<cfset local.intQuestionTypeID = local.objQuestion.getTypeID() />
<cfset local.strSubQuestionList=local.objQuestion.getAnswer() />
<cfset local.strPossibleAnswerList=local.objQuestion.getPossibleAnswer() />
<cfset local.arrChartDataResult=arrayNew(1) />
<!--- loop over each school's survey --->
<cfloop query="arguments.surveyList">
<cfset local.arrChartData = getChartData(arguments.surveyList.survey_id, arguments.surveyList.question_id, arguments.filter) />
<!--- loop over each sub question and append (union) it to a running total --->
<cfloop array="#local.arrChartData#" index="rstChartData">
<cfquery name="rstCombinedChartData" dbtype="query">
SELECT
itemColumn
,valueColumn
,label
FROM
rstCombinedChartData
UNION ALL
SELECT
itemColumn
,CAST(valueColumn AS INTEGER) AS valueColumn
,label
FROM
rstChartData
</cfquery>
</cfloop>
</cfloop>
<!--- get the totals for each itemColumn --->
<cfquery name="rstChartDataTotal" dbtype="query">
SELECT
itemColumn
,SUM(valueColumn) AS valueColumn
,label
FROM
rstCombinedChartData
GROUP BY
label
,itemColumn
ORDER BY
label DESC
,itemColumn DESC
</cfquery>
OK - Major UPDATE
I have no idea why but I added this line in by mistake:
<cfset querySetCell(rstCombinedChartData, "itemColumn", "1") />
All of a sudden the query started to work in Railo! Ok now I have one extra result that makes no sense "1" but WTF! It seems that Railo does not like all yes, no answers I put something else into the mix and it starts to tread it correctly again as varchars like it should.
anyone know whats going on here? I have tired casting in sql as varchar but this does not work only at the CF level does something happen.
If i take out the line:
<cfset querySetCell(rstCombinedChartData, "itemColumn", "1") />
it goes back to:
From the comments - I am curious why you had to CAST the valueColumn as an integer in the line CAST(valueColumn AS INTEGER) AS valueColumn when it is already an integer?
You should try casting your itemColumn as a char in the same SQL statement. Note: in MySQL you cannot cast to VARCHAR. In MySQL you must use CHAR. Something like CAST(itemColumn AS CHAR) AS itemColumn.
The rest of this is not really an answer but was too long for a comment
I created a self-contained repro based on the data that you shared but I cannot get it to fail. Your query works correctly for me in ACF and Railo. Copy the code below and paste it into cflive.net.
<cftry>
<cfset rstCombinedChartData = QueryNew("itemColumn,valueColumn,label","varchar,integer,varchar") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 33) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 45) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 72) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 66) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 42) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 38) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 64) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 83) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 65) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 43) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "Yes") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfset temp = QueryAddRow(rstCombinedChartData) />
<cfset temp = QuerySetCell(rstCombinedChartData, "itemColumn", "No") />
<cfset temp = QuerySetCell(rstCombinedChartData, "valueColumn", 0) />
<cfset temp = QuerySetCell(rstCombinedChartData, "label", "") />
<cfquery name="rstChartDataTotal" dbtype="query">
SELECT
itemColumn
,SUM(valueColumn) AS valueColumn
,label
FROM
rstCombinedChartData
GROUP BY
label
,itemColumn
ORDER BY
label DESC
,itemColumn DESC
</cfquery>
<html>
<head><title>Test</title></head>
<body>
<h3>Test</h3>
<div>
<cfoutput query="rstChartDataTotal">
<p>#rstChartDataTotal.itemColumn# - #rstChartDataTotal.valueColumn#</p>
</cfoutput>
<cfdump var="#rstCombinedChartData#" label="rstCombinedChartData" />
<hr />
<cfdump var="#rstChartDataTotal#" label="rstChartDataTotal" />
</div>
</body>
</html>
<cfcatch type="any">
<cfdump var="#cfcatch#" />
</cfcatch>
</cftry>
You can see in the cfdump results of rstChartDataTotal that Railo maintains the itemColumn as a varchar and still displays "yes" or "no".
In Adobe ColdFusion it changes the itemColumn to a boolean and displays as "true" or "false".
I believe that anomaly is only coming from the output generated at cflive.net, but in both cases the query still ran and correctly calculated the results of both columns?
This may be a scoping/ reference issue;
Change:
<cfquery name="rstCombinedChartData" dbtype="query">
Into
<cfquery name="local.q" dbtype="query">
Then after the QoQ, at the end of the local.arrChartData loop, set it back to the rstCombinedChartData variable;
<cfloop array="#local.arrChartData#" index="rstChartData">
<cfquery name="local.q" dbtype="query">
SELECT
itemColumn
,valueColumn
,label
FROM
rstCombinedChartData
UNION ALL
SELECT
itemColumn
,CAST(valueColumn AS INTEGER) AS valueColumn
,label
FROM
rstChartData
</cfquery>
<cfset rstCombinedChartData = local.q />
</cfloop>
</cfloop>
This should make sure all pointers/ references are set correctly.
Try this query -
SELECT UNIQUE itemColumn
, SUM( SELECT valueColumn
FROM rstCombinedChartData
WHERE itemColumn = "yes") as YES
, SUM ( SELECT valueColumn
FROM rstCombinedChartData
WHERE itemColumn = "no") as NO
, label;
My JSON contains special characters like: new line, double quotes etc.
I am creating the JSON using Coldfusion server side script. But in case of special chars I get error due to wrongly formatted JSON. What should I do in such a case?
<cfoutput>
[
<cfset loopIndex=0>
<cfloop query="qEvents">
<cfif loopIndex NEQ 0>,</cfif>
<cfif is_allday EQ 1>
<cfset isallDayEvent = "true">
<cfelse>
<cfset isallDayEvent = "false">
</cfif>
{
"title": "#title#",
"start": "#DateFormat(start_date_time,'mm/dd/yyyy')# #TimeFormat(start_date_time,'hh:mm tt')#",
"end": "#DateFormat(end_date_time,'mm/dd/yyyy')# #TimeFormat(end_date_time,'hh:mm tt')#",
"allDay": #isallDayEvent#,
"eventID": "#event_id#",
"duration": "#duration#",
"note": "#note#",
"location": "#location#"
}
<cfset loopIndex=loopIndex+1>
</cfloop>
]
</cfoutput>
Rather than writing the JSON by hand, you should generate an array of structs and then use serializeJSON() to convert it to a valid JSON string:
<cfset thisArrayBecomesJSON = [] />
<cfloop query="qEvents">
<cfif is_allday EQ 1>
<cfset isAllDayEvent = "true" />
<cfelse>
<cfset isAllDayEvent = "false" />
</cfif>
<cfset thisEvent = {
'title' = title,
'start' = dateFormat( start_date_time, 'mm/dd/yyyy' ) & timeFormat( start_date_time, 'hh:mm tt' ),
'end' = dateFormat( end_date_time, 'mm/dd/yyyy' ) & timeFormat( end_date_time, 'hh:mm tt' ),
'allDay' = isAllDayEvent,
'eventID' = event_id,
'duration' = duration,
'note' = note,
'location' = location
} />
<cfset arrayAppend( thisArrayBecomesJSON, thisEvent ) />
</cfloop>
<cfset myJSON = serializeJSON( thisArrayBecomesJSON ) />
<cfoutput>#myJSON#</cfoutput>
This is untested, but I think it should work ok - there may be some syntax errors.