Splitting an address string into separate variables - Coldfusion - coldfusion

I've been struggle with splitting an address field in my database into it's separate components.
I am pulling address data from my database that is stored in column #company_address# . The data looks like this when I output it:
Address1
Address2 (Not always present)
City, State Zip (Sometimes there is a comma, sometimes there is not)
I would like to break up the string in #company_address# and assign each part of the address to it's own variable:
variable1 - address1
variable2 - address2
variable3 - city
variable4 - state
variable5 - zip
Once I have that data, I will enter it back into the db in its seperated form.
I have tried using the listtoarray function but it assigns the whole string to one array element and seems to skip the address2 line entirely.
Here is the code I am using:
<!--- Select ticket record --->
<cfquery name="get_ticket" datasource="#datasource#">
SELECT *
FROM closed_tickets
where ticket_id = #url.ticket_id#
</cfquery>
<cfoutput>
<cfset list = "#get_ticket.company_address#">
<cfset arr = listToArray (list, 'ch(13)' ,false,true)>
<cfdump var="#arr#">
</cfoutput>
Can anyone help??

The problem is that you are using chr(13) as a string. Use the following.
<cfset arr = listToArray (list, chr(13) , false, true)>

Related

How to build structure with different set of column names?

I have two different set of columns in my cfquery. One set of columns is reserved for the values and second is reserved for title in the form input fields. I'm building structure on the server side and I would like these two in separate columns. Here is example:
<cfquery name="UInfo" datasource="Test">
SELECT TOP 1
u_fname,
u_lname,
zu_fname,
zu_lname
FROM Users WITH (NOLOCK)
WHERE u_urid = '0012341'
</cfquery>
<cfloop query="UInfo">
<cfset qryRecs = StructNew()>
<cfloop array="#UInfo.getColumnNames()#" index="columnName">
<cfset qryRecs[columnName]['value'] = UInfo[columnName][CurrentRow]>
<cfset qryRecs[columnName]['title'] = (structKeyExists(UInfo, "z"&columnName)? UInfo[columnName][CurrentRow] : "")>
</cfloop>
</cfloop>
My code above will produce this kind of output:
U_FNAME
struct
title First Time
value Mark
U_FLAST
struct
title New Customer
value Miller
ZU_FNAME
struct
title First Time
value [empty string]
ZU_LNAME
struct
title New Customer
value [empty string]
As you can see above my code produced structure for Z columns as well. I don't need separate structure for these columns they should show in TITLE only. My output should be something like this:
U_FNAME
struct
title First Time
value Mark
U_FLAST
struct
title New Customer
value Miller
I'm not sure how to get desired output. If anyone can help please elt me know. Thank you!
Appears you simply need an if statement on the columnName inside the column names loop
<cfif left(columnName, 1) eq "u">
You have this:
<cfset qryRecs = StructNew()>
inside a loop. It should be before this:
<cfloop query="UInfo">

Using dynamic variables in query

