ColdFusion is NOT dead, it's just NOT marketed well!

Goog Feed, ColdFusion    Comments (14)


"ColdFusion is pretty much a dying language," said the customer service rep for a very popular hosting company, which I will name later.

Alright, enough of this! I know this has been a touchy point for ColdFusion developers for years, from the days of Allaire, to the purchase by Macromedia in 2001 which everyone thought would be CF's demise, to the purchase by Adobe in 2005 which we hoped would push CF to new heights in the coding world, but hasn't really came to pass as of yet.

In thinking this through, I have come up with a theory as to why CF after 10 plus years is still, a "dying" language...

So how did this come to pass?

A buddy of mine here at work recently called GoDaddy.com in regards to their hosting package, which currently offers CFMX7. He asked the rep if they had any plans in the works to upgrade to CF8. His response was "hold on a minute, let me check on that for you...," a couple minutes later he comes back on the line... "I just talked to our developers and they say that ColdFusion is 'pretty much a dying language' and we have no plans to upgrade at this time."

This coming from one of the biggest hosting providers in the world doesn't sit well with making me feel any better about the future of CF.

So, here is my theory. I think CF is awesome, I think it offers so much to the developer, it is easy to use and program in, it is very robust, BUT it's one drawback, the PRICE TAG!

Listed at $7,499.00 by Adobe for the Enterprise Edition of CF doesn't exactly make CF an attractive option for going the route of CF. Why would ANY company want to pay $7,500.00 bucks just to set the stage for a developer to write and deploy code, when there are FREE alternatives, namely, PHP, JAVA, ASP, etc...

This is our livelihood, CF is how we get paid, you would think that Adobe would make CF a more attractive alternative to it's competing languages. If Adobe make purchasing CF something that was NOT a financial burden, then more companies would use it. If more companies used CF, more CF jobs would be created. When more CF jobs are created, our futures become more secure, pay goes up and Adobe shines.

Maybe my perception is off, but this is just my perception of this whole situation. What do you think?

SQL - Update Query Using Sub Queries Update Value

Goog Feed, General, SQL    Comments (4)


I like to post anything SQL that is "new" to me that perhaps I didn't know before or don't remember doing. Today was one such occasion.

I was challenged with the task of updating a table full of reading data for for our district's 3rd-5th graders. The data was comprised of a record per student per testing cycle, and was used for the purpose of tracking reading fluency. I have a second table which holds a score matrix letting me know per grade, per testing cycle what the low and high grades should be to determine if a student is above average, below average or at average.

This was something that I had to do as a "one time event" to about 7000 plus records. I decided that I could run a bunch of queries per reading cycle per grade to do this, but that seemed cheesy to me. I wanted to do it all in one fell swoop. Here is what worked for me.

UPDATE dataTable
SET dataTable.atAboveBelow =
CASE
WHEN dataTable.readingScore < (SELECT belowAvg FROM scoreMatrix where gradeLevel = dataTable.gradeLevel AND testWindow = dataTable.testWindow) THEN -1
WHEN dataTable.readingScore > (SELECT aboveAvg FROM scoreMatrix where gradeLevel = dataTable.gradeLevel AND testWindow = dataTable.testWindow) THEN 1
ELSE 0
END

Comparing the Match Percentage of Two Strings

Goog Feed, General, ColdFusion    Comments (4)


Today at work, my boss asked me to check into "Fuzzy Match" capabilities in ColdFusion for a project we're working on here at work. Basically we want to compare two strings and find out what is the percentage of match between the two. For example does string one match string two with 70% accuracy or better?

So after a couple Google searches I came upon a partial solution. All signs pointed to the fact that I would have to use the Levenshtein distance formula which calculates the number of replacements, insertions or deletions necessary to match string one exactly up to string two.

I happened across a ColdFusion UDF written by Nicholas Zograpos which uses the Levenshtein formula to do this computation and passes back the number of characters needed to change string one into string two. You can find the UDF here.

I put this UDF at the top of my CFC.

<cfscript>
/**
* Computes the Levenshtein distance between two strings.
*
* @param s First string. (Required)
* @param t Second string. (Required)
* @return Returns a number.
* @author Nicholas Zographos (nicholas@nezen.net)
* @version 1, March 15, 2004
*/
function levDistance(s,t) {
var d = ArrayNew(2);
var i = 1;
var j = 1;
var s_i = "A";
var t_j = "A";
var cost = 0;

var n = len(s)+1;
var m = len(t)+1;

d[n][m]=0;

if (n is 1) {
return m;
}

if (m is 1) {
return n;
}

for (i = 1; i lte n; i=i+1) {
d[i][1] = i-1;
}

for (j = 1; j lte m; j=j+1) {
d[1][j] = j-1;
}

for (i = 2; i lte n; i=i+1) {
s_i = Mid(s,i-1,1);

for (j = 2; j lte m; j=j+1) {
t_j = Mid(t,j-1,1);

if (s_i is t_j) {
cost = 0;
}
else {
cost = 1;
}
d[i][j] = min(d[i-1][j]+1, d[i][j-1]+1);
d[i][j] = min(d[i][j], d[i-1][j-1] + cost);
}
}

return d[n][m];
}
</cfscript>

