In coldfusion compare two queries from different databases - coldfusion

How do I compare two queries from two different databases?
<cfquery name="doggyValidationOne" datasource="myDatabaseSource"
select dogType from databaseOne
</cfquery>
<cfquery name="doggyValidationTwo" datasource="myOtherDatabaseSource"
select dogType from databaseTwo
</cfquery>
I need to inform the user that all dogs in database two exist in database one.
I can do this in sql with
select doggy from tableOne minus select doggies from tableTwo
How can I accomplish this in coldfusion 10?
I'm thinking maybe creating a list out of each query and comparing the results, but then I can't display the table row information to the user.

Not in QoQ, but http://www.cflib.org/udf/querycompare or http://www.cflib.org/udf/queryDiff should do the trick.

Related

Why doesn't Lucee consider column alias name in QoQ

I was comparing the following queries in my local CF & Lucee servers. The ColdFusion server throws a QoQ runtime error. However, when I execute the same queries in Lucee, it returns the needed query results.
<cfquery name="getusers" datasource="myDSN">
SELECT
UC.UserContactName, U.UserID
FROM Users U
INNER JOIN UserContacts UC ON U.UserID = UC.UserID
WHERE U.UserID in (99,52,41,76,15)
</cfquery>
<cfquery name="getContactName" dbtype="query">
SELECT UserContactName FROM getusers
WHERE U.UserID = <cfqueryparam value="76" cfsqltype="cf_sql_integer">
</cfquery>
<cfdump var="#getContactName#" />
The CF server throws this error on the above code, because it considers the alias name:
The selected column reference U.UserID does not match any table in the
FROM table list.
However, the Lucee server doesn't consider the alias name, ran runs the above without error. Does anyone know why the Lucee server does not consider the QoQ column alias name? Please share your thoughts or suggestions about this.
The getusers query results in the columns:
UserContactName | UserID
A QoQ on getusers no longer has any table related information stored. If you reference U (as in U.UserID), ACF expects a (new) reference in the QoQ to be able to resolve what U even means.
Lucee on the other hand stores these information and can resolve it using an alias. You can check the source code how it parses the QoQ statement.
Regardless of the capabilities of Lucee, I suggest to remove former aliases in QoQ statements. Consider debugging a QoQ statement when your query dump doesn't even hint you about stored aliases.

Move a row to the beginning of a query