I have a page that has an variable number of input fields (this number of fields is saved in the database). Upon submit, the information in these fields is to be saved into a database. The names of the fields are looped through and the current loop number is attached to the end of the field. I then save this into a variable and use the variable in the query. It's getting the correct information from the variable, but isn't actually evaluating the form fields. For instance, the values put into the form fields are:
"#FORM.TEST_LOCATION_1#=two"<br>
"#FORM.TEST_LOCATION_2#=four"<br>
"#FORM.TEST_LOCATION_3#=six"<br>
"#FORM.TEST_LOCATION_4#=eight"<br>
"#FORM.TEST_LOCATION_5#=ten"<br>
"#FORM.TEST_NAME_1#=one"<br>
"#FORM.TEST_NAME_2#=three"<br>
"#FORM.TEST_NAME_3#=five"<br>
"#FORM.TEST_NAME_4#=seven"<br>
"#FORM.TEST_NAME_5#=nine"<br>
The variable that is used in the query gets:
test_location_1 = '#form.test_location_1#', test_name_1 = '#form.test_name_1#', test_location_2 = '#form.test_location_2#', test_name_2 = '#form.test_name_2#', test_location_3 = '#form.test_location_3#', test_name_3 = '#form.test_name_3#', test_location_4 = '#form.test_location_4#', test_name_4 = '#form.test_name_4#', test_location_5 = '#form.test_location_5#', test_name_5 = '#form.test_name_5#',
but instead of putting the values actually entered in the input field in to database, it puts:
"#form.test_location_1#"
"#form.test_location_2#"
"#form.test_location_3#"
"#form.test_name_1#"
"#form.test_name_2#"
"#form.test_name_3#"
etc
The code I'm using right now is:
<cfset session.updque = ''>
<cfloop from="1" to="#session.test_numfields#" index="numf">
<cfset session.updque &= "test_location_" & #numf# &" = '##form.test_location_" & #numf# & "##', ">
<cfset session.updque &= "test_name_" & #numf# &" = '##form.test_name_" & #numf# & "##', ">
</cfloop>
<cfquery DATASOURCE="#ODSN#" NAME="uptest" >
UPDATE redbook_test SET
<cfoutput>#PreserveSingleQuotes(updque)#</cfoutput>
test_date_last_mod='#datecompleted#',
test_status='C',
where buildno = '#session.buildno#'
</CFQUERY>
What do I need to do to actually get the form variable saved into the database??
FORM is a structure. To evaluate dynamically named fields, use associative array notation:
<cfset value = FORM["test_location_" & numf]>
Not directly related to your question, but your current query is unsafe. CF automatically escapes single quotes inside query parameters to protect against sql injection. PreserveSingleQuotes disables that protection, putting your database at risk. To avoid that risk, always use cfqueryparam on user supplied values:
UPDATE Table
SET Column = <cfqueryparam value="#form.fieldName#" cfsqltype="...">
WHERE ...
Also, when you have multiple columns with the same name, ie test_location_1, test_location_2, ..., location_n it is usually a good sign you need to normalize your tables. Typically, you want to create a secondary table and store the duplicated information in rows, not columns, with a link back to the main table.
This sort of syntax will get you started.
update redbook_test
set test_date_last_mod <cfqueryparam value="#test_date_last_mod#">
, test_status='C'
<cfloop list="#form.fieldnames#" index="ThisField">
<cfif left(ThisField, 5) is "test_">
, #ThisField# = <cfqueryparam value = "#form[ThisField]#">
</cfif>
</cfloop>
where buildno = <cfqueryparam value='#session.buildno#'>
It's not complete. You have to consider how to handle empty strings, different datatypes, and such.

ArrayMin on query column with a null value

CF8
I was using this line to get the MIN value of a query column. I just noticed a null value in a recordset causes an error. Is there a simply way to tell ArrayMin to skip nulls w/o having to loop the column and load an array with all non-null values?
<cfset temp_data_min = #round(ArrayMin(query_x["some_field"]))#>
thanks!
Building off of what Al said with using the query-of-queries, just adding the Min() call into the query.
<cfquery name="query_x_fixed" dbtype="query">
SELECT Min(some_field) as some_field
FROM query_x
WHERE some_field IS NOT NULL
</cfquery>
<cfset temp_data_min = round(query_x_fixed.some_field)>
Tested to work in CF9
You could loop through your array and create a new array that doesn't contain any null values. Then apply the ArrayMin function to the new array.
<cfset newArray = []>
<cfloop index="x" array="#query_x["some_field"]#">
<cfif x NEQ 'null'>
<cfset arrayAppend(newArray, x)>
</cfif>
</cfloop>
<cfset temp_data_min = round(ArrayMin(newArray))>
NOT TESTED
Simplest way is probably to do a query-of-queries with just that column and remove the nulls.
<cfquery name="query_x_fixed" dbtype="query">
SELECT some_field
FROM query_x
WHERE some_field IS NOT NULL
</cfquery>
<cfset temp_data_min= round(ArrayMin(query_x_fixed["some_field"]))>
(not tested)
You can keep the solution at one line by converting the column to a list then into an array. ListToArray defaults to ignoring empty list items, which is what the null values will be.
<cfset temp_data_min = Round(ArrayMin(ListToArray(ValueList(query_x.some_field, Chr(7)), Chr(7))))>
This should be faster than any of the other proposed solutions and is less code.
I've specified the delimiter for locales that use the comma as the decimal separator in numbers. If you're in the US or another locale that uses the "." then you can remove the delimiter arguments.
Additional functions used:
ListToArray
ValueList
Chr

