Archive for the ‘SQL’ Category

ORA-00923: FROM keyword not found where expected

Wednesday, December 15th, 2010

This is a general reference to an error I received today when executing an Oracle statement. Essentially the statement was fairly complicated containing a number of subqueries. As such receiving ‘ORA-00923: FROM keyword not found where expected’ as an error in a statement was somewhat frustrating. As it turns out, not only is it a somewhat useless user facing error, it didn’t even turn out to have anything to do with the FROM clause.

After much debugging, a co-worker determined that the issue was a duplicate column reference in the SELECT clause. After determining the point of failure I decided to write up a simple test to determine if this error would be thrown in a statement far less complicated than the one being worked on at the time.

What I learned is rather interesting. This error is only thrown when a column is duplicated, in which the duplicate is contained within the all symbol (*). So on the assumption that the employee_table contains three columns – employee_id, employee_name, and employee_email – let’s take the following example that would throw this error when run against Oracle.

Throws: ORA-00923: FROM keyword not found where expected

SELECT *, employee_name
FROM employee_table

If I were to write out the columns and duplicate the columns I would get a different error. The following example would throw an ambiguous column reference.

Throws: ORA-00918: column ambiguously defined

SELECT employee_id, employee_name, employee_email, employee_name
FROM employee_table

While the above examples are no-brainers, the particular query I was working on was a very complex SQL statement with CF wrappers and Oracle functions and all kinds of good stuff. So under these conditions finding duplicate columns can be very tricky and unfortunately Oracle doesn’t do much to help. So I guess the lesson is that if you get either of these errors check for any duplicating columns. Note that my literal test did contain a JOIN, which may have something to do with the second error listed. That particular statement might throw a different error.

Query Of Queries runtime error. The aggregate function [SUM(expression)] cannot operate on an operand of type [VARCHAR].

Tuesday, December 14th, 2010

I ran into the above error today when trying to run a SUM() function on a query retrieved from a database using the Coldfusion Query of Queries sweetness. While the error itself is fairly explanatory I couldn’t figure out where my column being summed was being typed as a string as opposed to an integer. As such I began reading up in the Coldfusion docs on how to type data columns via a Query of Queries. It turns out that it’s very doable with a Cast() function. So while not using Cast() would throw the above error, using it to cast the column data type as an Integer resolved the issue.

Won’t work while My_Total is a type string (VARCHAR)

SELECT SUM(My_String_Column) AS My_Total
FROM Some_Table

Will work while My_Total is a type string (VARCHAR)

SELECT SUM(Cast(My_String_Column AS INTEGER)) AS My_Total
FROM Some_Table

So, fairly straight-forward usage. Any column can be cast as a number of data types on the fly within the Query of Queries. Just as a side-note, I did resolve the actual issue after discovering the Cast() function. Essentially, I typed my return variable in my Oracle Function as an NVARCHAR2. Hence my value was returning as a string. Once I changed my return data type I no longer needed the Cast() function in my Query of Queries. Nonetheless, it’s pretty cool functionality provided by Coldfusion.

Oracle SQL Developer Error: Exception firing addinsLoaded to oracle.jdevimpl.vcs

Monday, September 27th, 2010

I recently installed a new version the Oracle SQL Developer on my Windows machine and promptly received the following error upon opening the program: ‘SEVERE 46 0 oracle.ide.IdeCore Exception firing addinsLoaded to oracle.jdevimpl.vcs’.

After spending some time trying to determine the source of the problem I decided to read the instruction manual. While I should have read this first to avoid any issues, I figure better late than never. The docs clearly state: ‘… and do not unzip a kit over the SQL Developer files that are included with Oracle Database’. This is of course exactly what I had done.

I promptly cleaned up the old directory and unzipped the new files into a different directory, and sure enough problem solved.

Lessons Learned:

  1. Always read the installation manual before performing installation, duh!
  2. Do not unzip the SQL Developer files on top of an existing set of SQL Developer files.  It won’t work.

Performing arithmetic with SQL or Coldfusion

Saturday, September 18th, 2010

I’ve been running through some online courses concerning Oracle systems.  One of the earlier lessons discusses performing arithmetic with your SQL statement so that not just the data in the table is returned, but manipulated table data is returned as well.  This peaked my interest since it’s so simple, and yet I’ve never really considered using SQL to do basic arithmetic work from within the SQL statement as opposed to just manipulating the base values with Coldfusion.

