Odd error on cfquery while creating view - sql

I have the following query that's returning the error: "Incorrect syntax near the keyword 'VIEW'." I've tried to find any reference of this instance online and in SO. If I overlooked a solution or if anyone has any suggestions I'd greatly appreciate it.
Query:
<cfquery datasource="#mydatasource#">
CREATE VIEW #arguments.bulkRow.request_by#_uploader_features_view
(
feature_products_id
, feature_text
, feature_priority
)
AS
SELECT
a1.tbl_products__products_id AS feature_products_id,
a1.tbl_productfeature__feature_text__1 AS feature_text,
1 AS feature_priority
FROM bulk_product_upload a1
WHERE processed = 0
AND request_by = <cfqueryparam value="#arguments.bulkRow.request_by#" cfsqltype="cf_sql_varchar">
AND LEN( a1.tbl_productfeature__feature_text__1 ) > 1
UNION
SELECT
a1.tbl_products__products_id AS feature_products_id,
a1.tbl_productfeature__feature_text__2 AS feature_text,
2 AS feature_priority
FROM bulk_product_upload a1
WHERE processed = 0
AND request_by = <cfqueryparam value="#arguments.bulkRow.request_by#" cfsqltype="cf_sql_varchar">
AND LEN(a1.tbl_productfeature__feature_text__2) > 1
...
UNION
SELECT
a1.tbl_products__products_id AS feature_products_id,
a1.tbl_productfeature__feature_text__20 AS feature_text,
2 AS feature_priority
FROM bulk_product_upload a1
WHERE processed = 0
AND request_by = <cfqueryparam value="#arguments.bulkRow.request_by#" cfsqltype="cf_sql_varchar">
AND LEN(a1.tbl_productfeature__feature_text__20) > 1
</cfquery>
This is an abbreviated form of the query but it should get you started and show the basic layout.
Thanks in advance,
JP