coldfusion query loop not cooperating

I'm trying to create a function to create csv files from queries. After I run the query, I'm looping through it and appending each row's fields to a StringBuffer object. To that end, I'm putting the column names into an array:
<cfset indexes = #ListToArray(Arguments.header)# />
where the argument is currently a string like:
"col1, col2, col3...."
I've verified that both the query and the array are what they should be by dumping.
The trouble comes when looping through the query results. Given:
<cfset indexes_length = #ArrayLen(indexes)# />
<cfloop query="query_for_csv">
<cfloop index="i" from="1" to="#indexes_length#">
<cfset attr = #indexes[i]# />
<cfset sbOutput.Append(
"#query_for_csv[attr][query_for_csv.CurrentRow]#") />
</cfloop>
</cfloop>
Only the first value of the first row is output before I get the error message:
[Table (rows 10 columns col1, col2, col3):
[col1: coldfusion.sql.QueryColumn#6f731eba]
[col2: coldfusion.sql.QueryColumn#6ee67e7f]
[col3: coldfusion.sql.QueryColumn#5c6647cb]
is not indexable by col2
If I replace the variable #attr# with the literal "col2":
#query_for_csv['col2'][query_for_csv.CurrentRow]#
then the loop sails through with no problem, and spits out all the values indexed by 'col2'. Any ideas?
I would guess it's the spaces in your header list that is the problem, so probably this would work:
<cfset attr = trim(indexes[i]) />
However, since you're not using them, you probably don't need that and can just do this...
<cfloop query="QueryName">
<cfloop index="CurCol" list=#QueryName.ColumnList# >
<cfset sbOutput.Append(
QueryName[CurCol][QueryName.CurrentRow]
)/>
</cfloop>
</cfloop>
p.s.
You'll note here that there's only one pair of hashes - there only needs to be one pair in your original code snippets too (in the to attribute) - the rest are unnecessary noise.
As has already been said before, try to avoid spaces before or after a list element.
In case you want to compare notes, check out the approach Ben Nadel chose to implement such a Query2CSV converter: http://www.bennadel.com/blog/1239-Updated-Converting-A-ColdFusion-Query-To-CSV-Using-QueryToCSV-.htm

cfspreadsheet escape comma in comma separated row insert

The function for adding a row to a coldfusion spreadsheet is SpreadsheetAddrow which accepts data as "A comma delimited list of cell entries, one per column."
Some of my data has commas within it. How do I escape the commas within my data without escaping the commas in the list?
I am currently creating an array with the contents of the row, then converting it to a list to add to the spreadsheet:
<cfset row = ArrayNew(1)>
<cfloop list="#structKeyList(setRecord.columns)#" index="key">
<cfset ArrayAppend(row, "#Evaluate(key)#")>
</cfloop>
<cfset spreadsheetAddRow(xlsObj, "#ArrayToList(row)#")>
Looks like the ability to specify a different delimiter is not supported yet. Since you are already looping, you may as well skip the array and use SpreadsheetSetCellValue instead. You should be able to eliminate the evaluate() as well.
<cfset cols = structKeyArray(yourStruct) >
<cfloop from="1" to="#arrayLen(cols)#" index="c">
<cfset SpreadsheetSetCellValue(xlsObj, yourStruct[ cols[c] ], lastRow, c)>
</cfloop>
<cfset lastRow++>
...
Update: However, if the base object is a query, not a structure, then it is more efficient to use CfSimplicity's suggestion of SpreadSheetAddRows.
If the data you want to add to the sheet is in a query object (recordset) then the simplest solution is to use SpreadSheetAddRows(), (as opposed to SpreadSheetAddRow - singular).
<cfset SpreadSheetAddRows( xlsObj,query )>
The sheet columns are mapped from the query columns, so commas in the data won't matter.
Even if the data is in another format or you are only adding a single row, converting it to a query object is an effective way of getting round the issue, see http://cfsimplicity.com/30/workaround-for-spreadsheetaddrow-limitation-when-column-values-contain-commas
You can replace the commas with the character "#130;" (see the source: https://www.petefreitag.com/cheatsheets/ascii-codes/), which looks the same as comma but doesn't create any problems.