Just out of curiosity I ran some tests on my local system, which of course doesn’t run Oracle, but does run MySql.  The test consists of the idea that a company has a database of job applications, but after 30 days they want them to be marked as expired.  So essentially what I want to end up with is an application date plus 30 days, and then compare if that date is greater than today’s date.  All we want to potentially use the database for is adding the 30 additional days to each date in the database.  Because I didn’t have any data to work with I used the following function to enter 500 dummy records into MySql.

<cffunction name="buildQuery" displayname="Build Query" hint="Needed to build a simple set of tables with applications and creation dates." access="public" output="false" returntype="void">

	<cfoutput>
		<cfloop from="1" to="500" index="i">
			<cfset var startDate = dateFormat(now()) />
			<cfset var endDate = dateFormat(now() - 365) />

			<cfset var randomDate = randRange(startDate, endDate) />

			<cfquery name="insertApps" datasource="apps">
				INSERT INTO application_tbl (application_created)
				VALUES (#randomDate#)
			</cfquery>
		</cfloop>
	</cfoutput>

</cffunction>

This function simply takes a random date between now and one year ago and inserts it into the application_tbl table. Now we have some data to process with Coldfusion and SQL. The two functions that return the same thing, but one use CF and the other SQL are.

<!--- Process with Coldfusion --->
<cffunction name="processWithCF" displayname="Process with Coldfusion" hint="Processes the expiration date with Coldfusion" access="public" output="false" returntype="array">

	<cfset var appsQuery = getQuery() />
	<cfset var appsAry = arrayNew(1) />
	<cfset var finalDate = "" />

	<cfloop query="appsQuery">
		<cfset finalDate = application_created + 30 />

		<cfset arrayAppend(appsAry, dateFormat(finalDate, "full")) />
	</cfloop>

	<cfreturn appsAry />

</cffunction>

<cffunction name="getQuery" displayname="Get Query" hint="Gets a query full of applications and dates created." access="private" output="false" returntype="query">

	<cfset var thisQuery = "" />

	<cfquery name="thisQuery" datasource="apps">
		SELECT *
		FROM application_tbl
	</cfquery>

	<cfreturn thisQuery />

</cffunction>
<!--- Process with SQL --->>
<cffunction name="processWithSQL" displayname="Process with SQL" hint="Processes the expiration date with SQL" access="public" output="false" returntype="array">

	<cfset var appsQuery = getQueryProcessed() />
	<cfset var appsAry = arrayNew(1) />

	<cfloop query="appsQuery">
		<cfset arrayAppend(appsAry, dateFormat(application_created, "full"))>
	</cfloop>

	<cfreturn appsAry />

</cffunction>

<cffunction name="getQueryProcessed" displayname="Get Query" hint="Gets a query full of applications and dates created." access="private" output="false" returntype="query">

	<cfset var thisQuery = "" />

	<cfquery name="thisQuery" datasource="apps">
		SELECT application_id, application_created + 30 AS application_created
		FROM application_tbl
	</cfquery>

	<cfreturn thisQuery />

</cffunction>

The only difference between the two is that with the function getQueryProcessed() the SQL statement returns ‘application_created + 30 AS application_created’. This is returning a date created 30 days later than the actual date created. In the getQuery() function the statement is returning the raw data, but I am then using Coldfusion ‘finalDate = application_created + 30′ to set the date to 30 days in advance of the actual date.

In order to time the processing of both simple formats I use the following index page which outputs the average processing time for both according to 1000 iterations over both methods. The index page that monitors performance is the following.

<!--- set of lists to keep up with each time of processing --->
<cfset variables.cfProcessingList = "" />
<cfset variables.sqlProcessingList = "" />

<cfset VARIABLES.process = createObject("component", "processExpiration").init() />

<cfset variables.startCount = getTickCount() />

<cfloop from="1" to="1000" index="variables.i">
	<cfset VARIABLES.processedWithCF = VARIABLES.process.processWithCF() />
</cfloop>

<cfset variables.endCount = getTickCount() />

<!--- time to process and output instance --->
<cfset variables.processingTime = variables.endCount - variables.startCount />

<!--- append processing time to list --->
<cfset variables.cfProcessingList = listAppend(variables.cfProcessingList, variables.processingTime, ",") />

<cfset variables.startCount = getTickCount() />

<cfloop from="1" to="1000" index="variables.i">
	<cfset VARIABLES.processedWithSQL = VARIABLES.process.processWithSQL() />
</cfloop>

<cfset variables.endCount = getTickCount() />

<!--- time to process and output instance --->
<cfset variables.processingTime = variables.endCount - variables.startCount />

<!--- append processing time to list --->
<cfset variables.sqlProcessingList = listAppend(variables.sqlProcessingList, variables.processingTime, ",") />

<!--- average processing times --->
<cfset variables.cfProcessingAvg = arrayAvg(listToArray(variables.cfProcessingList, ",")) />
<cfset variables.sqlProcessingAvg = arrayAvg(listToArray(variables.sqlProcessingList, ",")) />

<cfoutput>
	<br /><br /><br />
	CF Processing Average: #variables.cfProcessingAvg#<br /><br />
	SQL Processing Average: #variables.sqlProcessingAvg#
</cfoutput>

The results:
Average Coldfusion processing time – 23509 ms
Average SQL processing time – 34163 ms

Considering that this was 1000 iterations we’re talking marginal differences at best. As such, when I see two ways of performing the same process that takes roughly the same amount of time to process, I immediately begin looking at design. This is an instance where I do feel the context in which this type of performing is needed should determine the method that is used. Nonetheless, with my experience I think the majority of the time using Coldfusion to perform the data manipulation portion is best practice.

I say this because what does take time are database connections and the process of calling data from a database. Let’s take our theoretical example above and say that we want to not only see which applications are being thrown away, but also those that would be thrown away if our cutoff was 60 days old and 90 days old. To do this the really bad way, we would write three different SQL statements, each adding 30, 60, and 90 days to each returned result. A much better way of doing it would be to return each set within the same SQL statement so that we are only making one database call. This statement would look like:

SELECT application_id, application_created + 30 AS application_created_thirty, application_created + 60 AS application_created_sixty, application_created + 90 AS application_created_ninety
FROM application_tbl

Even better and more flexible is to simply return the data with SQL and then use Coldfusion to do all data manipulation. It will simply run faster and be more flexible to change easily over time. An abstract function can be written that adds a passed in number to a passed in value and returns the result. This doesn’t restrict us to statements. The abstract function could look like the following.

<cffunction name="addStuff" displayname="Add Stuff" hint="Adds any passed in number to any passed in value and returns it." access="public" output="false" returntype="Numeric">

	<cfargument name="value" displayname="Value" hint="Value to add to." type="numeric" required="true" />
	<cfargument name="toBeAdded" displayname="To Be Added" hint="Number to be added to value." type="numeric" required="true" />

	<cfset var result = ARGUMENTS.value + ARGUMENTS.toBeAdded />

	<cfreturn result />

</cffunction>

Now after returning the raw data from the database the above function can be used for manipulation as such.

<cfset VARIABLES.result1 = addStuff(application_created, 30) />
<cfset VARIABLES.result2 = addStuff(application_created, 60) />
<cfset VARIABLES.result3 = addStuff(application_created, 90) />

The beauty of this is that we can continue to add to it simply and quickly. Let’s say our boss came to us and wanted to see how many applications would be left under 45 and 50 days old. We would just add to our code:

<cfset VARIABLES.result4 = addStuff(application_created, 45) />
<cfset VARIABLES.result5 = addStuff(application_created, 50) />

So this is how I see it. There are probably situations where it would make sense to process arithmetic with SQL, but for the most part I feel performing data manipulation with Coldfusion is the way to go. Nonetheless, having the ability to do these things with SQL alone is certainly a powerful tool to have in one’s arsenal.

Deleting from multiple SQL tables with a single query

Wednesday, March 31st, 2010

I’m by no means an expert using SQL, but as of yet I’ve found no way to delete data from multiple tables without writing a single query specifically for each table that data needs deleted from. So if you’re reading this expecting a native SQL statement that will delete data from multiple tables then I have nothing to offer. However, I do have a solution. One which requires a programming language, Coldfusion in my case.

The idea is that we have a number of tables.  Lets say we have five tables holding data about products.  So we’ll have tables named ‘products_tbl’, ‘products_name_tbl’, ‘products_description_tbl’.  Using just SQL we would need to write three delete statements like:

Straight SQL

<cfquery name="VARIABLES.deletetable" datasource="myds">
	DELETE
	FROM product_tbl
	WHERE product_id = 9
</cfquery>

<cfquery name="VARIABLES.deletetable" datasource="myds">
	DELETE
	FROM product_name_tbl
	WHERE product_id = 9
</cfquery>

<cfquery name="VARIABLES.deletetable" datasource="myds">
	DELETE
	FROM product_description_tbl
	WHERE product_id = 9
</cfquery>

Now let’s say that halfway through the project the client suddenly wants the price to be included. Really not a big deal, but when we now go to delete the product we realize that we need to go find our component or whatever that is handling the deleting transactions and add a new delete statement.

<cfquery name="VARIABLES.deletetable" datasource="myds">
	DELETE
	FROM product_price_tbl
	WHERE product_id = 9
</cfquery>

I personally hate this, and like most things the more complicated the data becomes the more burdensome it gets on the developer. So what’s the solution?

The idea is that we need to bundle all of these related sets of data into a group. When I say related I simply mean that in this case all the tables containing the parts and pieces of a product. The product is an object, and when that object is deleted we need to visit each of the tables containing information for that product and get rid of it. If we could simply group each of the table names we could run a loop with a delete statement inside where the table name dynamically changes with each loop. This would allow us to update our group and not have to worry about updating any actual SQL.

In my case, I’ve created the group under the APPLICATION scope. This let’s me access the group from anywhere within my application. As such my Application file would contain inside the onApplicationStart() method, for this case, the following.

<cfparam name="APPLICATION.producttables.productTbl" type="string" default="product_tbl">
<cfparam name="APPLICATION.producttables.productNameTbl" type="string" default="product_name_tbl">
<cfparam name="APPLICATION.producttables.productDescriptionTbl" type="string" default="product_description_tbl">

Now that we have our table names stored in the APPLICATION scope under a group called ‘producttables’ we can build a function that will get all the data in the ‘producttables’ group and set it into an array. We can then loop over this array of table names deleting from each the product data associated with the specified product id. In this case our function would look like.

<cfcomponent displayname="Looping Delete" hint="Loops over a portion of a struct with table names and deletes from those tables." output="false">

	<cffunction name="deleteProduct" displayname="Delete Product" description="Deletes a product." access="public" output="false" returntype="void">

		<!--- PRODUCT ID --->
		<cfargument name="productid" displayname="Product ID" hint="Id of the product to be deleted." type="numeric" required="true" />

		<!--- CREATE AN ARRAY OF TABLE NAMES STORED IN APPLICATION SCOPE --->
		<cfset var tableArray = structkeyarray(APPLICATION.producttables)>

		<!--- LOOP OVER THE ARRAY --->
		<cfloop array="#tblArray#" index="VARIABLES.i">
			<cfquery name="deleteproduct" datasource="#APPLICATION.dataSource#">
				DELETE
				FROM schema_name.#APPLICATION.producttables[VARIABLES.i]#
				WHERE product_id = <cfqueryparam value="#ARGUMENTS.productid#" cfsqltype="cf_sql_integer" maxlength="10">
			</cfquery>
		</cfloop>

	</cffunction>

</cfcomponent>

So what we’ve done here is made it much easier to add data to the product without ever having to touch our component. Instead all we really need to do is add the data to the APPLICATION scope to the producttables group. So for instance now if we need to add a price to our product all we have to do is go into the Application.cfc file and set

<cfparam name="APPLICATION.producttables.productPriceTbl" type="string" default="product_price_tbl">

That’s all that we need now to make the update. The loop will now find this table in our group and delete from it the same as the others.

MySQL Workbench doesn’t have Query Browser or Administrator in 5.1

Friday, March 19th, 2010

If you’re lazy like me and prefer to work in the mysql Administrator and Query Browser as opposed to the command prompt, you may be surprised if you go to the website now to download the GUI tools.  They have changed now to a single application called the Workbench.  This is great and a welcome change in my opinion.  The only problem I found was that they have removed the old GUI tools from the downloads page and have replaced it with the current stable release (5.1) of the Workbench.  This is fine except that the current stable release only contains the new data visualizer.  If you want the Workbench that contains the data visualizer and the Query Browser and Administrator you need to download the beta 5.2.  Unfortunately the beta is not readily available under the downloads page of the main site.  As such, the link to the download at the time of this writing is http://dev.mysql.com/downloads/workbench/.  So if you need the Query Browser and the Administrator you’ll need to download this version, or a later version depending on what is available at the time of your reading.

Access denied for user ‘someone’@’localhost’ (using password: YES)

Thursday, February 25th, 2010

If I had a nickel for every time I’ve gotten this error I’d be somewhere around 35 cents richer.  Point being this error really isn’t that big of a deal, but can certainly be somewhat annoying.  If you’re using shared web hosting and are receiving this error on your production site just call your host because there is probably nothing you can do on your end.

However, if you’re working on a VPS, dedicated server, the cloud, or any environment in which you have access to both the server and the Coldfusion Administrator then you’re in luck.  This error is usually thrown as a result of trying to access the database with a datasource set up for a user that doesn’t exist.  So if you’re using MySql on your server and you try to access it with an account that maybe exists on the local drive, but not on the server you’ll receive this error.  To test if this is the case go to the Coldfusion Administrator and verify the data source connection in question under the datasources menu.  It probably won’t verify.  At this point you will want to connect the datasource using a legitimate account or just use the ‘root’ username and no password.  This should verify the datasource and eliminate the error.

Starting MySQL after installation on a mac.

Wednesday, January 27th, 2010

This is more of a quick note than anything else.  I installed MySQL on a new mac a while back and spent some amount of time fighting to get it running.  Assumptions can be very dangerous, or wasteful of time in my case.  My assumption was that MySQL start up once installed.  But it didn’t.  After installation of both MySQL and the GUI tools I tried to login, but with no success.  I went to the docs, the command line, the blogs and forums, and anywhere else you can probably imagine.

I don’t remember how I found it, but I ended up in preferences under the MySQL tool that is installed initially.  Here, you can start and stop MySQL.  If it is started it will say that MySQL is ‘running’ in incredibly bright unreadable letters.   And if not it will say ‘stopped’.  All I needed to do was start it.  Duh! Lesson: don’t assume that the basic simple stuff just happens always.

Recording decimal numbers into a MySQL database

Friday, November 20th, 2009

I had a little problem this afternoon that took me a few minutes to figure out. I was trying to insert a price into a MySQL database using the Coldfusion <cfquery> tag. This was my problem. I set up the database to accept decimals. So I have a column data-typed to DECIMAL(5,2). So I can store a 5 digit number that always has two decimal places. All is fine with this. If I hard code a price such as 14.98 into an INSERT statement there is no problem. But when I insert it dynamically using Coldfusion I get 14.00 inserted into the database. Let’s take a look at what I was trying to do.

<cfset VARIABLES.price = 14.98>
<cfquery name=”insertPrice” datasource=”datasource”>
INSERT INTO mytable_tbl (price)
VALUES (<cfqueryparam value=”#VARIABLES.price#” cfsqltype=”cf_sql_decimal”>)
</cfquery>

So I have a price of 14.98 set into a variable called ‘price’.  All I want to do is insert this price into a column called price (data-typed DECIMAL(5,2)) into mytable_tbl table using a query statement.  However, running this statement enters ’14.00′ into the database.  After trying some things I realized that there are a few more attributes in the <cfqueryparam> tag that I just didn’t know about.  I use <cfqueryparam> religiously, but have never really had reason to take it beyond the ‘value’ and a cfsqltype of ‘varchar’ or ‘numeric’ before.  But as it turns out when using ‘cf_sql_decimal’ as the cfsqltype you can also, and should, use another attribute called ‘scale’. So our new SQL statement looks like the following.

<cfquery name=”insertPrice” datasource=”datasource”>
INSERT INTO mytable_tbl (price)
VALUES (<cfqueryparam value=”#VARIABLES.price#” cfsqltype=”cf_sql_decimal” scale=”2″>)
</cfquery>

Simple solution.  One I just didn’t know about.  I’ll also note that I have since checked the docs and sure enough it’s there. Just a reminder to always check the docs first.