Lucee need duplicate columns in SQL query - mysql

Programming in Lucee (Ubuntu, Firefox) and have a query in which I need duplicate columns. In generic SQL run from my terminal this produces exactly what I ask for. It works fine in ColdFusion. But when I run it in Lucee, it refuses to accept the request for the duplicate column.
<cfoutput>
<cfset mylist = "PersonFn, PersonLn, PersonState, PersonLn">
<cfquery name = "betty" datasource = "Moxart">
select #mylist#
from Person
limit 5
</cfquery>
</cfoutput>
When I get the columnlist for this Query, it has only 3 items in it, having eliminated the duplicate column. When I run a report against the output:
<cfset m = 0>
<cfoutput query = "betty">
<cfloop list = #mylist# index = "xxcol">
<cfset m = m + 1>
#betty[xxcol][currentrow]#
<cfif m EQ 4>
<br>
</cfif>
</cfloop>
</cfoutput>
I get this error:
key [ PersonLn] not found in query, columns are [PersonFn,PersonLn,PersonState]
I really, really need that duplicate column. Programming around this would be very difficult and excruciating.
I cannot use an alias, because the actual list is chosen by the user and there is no way to know what he might choose, or how many duplicates I might have. For similar reasons, I cannot reconstruct the data after the query to create the extra columns -- since I don't know what they are.
To be more exact, I probably can do those things, but the amount and complexity of programming is significant -- and all because Lucee just won't do what generic MySql will do.
Can anyone think of a way I can get those duplicate columns back into my output without major programming?

You can't have duplicate columns in sql you have to rename it to field1 and field2 for example.
What you seek violates the Sql standard.

Related

Mysql getting wrong information from information_schema

Writing in Linux/Lucee and Coldfusion/Mysql. I have several databases in my system, with quite a few tables overlapping. I have a program which would add a field to a given table, say Activity, in each database. Of course I don't want to alter a non-existent table, so I am checking to make sure the table is there.
The simplest way would be to go to the database and use "show tables like 'Activity'". To do that in ColdFusion I used the datasource that belongs to that database. However, when I tried that, I got zero tables even when the table is present.
<cfquery name = 'tbl' datasource = '#thedatasource#'>
show tables like 'Activity'
</cfquery>
The record count for this query is zero. Then I tried using the information schema and got better results with this test program:
<cfquery name = 'dblist' datasource = 'Moxart'>
select MoxcoId from Moxco
</cfquery>
<cfloop query = 'dblist'>
<cfoutput>
<cfquery name = 'tbl' datasource = 'Moxart'>
select table_schema,table_name from information_schema.tables
where table_schema = '#MoxcoId#' AND table_name = 'Activity'
</cfquery>
<cfdump var = '#tbl#'>
</cfoutput>
</cfloop>
This gave exactly the right answer. However, when I put the same code into the real program, it keeps returning zero records. The real program is rather long, however most of the beginning consists of picking up info from the previous form . From the line
<cfquery name = 'dblist' datasource = 'Moxart'>
the only difference is the addition of this section because #MoxcoId# is not always the schema name. The variable #mmox# is in this case blank, so doesn't add anything.
<cfif #MoxcoId# EQ 'Moxart'>
<cfset pref = '#mmox#Moxware'>
<cfelse>
<cfset pref = '#mmox##MoxcoId#'>
</cfif>
When I do a dump on the query 'tbl' it shows that zero records were retrieved, even though the code appears to be exactly correct.
I am baffled. There must be something wrong in my code, but I just can't see it. If anyone can suggest something I would appreciate it.

Coldfusion cfloop through checkboxes in a cfquery