I have a recordset of messages, some of which are are from a group named "ADMIN". I want all the messages from the "ADMINS" placed at the top of the query object but I can't re-order them within the original query -- I have to do it after I already have the query object. I have a way to see which rows are from "ADMINS" but I'm not sure the best way to extract them from the query object and put them at the top.
<!--- this is the query object of all the messages --->
<cfset messageData = application.message.getMessages(inboxID)>
<!--- this returns a list of which users inside the recordset are ADMINS --->
<cfset getAdmins = application.message.getAdmins(valueList(messageData.useridfk)) />
Now I want to take all the UserIDs returned in #getAdmins#, remove the messages that are theirs in #messageData# and put them at the top of #messageData# so I can output the results. Is this a QoQ or is there a better way?
I can't really get my head around the QoQ, but I'm taking a stab at it. IS there a better way then doing THREE different QoQs?
<!--- this gets all the rows from Admins --->
<cfquery name="getAdminAnswers" dbtype="query">
SELECT *
FROM messageData
WHERE useridfk in ('#getAdmins.id#')
ORDER BY UpvotesNum DESC, posted DESC
</cfquery>
<!--- this gets all the rows from non-RDs --->
<cfquery name="getNonAdminAnswers" dbtype="query">
SELECT *
FROM messageData
WHERE useridfk NOT IN ('#getAdmins.id#')
ORDER BY UpvotesNum DESC, posted DESC
</cfquery>
<!--- join the queries with a UNION in a QoQ --->
<cfquery dbtype="query" name="data">
SELECT * FROM getAdminAnswers
UNION
SELECT * FROM getNonAdminAnswers
</cfquery>
Answer:
Got it: Like this:
<!--- this combines two queries into one --->
<cfquery name="data" dbtype="query">
SELECT *, 1 sortCol
FROM messageData
WHERE useridfk in ('#variables.getAdmins.id#')
UNION
SELECT *, 2 sortCol
FROM messageData
WHERE useridfk NOT IN ('#variables.getAdmins.id#')
ORDER BY sortCol, UpvotesNum DESC, posted DESC
</cfquery>
I can't see that there's a more expedient way of doing this without using QoQ, no. It's kinda what it's for: these exceptional circumstances where the app needs both the original data as from the DB, and a variation of it as well.
Can you say
SELECT *,
(CASE WHEN USERIDFK IN ('#getadmins.id#') THEN 1 ELSE 0 END) as mRank
FROM MessagesTableName
ORDER BY mRank DESC, UpvotesNum DESC, posted DESC
That would be the SQL Server Syntax anyway, I'm not sure what SQL flavor you're using.
I realize that all three queries are QoQs, but with just one query to get your admin list, this direct query to the db might work.
(Previously, I was unsure if you could use CASE in QoQ. You can't, so if this works at all, it would have to a direct query to the database.)

How do I use cfqueryparam in ORDER BY to list titles matching "School of " first

How do I use cfqueryparam in the ORDER BY to have titles matching "School of " listed first and then just list the rest of the titles? Here is my current query:
<cfquery name="getblogs" dbType="query">
SELECT title, id,description,date_registered,public1,uri
FROM myquery
where public1<>0
order by title asc
</cfquery>
What syntax do I use filter by "School of" titles first and then the rest can be ordered in ASC.
EDIT: How do I output specific title based on ID matches? I tried this but get an error.
<cfquery name="getschoolblogs" dbType="query">
SELECT id, title, uri
FROM myquery
WHERE id = 396,378
ORDER BY title asc
</cfquery>
One of the way s is like this:
<cfquery name="getblogs" dbType="query">
SELECT title, id,description,date_registered,public1,uri,
CASE left(title, 9) WHEN 'School of' THEN 1 ELSE 2 END as sortIdx
FROM myquery
where public1<>0
order by sortIdx, title asc
</cfquery>
You can do some better variation on the condition, it's just first one that came to mind.
QoQ's are extremely limited. They do not support the operators or functions you would need to alter the natural sort order that way. What you could do is use a CASE in your database query to create an additional sort column. Then sort by it in either your database query OR the QoQ.
SELECT CASE WHEN title LIKE 'School of %' THEN 1
ELSE 2
END AS TitleSortValue
, title id,description,date_registered,public1,uri
FROM YourTable
ORDER BY TitleSortValue, Title ASC
Also, you cannot use cfqueryparam in an ORDER BY clause. cfqueryparam prevents the input from being evaluated as sql. So it can only be used with simple values, not objects (ie table or column names).
where id=396,378
Edit: To answer your later question, you can only compare a single value with =. Use IN (...) to filter on multiple values:
WHERE ID IN ( <cfqueryparam value="#listOfIDValues#"
cfsqltype="cf_sql_integer"
list="true">
)
You don't need to be returning a column you don't need but to get the same result just use a case statement in the order by.
<cfquery name="getblogs" datasource="dsn">
SELECT title, id, description, date_registered, public1, uri
FROM tbl_blogs
WHERE public1<> 0
ORDER BY CASE left(title, 9) WHEN 'School of' THEN 1 ELSE 2 END,
title ASC
</cfquery>
This will avoid returning data you don't need.

Is there a way to escape and use ColdFusion query reserved words as column names in a query of query?

I'm working with a query that has a column named "Date."
The original query returns okay from the database. You can output the original query, paginate the original query, get a ValueList of the Date column, etc.
Query of Query
<cfquery name= "Query" dbtype= "query">
select
[Query].[Date]
from [Query]
</cfquery>
Response from ColdFusion
Query Of Queries syntax error. Encountered "Date. Incorrect Select
List,
Typically, I use descriptive names so I haven't run across this issue previously.
In this case, I'm working with a stored procedure that someone else wrote. I ended up modifying the stored procedure to use a more descriptive column name.
I have a service I use for transforming, searching and sorting queries with ColdFusion. I'm curious to know the answer to my original question, so that I can modify my service to either throw a better error or handle reserved words.
Is there a way to escape and use ColdFusion query reserved words as column names in a query of query?
The following code works fine for me:
<cfset query = queryNew("date")>
<cfdump var="#query#">
<cfquery name= "Query" dbtype= "query">
select
[Query].[Date]
from [Query]
</cfquery>
<cfdump var="#query#">
In standard mysql you'd "escape" the fields by using the ` character.
So for example:
select `query`.`date` from `query`
Try that and see if it works?

CFQuery 'WHERE' from results of another query?

I'll explain the 'real life' application of this so it's easier to understand.
I'm working on an eCommerce app that has a category structure. It starts at the top level and gradually moves down through subcategories. For example Home > Electronics > TVs > Plasma
I'm using a single page for this, showing the 'home' page if no category is defined, the subcategories if there are any, and finally the products if there are no subcategories.
This all works fine, however when I get to the 2nd part - displaying subcategories, the page is a little empty. Therefore, I'd like to display a selection of products that span all of the subcategories applicable.
This is where I'm struggling - in most cases, there will be a few subcategories. However, I'm not sure how to structure the 'where' query using the results of the previous query (code snippets below for reference).
I don't believe QofQ would be worth exploring, and I've made a vain attempt at doing something with substrings, without success.
Any pointers much appreciated!
<cfquery name="getcategories">
SELECT p.ID AS CategoryID, p.Cat_Name as CategoryName, p.Cat_Shortname, c.ID AS SubCategoryID, c.Cat_Name as SubCategoryName, c.Cat_Shortname AS SubCatShortname
FROM product_categories p LEFT JOIN product_categories c ON p.ID = c.SubcategoryOf
WHERE p.SubcategoryOf = 0
</cfquery>
<cfif IsDefined('url.cat')>
<!--- Look for additional subcategories --->
<cfquery name="getsubcategories">
SELECT *
FROM product_categories
WHERE Subcategoryof='#url.cat#'
</cfquery>
<cfquery name="getproducts">
SELECT *
FROM products
WHERE categoryid='#url.cat#'
ORDER BY RAND()
</cfquery>
</cfif>
Assuming your products table contains a subcategoryID of some kind you can use the following to get a list of sub category IDs from the query getsubcategories:
<cfset subCategoryIDs = valueList(getsubcategories.subCategoryID) >
This will give you a list of all subCategoryIDs. You can the feed this into the getproducts query like so:
<cfquery name="getproducts">
SELECT *
FROM products
WHERE subCategoryID in (<cfqueryparam cfsqltype="cf_sql_integer" value="#subCategoryIDs#" list="true">)
ORDER BY RAND()
</cfquery>
You should always cfqueryparam your query parameters.
If i understand your database structure, this query should return all products in all subcategories.
<cfquery name="getallproducts">
SELECT *
FROM products p LEFT JOIN product_categories pc ON p.categoryID = pc.ID
WHERE pc.Subcategoryof= <cfqueryparam cfsqltype="cf_sql_integer" value="#url.cat#">
</cfquery>
note: you really do want to use cfqueryparam here.