I ran some testing against my own SQL Server and it appears that parameterized queries cause problems when creating views. Removing the CFQUERYPARAM tags should correct the issue. Using CFQUERYPARAM with a standard select statement is a best practice, but in this case you're passing in SQL that will be executed every time the view is accessed, so the parameterization isn't able to get passed through into the view.
Here are a couple of examples using the same concept, but tables from one of my own databases.
The following produces the Incorrect syntax near the keyword 'view' error:
<cfset id="x" />
<cfquery>
create view #id#_view as
select * from AdminUser
where admID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#id#" />
</cfquery>
The following works fine:
<cfset id="y" />
<cfquery>
create view #id#_view as
select * from AdminUser
where admID = '#id#'
</cfquery>
If anyone is able to locate a SQL Server reference which explains this in detail, feel free to edit this answer with a link.
I would also note that depending on the value of the ID, you might consider wrapping the view name with brackets. If the ID begins with a number the statement will fail as-is, but putting that into a bracketed statement will cover those situations (just be sure to use the bracket notation when querying the view as well). Example: create view [#id#_view]

Related

ColdFusion count the amount without using SQL

I am trying to count the amount without using SQL count() code
Is there a way to extract the results including the number amount over ColdFusion?
Select test
From ......
Where .....
<Cfif not test.RecordCount>
No records found
</Cfif>
<cfoutput query="test">#amount#</cfoutput>
It should display like this
TEST CountOutput
TEST A: 22
TEST B: 32
TEST B: 1
TEST C: 23
(From comments ...)
Why can't you use SQL for this? Unless there's a valid reason you can't use COUNT, it's by far the simplest way to aggregate. You don't need to know the specific values in the database table in order to perform a COUNT. Just do:
SELECT column, count(*) AS someAlias
FROM tableName
GROUP BY column
Yes, it is possible to do the same in ColdFusion code, but again unless there's a specific reason to do so, it's more efficient to use SQL.
<cfset data = {} />
<cfset names = {} />
<cfloop query="test">
<cfif not structKeyExists(data, test.name)>
<cfset data[test.name] = 0 />
<!--- if you need to preserve original case of name --->
<cfset names[test.name] = test.name />
</cfif>
<cfset data[test.name] += 1 />
</cfloop>
<cfoutput>
<cfloop collection="#data#" item="key">
#names[key]#: #data[key]#<br />
</cfloop>
</cfloop>
To get the total count without using SQL, Use
QUERYVARIABLE.RECORDCOUNT
Based on the condition used in the SQL query it will give you the count.
FOR Example,
<cfquery name="test">
SELECT * FROM database WHERE name=testA
</cfquery>
<cfdump var="#test.RECORDCOUNT#" />
Use this within a function, call it and store the return value in a stack or an array.
I strongly recommend you use a SQL Count(). I cannot imagine why you would want to do it inside a CFLoop or CFOutput, but it is possible if you use the Group attribute, and count each row that way.
Did you know that after you execute CFQuery against your SQL server to get all those detail records, you can run a "query of queries" summarize the SQL data. This article seems to explain it:
https://www.quackit.com/coldfusion/tutorial/coldfusion_query_of_queries.cfm

ColdFusion: SQL Select IN from a Query

I have a SQL Server query which returns two values for one MyBusinessUnit column returns two values, say:
1111
2222
in a query object called MyQuery1
Both of these values also exist in a DB2 database's MyCorpUnit column.
What I want is to select all the matching records from the DB2 table--and, no, cross database queries are NOT working.
So, here's my Query2 for DB2 database:
<cfquery name="Query2" datasource="#application.DSN#">
SELECT MyCorpUnit WHERE MyCorpUnit IN
(
<cfqueryparam value=" #Query1.MyBusinessUnit #" CFSQLType="cf_sql_varchar" />
)
</cfquery>
But Query2 only returning matching record for only one value (1111).
So some other approach is needed. I have tried to create a string but that didn't work either.
Any idea?
Thanks!
cfqueryparam has a list attribute which might help:
<cfqueryparam value = "parameter value"
CFSQLType = "parameter type"
list = "yes|no"
maxLength = "maximum parameter length"
null = "yes|no"
scale = "number of decimal places"
separator = "separator character">
AND/OR ...additional criteria of the WHERE clause...>
I've used it before but not sure if it was in a QoQ or not. :D
ref: http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f6f.html
I am going to accept #AJ Dyka answer [Thank you!] but I have more to add to make it complete. Indeed, per his advice, I ended up using the 'LIST' attribute. A good discussion on it can be found here.
But, as you can see in the comments, I was still getting only "1111" despite using a List. And that's because of the leading spaces in my data. I ended up using a TRIM function. Here is a code snippet.
Converted the output from Query1 to a List :
<cfset ListUniqueWStreamBusinessUnit = ValueList(Query1.MyBusinessUnit )>
Then the magical code snippet!
...
WHERE trim(GMMCU) IN
(
<cfqueryparam value="#ListUniqueWStreamBusinessUnit#"
CFSQLType="cf_sql_varchar"
list="yes" />
)

Update error using ## [Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near the keyword 'WHERE'

Here is my code:
<cfdump var="#addEnt#" >
<!-- ADD -->
<cfquery name="add" datasource="testdatasource" dbtype="OLEDB">
UPDATE tblrequests
SET
lastname='#ucase(form.lastname)#',
firstname='#ucase(form.firstname)#',
middlei='#ucase(form.middlei)#',
title='#form.title#',
eod='#dateformat(form.eod,'m-d-yyyy')#',
dutystation='#form.dutystation#',
requestsnetwork=<cfif parameterexists(form.requestsnetwork)>1<cfelse>0</cfif>,
affiliation='#form.affiliation#',
commentssupvreq='#form.commentssupvreq#',
requestdelete=<cfif form.requestdelete IS NOT ''>'#dateformat(form.requestdelete,'m-d-yyyy')#',<cfelse>Null,</cfif>
commentssupvdelete='#form.commentssupvdelete#',
commentssupvedit='#form.commentssupvedit#',
dateemailrequested=<cfif form.dateemailrequested IS NOT ''>'#dateformat(form.dateemailrequested,'m-d-yyyy')#',<cfelse>Null,</cfif>
commentsit='#form.commentsit#',
bgcomplete=<cfif form.bgcomplete IS NOT ''>'#dateformat(form.bgcomplete,'m-d-yyyy')#',<cfelse>Null,</cfif>
dategroupscreated=<cfif form.dategroupscreated IS NOT ''>'#dateformat(form.dategroupscreated,'m-d-yyyy')#',<cfelse>Null,</cfif>
WHERE recnumber = #addEnt#
</cfquery>
When I submit the form I get an error:
Error Executing Database Query. [Macromedia][SQLServer JDBC
Driver][SQLServer]Incorrect syntax near the keyword 'WHERE'.
My cfdump displays the correct addent number from sql, but using #addEnt# in the sql statement is not working. Other pages in my applications ## for SQL queries and they work fine.
The last line in your set statements has a comma at the end, which is where the SQL will be complaining
(Too long for comments)
As suggested in the comments, there are several improvements you could make to the query: one of the biggest, being the addition of cfqueryparam. It provides several advantages, such as:
CFQueryparam, or bind variables, help improve performance by encouraging databases to reuse query execution plans, rather than generating a new one each time (which is a costly operation).
Bind variables also prevent the execution of client supplied values as SQL commands, which has the happy side effect of preventing common forms of sql injection.
CF's implementation of bind variables also provides an extra layer of validation, by type checking input values, before the query is ever executed. So when invalid parameters are detected, it saves a wasted trip to the database.
A few other tips for improving the query
Although it makes no syntactical difference, consider placing commas at the beginning of each line, rather than at the end. This makes it easier to spot extra or missing commas:
UPDATE SomeTable
SET ColumnA = 'xxxx'
, ColumnB = 'yyyy'
, ColumnC = 'zzzzz'
, ColumnD = 'xxxx'
, ColumnE = 'yyyy'
WHERE ....
It looks like your query is populating several datetime columns. When working with datetime columns, it best to use date objects, not strings. Date strings are ambiguous, and can be interpreted differently than you might expect, depending on the database or settings. To insert a date only, use <cfqueryparam cfsqltype="cf_sql_date" ...>, for both date and time use <cfqueryparam cfsqltype="cf_sql_timestamp" ...>. Obviously, always validate the date strings first.
Consider using cfqueryparam's null attribute. It can be quite handy when inserting null values conditionally. (See example below)
As an aside, ParameterExists was deprecated a while ago and replaced with IsDefined, or preferably StructKeyExists. In this case, another alternative to a CFIF is to declare a default with cfparam, so the form field in question always exists.
Putting it all together, your final query might look something like this. I guessed about the column data types, so adjust as needed.
UPDATE tblrequests
SET lastname = <cfqueryparam value="#ucase(form.lastname)#" cfsqltype="cf_sql_varchar">
, firstname = <cfqueryparam value="#ucase(form.firstname)#" cfsqltype="cf_sql_varchar">
, middlei = <cfqueryparam value="#ucase(form.middlei)#" cfsqltype="cf_sql_varchar">
, title = <cfqueryparam value="#form.title#" cfsqltype="cf_sql_varchar">
, eod = <cfqueryparam value="#form.eod#" cfsqltype="cf_sql_date">
, dutystation = <cfqueryparam value="#form.dutyStation#" cfsqltype="cf_sql_varchar">
, requestsnetwork = <cfqueryparam value="#form.requestsNetwork#" cfsqltype="cf_sql_bit">
, affiliation = <cfqueryparam value="#form.affiliation#" cfsqltype="cf_sql_varchar">
, commentssupvreq = <cfqueryparam value="#form.commentsSupvReq#" cfsqltype="cf_sql_varchar">
, requestdelete = <cfqueryparam value="#form.requestDelete#" cfsqltype="cf_sql_date" null="#not isDate(form.requestDelete)#">
, commentssupvdelete = <cfqueryparam value="#form.commentssupvdelete#" cfsqltype="cf_sql_varchar">
, commentssupvedit = <cfqueryparam value="#form.commentssupvedit#" cfsqltype="cf_sql_varchar">
, dateemailrequested = <cfqueryparam value="#form.dateEmailRequested#" cfsqltype="cf_sql_date" null="#not isDate(form.dateEmailRequested)#">
, commentsit = <cfqueryparam value="#form.commentsit#" cfsqltype="cf_sql_varchar">
, bgcomplete = <cfqueryparam value="#form.bgComplete#" cfsqltype="cf_sql_date" null="#not isDate(form.bgComplete)#">
, dategroupscreated = <cfqueryparam value="#form.dateGroupsCreated#" cfsqltype="cf_sql_date" null="#not isDate(form.dateGroupsCreated)#">
WHERE recnumber = <cfqueryparam value="#addEnt#" cfsqltype="cf_sql_integer">

cfqueryparam issues [duplicate]

This question already has answers here:
MS SQL Exception: Incorrect syntax near '#P0'
(7 answers)
Closed 8 years ago.
I am updating queries to use the cfqueryparam after I was shown all the advantages to using cfqueryparam's. However I have now run into an error that I have not crossed before and not sure how to troubleshoot or where to look for the issue. I am guessing that it is a syntax issue.
Here is the error-
Error Executing Database Query.[Macromedia][SQLServer JDBC Driver][SQLServer]Incorrect syntax near '#P1'. The specific sequence of files included or processed is: C:\inetpub\wwwroot\cfleadsource\admin\MultipleAccountReassign_new.cfm, line: 170
Here is my query. As you can see the old query is commented out and has been replaced with the new query. It should be noted that the old query worked without issues and this is the first query on the page that has been altered. For the life of me I can not determine what is incorrect. Thanks for the help.
<cfquery name="GetAccounts" datasource="#dbConn#">
<!--- select top #callNum# * from contact where mar in (select mar from marselect where userid = #oUID# and mar not like '%branch%') order by newid() --->
select top <cfqueryparam value= "#callNum#" CFSQLType="CF_SQL_INTEGER"> * from contact where
mar in (select mar from marselect where userid = <cfqueryparam value= "#oUID#" CFSQLType="CF_SQL_INTEGER"> and mar not like '%branch%') order by newid()
</cfquery>
select top cannot use <cfqueryparam> for top rows without brackets.
You may try adding a bracket and see if it works: MS SQL Exception: Incorrect syntax near '#P0'

fixing "more columns in insert than values specified"

A user got this error
DIAGNOSTICS: Error Executing Database Query. [Macromedia][SQLServer
JDBC Driver][SQLServer]There are more columns in the INSERT statement
than values specified in the VALUES clause. The number of values in
the VALUES clause must match the number of columns specified in the
INSERT statement. The error occurred on line 252. MESSAGE: Error
Executing Database Query. ROOT CAUSE:
coldfusion.tagext.sql.QueryTag$DatabaseQueryException: Error Executing
Database Query. Server: server2
There should be around 60 values/columns. Possible solution is adding <CFIF isDefined("VARIABLES.xxx")> to each of the values in INSERT and VALUES but this would take a long time. Is there a better way? Here is some of the code
<CFQUERY name="addAgency" datasource="#REQUEST.dsn#">
INSERT INTO agency (agency_name, code, address1, address2, city_id, postal, phone, alternativePhone, fax, provincialRegistration,
<!--- contact, ---> firstname, lastname, username, password, relationship_id, editdate, adddate, email, URL_link,Airport_id,
header, teaser, full_desc, <CFIF isDefined("VARIABLES.specialty")>specialty,</CFIF> hours_1, hours_2, hours_3, hours_4,
hours_5, hours_6, hours_7, merchant_ID,
region_ID, fcApproved, agencyType_ID, agencystatus, crossview, insp_Approved, rbc_Approved,
branch_number, gp_entity_ID,
<CFIF VARIABLES.alias1 gt 100> alias1,</CFIF>
<CFIF VARIABLES.alias2 gt 100> alias2,</CFIF>
<CFIF Trim(VARIABLES.alias3) NEQ ""> alias3,</CFIF>
default_agent_id,LOCAL_PASSWORD,LOCAL_USERNAME,NATIONAL_PASSWORD,NATIONAL_USERNAME,VACATIONCLUB_PASSWORD,VACATIONCLUB_USERNAME,toll_free_number,display_toll_free ,MARKETINGREGIONID, searchPreference, bookingOption,customer_can_choose
<CFIF isDefined("variables.logo_filedata")>,logo_fileName,logo_fileData,logo_mimeType</CFIF>
,gds, pseudo_city, acv_affiliate_code, vip_ext,owner_manager_title_en,owner_manager_title_fr)
VALUES (<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.agency_name))#" cfsqltype = "cf_sql_varchar" maxlength="150">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.code))#" cfsqltype = "cf_sql_varchar" maxlength="50">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.address1))#" cfsqltype = "cf_sql_varchar" maxlength="255">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.address2))#" cfsqltype = "cf_sql_varchar" maxlength="255">,
<CFQUERYPARAM value="#sanitize(VARIABLES.city_id,true,true,false,true,false)#" cfsqltype = "cf_sql_integer">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.postal))#" cfsqltype = "cf_sql_varchar" maxlength="10">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.phone))#" cfsqltype = "cf_sql_varchar" maxlength="20">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.fax))#" cfsqltype = "cf_sql_varchar" maxlength="20">,
<!--- <CFIF IsDefined("VARIABLES.contact")>#Trim(VARIABLES.contact)#, <CFELSE> ' ', </CFIF> --->
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.firstname))#" cfsqltype = "cf_sql_varchar" maxlength="40">,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.lastname))#" cfsqltype = "cf_sql_varchar" maxlength="40">,
'-', '-',
<!--- Dummy un/pw --->
<CFQUERYPARAM value="#sanitize(VARIABLES.relationship_ID,true,true,false,true,false)#" cfsqltype = "cf_sql_integer">,
#CreateODBCDateTime(Now())#,
#CreateODBCDateTime(Now())#,
<CFQUERYPARAM value="#Trim(sanitize(VARIABLES.email))#" cfsqltype = "cf_sql_varchar" maxlength="40">,
Each of your s in the "columns" area MUST be matched with corollary CFIF in the "values" section as long as you are doing it this way. While there are other ways of doing it, they are not necessarily less messy. You could, for example:
set defaults for all columns with some cfparams so you did not have to have any "cfifs"
Write multiple "cleaner" queries
Move the whole thing to a stored procedure and pass what you have into it - the SP would then worry about the logic.
Save a small subset of values then "update" based on your cfif logic (don't like that one!).
As you can see they all have a downside.
Elaboration on 1)
Instead of doing something arduous like:
<CFIF isDefined("VARIABLES.specialty")> Specialty,</cfif>
Before you start your query make sure you have a value for all the variables you need using cfparam as in:
<Cfparam name="Specialty" default=""/>
(of course the default for specialty might be 0 or whatever).
The cfparam tag checks to see IF the variable exist and if it does not exist it creates it with the default you specify. This would mean you can "guarantee" that the variable will indeed exist - meaning you can eliminate the CFIF statement in your query.
One cavaet has to do with NULLs in the database. If you are depending on nulls (meaning if specialty does not exist you wish for the column to remain null), then you will need to add the "null" attribute to your cfqueryparam as in:
<CFQUERYPARAM
value="#Trim(sanitize(VARIABLES.specialty))#"
cfsqltype = "cf_sql_varchar"
null="#mynullfunction(variables.specialty)#"/>,
Note the "mynullfunction" - I ususally create a utility UDF for this that simply returns YES if the value is blank or zero (or whatever I define) and "no" if it's populated.
The best solution is to use the null attribute of cfqueryparam for columns where a default has not be set in the database, this means you can avoid adding conditions to the INSERT INTO and keeps the VALUE to one line per column. When a default does exist for a column then you need to use the long winded condition. This is the simplest, least obtrusive change.
Example where Alias1 has a database default, speciality does not.
` <cfset Variables.IsValidAlias1 = Variables.alias1 gt 100>
<cfquery name="addAgency" datasource="#REQUEST.dsn#">
INSERT INTO agency (agency_name,
specialty
<cfif Variables.IsValidAlias1>
, Alias1
</cfif>)
VALUES (<cfqueryparam value="#Variables.agency_name#" cfsqltype="cf_sql_varchar" maxlength="150">,
<cfqueryparam value="#Variables.specialty#" cfsqltype="cf_sql_varchar" null="#StructKeyExists(Variables,'Specialty') EQ false#" maxlength="199">
<cfif Variables.IsValidAlias1>
,<cfqueryparam value="#Variables.Alias1#" cfsqltype="cf_sql_varchar" maxlength="199">
</cfif>)
</cfquery>`
As an aside you should use StructKeyExists() instead of IsDefined as the former is faster and can be clearer to read. You should put this code inside a function, and that function inside a component so it can be re-used. This is assuming your using CF6 or later.
I would avoid setting empty string defaults for each field or setting values to NULL for non-existent keys. The reason is that you may now (or decide to have in the future) default values in your database columns. As the resulting NULL values would be explicit, they would override your database defaults. If you had passed in an empty string, this might be valid but as a default it likely is not.
My main advice would be to be keep each column on one line so that you easily see that you are being consistent in your conditionals. As Mark said, you must be careful to have the exact same conditionals in the "columns" area as the "values" area of your query.
Somewhat as an aside, I have a free tool called DataMgr that you could use to manage all of this sort of thing for most simple queries.
http://www.bryantwebconsulting.com/docs/datamgr/replace-sql-inserts-and-updates.cfm
http://www.bryantwebconsulting.com/docs/datamgr/getting-started.cfm
The main thing, however, is to be consistent in your conditionals and to format your query in such a way as to make it obvious when you are not.