Next, I created a function of my own inside of my CFC which calls the levDistance function passing in two strings, it then divides the result by the length of the string we want to match against (stringTwo) and multiplies by 100 which gives the percentage of error between the two strings in numeric format. Finally I compare the error percentage with my threshold or my max error percentage I am willing to allow, passing the user back a true/false based on the result.

You'll find my function below.

<cffunction name="stringCompare" access="public" returnType="boolean" output="false">
<cfargument type="any" name="stringOne" default="" required="yes">
<cfargument type="any" name="stringTwo" default="" required="yes">

<cfset var result = true />
<cfset var threshold = 30 /><!---This means that we are only allowing for a 30% error rate, 70% match in essence.--->
<cfset var stringCompare = levDistance(trim(arguments.stringOne),trim(arguments.stringTwo))/len(trim(arguments.stringTwo))*100 />

<!---Comparing the result.--->
<cfif stringCompare GT threshold>
<cfset result = false />
</cfif>

<cfreturn result>
</cffunction>

Finally, one last bit of code. How to call the function from the view.

<cfset st1 = "How are you doing?" />
<cfset st2 = "How are ya doing?" />

#myObj.stringCompare(stringOne=st1,stringTwo=st2)#

You can play with the percentage numbers as needed to fit your situation. This really helped me in a problem I faced, hopefully it will do the same for you!

SQL 101 - Counts By Location and Grade

Goog Feed, General, SQL    Comments (0)



The Desired Result

The other day at work there was a need for a report that our reporting system was having trouble putting out. So the fix was to write it ourselves. It's not too complex and for some it may be quite elementary, but here it is none-the-less.

Being that I work for a school district there was a need for a report by campus and grade level of the number of students that fell into a certain category. So for the sake of this report we want a count of all active students based on their campus and their grade level.

Below is the stripped down version of how this was accomplished.

SELECT Campus, Grade, COUNT(studentID) AS StudentCount
FROM ourStudentTable
WHERE studentStatus = 'A'
GROUP BY Campus, Grade
ORDER BY Campus

Hopefully this helps!

SQL - Using Sub Queries As Joining Tables

Goog Feed, General, SQL    Comments (2)


Today at work I faced a dilemma. I was tasked with developing a function in which a parent could be notified when their child has an absence or a tardy in one of their classes (I work for a school district). It involved touching 3 different tables including one twice. The three types of tables are as follows, an attendance details table which we'll call AttendanceDetail, a parent/student table which ties parents with students which we'll call ParentStudent, and finally a notify parent when an absence occurs table which we'll call AttendanceNotification.

So here is the short of how the process works. Daily a routine will run checking to see if a student whose parent requested a notification upon an attendance event had missed a class and/or was tardy to class. Sounds simple enough huh? Well it wasn't as easy as first thought.

My first query was as follows...

SELECT an.studentID, ps.studentFirstName, ps.studentLastName, ad.absence_date
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'

Basically this query grabs all prior absence events for a student where they are active and the parent needs to be notified of the last absence event. So we have a bunch of unwanted events here, we just need the most recent event.

Simple enough we'll just add a couple things to our query and we'll be good to go right? Not so fast. So I added a MAX() function to the absence date which would give me the most recent absence and I grouped by the studentID which would only give me one record back per student and I ended up with the following.

SELECT an.studentID, ps.studentFirstName, ps.studentLastName, MAX(ad.absence_date) AS absenceDate
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'
GROUP BY an.studentID, ps.studentFirstname, ps.studentLastname

Well, the problems began to start, I needed to be able to show the parent what the absence event detail was. Did their student have a tardy? An unexcused absence? A doctors appointment? You get the point. My first thought was to just add it into the SELECT statement for the above query, but then I had to include them in my GROUP BY clause which caused more than one record per student to be returned. I then thought about trying to wrap them in a MAX function, that didn't work, they needed an aggregate function to be included in my SELECT criteria and not in my GROUP BY, I was at a loss.

Then I got an idea, I wondered if I could JOIN on a sub query. I had never tried it before, but it worked perfectly! I thought I'd share it with you just in case you ever ran across a similar problem.

The final query does an INNER JOIN from the AttemdanceDetail table to the previous result set or sub query. Now we're able to get detailed absence info yet only the most recent record. Here is the final query.

SELECT
   a.studentID,
   a.studentFirstName,
   a.studentLastName,
   a.absenceDate,
   CASE WHEN ltrim(rtrim(adII.am_office_abs)) IS NULL THEN ltrim(rtrim(adII.am_teacher_abs)) ELSE ltrim(rtrim(adII.am_office_abs)) END AS am,
   CASE WHEN ltrim(rtrim(adII.pm_office_abs)) IS NULL THEN ltrim(rtrim(adII.pm_teacher_abs)) ELSE ltrim(rtrim(adII.pm_office_abs)) END AS pm
FROM AttendanceDetail adII
INNER JOIN
(SELECT an.studentID, ps.studentFirstName, ps.studentLastName, MAX(ad.absence_date) AS absenceDate
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'
GROUP BY an.studentID, ps.studentFirstname, ps.studentLastname) a
ON a.studentID = adII.studentID AND a.absenceDate = adII.absence_date

Perhaps there is a better way to do this, I just don't know how, but this worked so I ran with it.

More Entries