I have had a good search through to see if there was something similar to what I am trying to do. Nothing specifically covers it though so without further ado.
I would like my cfloop to work through any of the checked boxes on a search page and display the appropriate results drawn from the database. This is what I have so far:
<cfquery name="joblibrary">
SELECT *
FROM tblJobLibraryRoles JOIN tblJobLibraryCategories
ON tblJobLibraryRoles.category = tblJobLibraryCategories.id
<cfloop list="#form.cbGrade#" index="i">
WHERE grade=<cfqueryparam cfsqltype="cf_sql_varchar" value="#i#"/>
</cfloop>
ORDER BY category, grade, title, heraRef;
</cfquery>
Now it works all fine if only one checkbox is ticked, so I am basically asking can I get this type of CFLOOP to work in the way I've created it, or am I barking up the wrong tree?
You don't need a loop. Just use the sql keyword "in".
where somefield in (
<cfqueryparam
cfsqltype="cf_sql_varchar" value="#form.checkboxfield#"
list="yes">
)
You just have to do something to contend with the situation where no boxes are checked.
IN () is certainly the way to handle this (works with other sql statements as well), but there may be times where you want multiple WHERE conditions that are all entirely defined by variables.
Again, IN () is the solution here, but I'll demonstrate with your query on how to do what you were originally wanting to do.
Simply add a WHERE 0=0 (or 1=1 or anystring=anysamestring. You could even say Where 'trickwhere'='trickwhere' but there's no reason to get wordy with it) and loop over the rest using an AND instead.
<cfquery name="joblibrary">
SELECT * from tblJobLibraryRoles JOIN tblJobLibraryCategories ON tblJobLibraryRoles.category=tblJobLibraryCategories.id
WHERE 0=0
<cfloop list="#form.cbGrade#" index="i">AND grade=<cfqueryparam cfsqltype="cf_sql_varchar" value="#i#"/></cfloop>
ORDER BY category, grade, title, heraRef;
</cfquery>

Can I use MySQL "IN" with a list of strings in Coldfusion?

I'm trying to feed a variables into an MySQL query from Coldfusion. My query currently includes:
<cfif Session.app_assign EQ "0">
AND art.iln IN ( #Session.app_ilns# )
<cfelseif Session.app_assign EQ "1">
AND art.marke IN ( "#Session.app_keys#" )
</cfif>
Session.app_ilns will be a list of numbers like so: 1111111111111,2222222222222.... which works fine. Howerver, Session.app_keys will be list of strings, like:
sample_1, sample_2, sample_3
which will produce an error in my script, because of
unknown column "sample_1, sample_2, sample_3" in where clause.
Question:
Is there a way to use MySQL IN with a list of string values or do I need to pre-loop over the variables to add quotation marks. Are there any other ways to get this done?
Thanks!
Try using a cfqueryparam (good practice anyhow) with list="yes"
See this Ben Nadel blog post
Code would look like:
AND art.marke IN ( <cfqueryparam value="#Session.app_keys#" cfsqltype="cf_sql_varchar" list="yes" />)
Got it. I can set list="true" in cfqueryparam. See here

in a multi-language site, why would I store some text strings in a database and write other one into the markup?

I'm working on an existing multi-language site (Coldfusion/MySQL).
Why is it that on a lot of pages I'm sitting on, some text strings are always hard-coded into the markup like:
<CFIF language = "EN"><p>Hello World</p></CFIF>
while others use the database to update text like so:
<p><cfoutput>#tx_greetings#</cfoutput></p>
What is the best practice here? I thought if I'm going to use a database for translations, it would be easier to store all texts in there (long and small). If I'm not using a database, then all texts should be if-elsed. Mixing it is a little maintenance-heavy, isn't it?
Also, is there a limit on text-string-length, which I'm storing to MySQL? Maybe performance-wise?
Thanks for some inputs!
You shouldn't store strings/translations in your code, that's bad practice if you want a maintainable i18n'd site.
You should store all your string in the same location, db or a properties file per language. It doesn't matter which, but be consistent. Personally I prefer a properties file as its easy to edit.
welcome_message=Hi {0}, Welcome to my site
Load all your translations in one go in onApplicationStart(), then provide a wrapper class to access them and to format the string with supplied arguments
for example
#i18n.getString(user.getLocale(), "welcome_message", [user.getUsername()])#
You can use java.text.MessageFormat[1] to provide powerful formatting
function getString(string locale, string key, array args) {
var mf = createobject("java", "java.text.MessageFormat");
mf.init(variables.strings[arguments.locale][arguments.key]);
return mf.format(javacast("java.lang.Object[]", args));
}
The above is just an example, and you need to provide error catching and caching to this
Hope that helps point you in a productive direction
[1] http://docs.oracle.com/javase/7/docs/api/index.html?java/text/MessageFormat.html
You can use a DB or a ascii file, depends on which you prefer.
If u use a DB you can create a table with the following columns:
country_code : country code for the language (i.e. US for english)
definition_name : name of the definition or message (*i.e. db_error_msg for a generic error message for db action*)
definition value : value of the definition (i.e. Sorry, an error occurred saving your data)
Each record will be a definition.
Depending on the language the user select your app will filter the database and you will get a query of all definitions you need.
I usually use that query to set a session variable structure like:
<cfif IsDefined("session.language") IS FALSE>
<cfquery name="getDefinition" datasource="dsn">
SELECT * FROM tbl_definitions WHERE country_code = "US"
</cfquery>
<cfset session.language = structnew()>
<cfoutput query="getDefinitions">
<cfset session.language["#definition_name#"] = "#definition_value#">
</cfoutput>
</cfif>
In the code I will simply use:
<cfoutput>
<h2>#session.language.db_error_msg#</h2>
</cfoutput>
and I will get the right message for the current language.
You can also use a master definition db to be used by different websites.
Same solution can be used with different configuration files (ie US.cfg. EN.cfg, ES.cfg) where you set your definitions in simple way to get a list.
I usually use the following system:
definition_name = definition_value for each line
db_error_msg = Sorry, an error occured saving your data
db_success_msg = Record saved
Then I read the current language configuration file (i.e. US.cfg for english, ES.cfg for spanish) and get the same result
<cfif IsDefined("session.language") IS FALSE>
<cffile action="read" file="#path#\US.cfg" variable="definitions">
<cfset session.language = structnew()>
<cfloop index="i" list="#definitions#" delimiters="#chr(10)#">
<cfset definition_name = ListGetAt(i,1,"=")>
<cfset definition_value = ListGetAt(i,2,"=")>
<cfoutput>
<cfset session.language["#definition_name#"] = "#definition_value#">
</cfoutput>
<cfloop>
</cfif>
This can be done just when session starts (if you know the language you need) and in both ways your definitions will be available everywhere inside your application for the user session time duration you have defined.
You can use definitions for buttons, messages, table headers, etc. creating a multilanguage ui in a very fast way without creating localized templates or using inline translations.
I hope this will help you.
Just as some generic localization advice, be careful about the variable name you'll use to know which phrase to retrieve. Don't just make it the english phrase, but make it something that is clearly a specific variable because you'll also have to handle contextual phrases that seem the same in English, but are very different in other languages depending on context.

java.lang.OutOfMemoryError when saving a huge amount of records

I have a problem with saving a huge amount of records to database using CFWheels. Here is an example:
<cfloop from="1" to="10000" index="i">
<cfset var newUser = model("user").new()>
<cfset newUser.name = "Test"&i>
<cfset newUser.save()>
</cfloop>
This causes java.lang.OutOfMemoryError
Please help me how to solve this problem.
Looping over multiple database calls leading to OOM is a known ColdFusion bug. Fortunately, there is a workaround, use <cfthread/>. You should be able to alter your code as such:
<cfloop from="1" to="10000" index="i">
<cfset threadName = "thread" & createUuid()>
<cfthread name="#threadName#">
<cfset var newUser = model("user").new()>
<cfset newUser.name = "Test"&i>
<cfset newUser.save()>
</cfthread>
<cfthread action="join" name="#threadName#">
</cfloop>
In this situation, you're using the thread solely for its side effect, running in a different context so that it doesn't get retained on the heap. Thus the immediate join right after declaring the thread, so it's not actually running anything in parallel.
You can try to run the Garbage collector:
http://www.beetrootstreet.com/blog/index.cfm/2009/6/25/Clearing-ColdFusion-memory-using-garbage-collection-when-memory-gets-low
There are a couple fairly inefficient things going on here. First, it's generating 1,000 user objects, which isn't really a good idea to do in a single request in ColdFusion. Second, it's running 1,000 database queries, which isn't really a good idea to do in any programming language.
I would stop using model objects for a case like this and figure out how to condense the logic into a single database query. The ORM stuff in Wheels is generally very useful, but it has its limits in situations like this one.
For example, if you're using SQL Server 2008, you can do this inside your user model to keep everything under a single call to cfquery:
<cffunction name="batchCreate">
<cfquery datasource="#get('dataSourceName')#">
INSERT INTO
#this.tableName()# (#this.columnNameForProperty("name")#)
VALUES
<cfloop from="1" to="10000" index="i">
(<cfqueryparam cfsqltype="cf_sql_varchar" value="Test#i#">)
<cfif i lt 10000>,</cfif>
</cfloop>
</cfquery>
</cffunction>
Of course, the query will look different if you're using MySQL or another database engine.