How can I insert an expiration date into a table and having messages expire without breaking functionality? - coldfusion

I’m using Coldfusion 9,0,0,251028 on Windows 7 64-bit, with a Microsoft Access 97 database.
The code is for an application that takes a submitted message from a form and posts it to a different page (breakingnews.cfm). The form values are inserted into the "news" table on a database, including the date the message was submitted (mes_dat) and the date it should expire (exp_dat).
On the database, the is_current and display columns have a default value of 0.
The form action is new_process.cfm, which does two things:
1) Does <cfset expdate = createdate(end_year, end_month, end_day)>. End_year, end_month, and end_day are dropdown selectors that set the expiration date. A problem I have had is expdate not being able to be inserted by post_breaking.cfm, but only when it is put online, on my local testing server there seems to be no problem.
2) Includes a template named "post_breaking.cfm", which runs these queries:
<cfquery name="get_init_info" datasource="#db#">
select id
from news
where is_current = 1
</cfquery>
<cfquery name="update_info_1" datasource="#db#">
update news
set is_current = 0, scrollshow = 0
</cfquery>
<cfif get_init_info.recordcount NEQ 0>
<cfquery name="update_info_2" datasource="#db#">
update news
set display = 1
where id = #get_init_info.id#
</cfquery>
</cfif>
<cfquery name="put_in_info" datasource="#db#">
insert into news
(is_current, display, mes_dat,mes_tim,mes_sub,mes_text,scrollshow, exp_dat)
values
(1,0, #createodbcdate(now())#, #createodbctime(now())#, '#subject#', '#message#',1, #expdate#)
</cfquery>
The message is then displayed on breakingnews.cfm if the column is_current on the news table is 1. This is code I have inherited, so I'm not sure how it does it, but the code only allows 5 messages at a time to have is_current = 1.
The part I'm trying to make happen is having a query run when breakingnews.cfm loads that checks if exp_dat is between now() and mes_dat to set is_current to 1, while still maintaining only 5 items having an is_current of 1.
When breakingnews.cfm is accessed it runs these queries:
<cfquery name="get_info" datasource="#db#">
select *
from news
where
<cfif not isdefined("id")>
is_current = 1
<cfelse>
id = #id#
</cfif>
order by mes_dat desc, mes_tim desc
</cfquery>
<cfquery name="add_exp" datasource="#db#">
UPDATE news
SET is_current = 1
WHERE now() BETWEEN mes_dat AND exp_dat
</cfquery>
<cfquery name="remove_exp" datasource="#db#">
UPDATE news
SET is_current = 0
WHERE now() NOT BETWEEN mes_dat AND exp_dat
</cfquery>
This will cause the messages that have an exp_dat between now() and mes_dat to be displayed and otherwise not display on breakingnews.cfm.
However, when a new message is submitted, upon accessing breakingnews.cfm the first time, only the newly submitted message is displayed.
If the page is refreshed, the messages that were filtered correctly will be displayed under the new message, but there will now be six items displaying on the page when there should only be five.
How can I get the correct amount of messages, and have them display the first time without needing a refresh?
I've gotten advice to replace the get_init_info query with
<cfquery name="get_init_info" datasource="#db#">
select id
from news
where exp_dat > now()
</cfquery>
but that caused all other rows in is_current and scrollshow to be changed to 0 after creating a new message (though the new message's scrollshow and is_current are 1).

My fist thought is to change how the system gets the news to display, but since you sppear not to have control of that, here's my suggestion. Please bear in mind that I've never used Access, so I'm using MS-SQ syntax.
Get the ids of the 5 items you want
select top 5 id
from bews
where exp_date > #createodbcdate(now)#
and display = 1
Now, set display = 0 on all items.
Finally, re-display the ids you found earlier.
update news
set display = 1
where id in #valuelist(query, "id")
If you have questions or corrections, feel free to comment.

Related

how can I check if a record already in database before submitting form in ColdFusion applications

<cfquery datasource = "myDb" name = "compare">
select *
from users
where cnic = #form.cnic#
</cfquery>
<cfif compare.cnic eq form.cnic>
<p> *CNIC already Exists </p>
</cfif>
I think you're misstating the problem. It should be more like,
"How can I show a form to add a record I know is not in the database?"
Please clarify if that is not the case.
Based on your code, I assume there's been a form submission from another page already. You're running a query to see if there is a record in the users table where cnic = #form.cnic#. If there was no previous form submission, then form.cnic wouldn't exist.
<cfquery datasource="myDb" name="compare">
select *
from users
where
cnic = #form.cnic#
</cfquery>
So when this page loads, you've done your "check if a record is already in the database" with the query named compare. Now all you need to do is check if there are 0 records in the query.
<cfif compare.recordcount EQ 0>
<!--- Display form here. ---->
</cfif>
If the query returns any records, then there is at least one record in the database, so no need to show the form or allow it to be submitted.
You can use bellow code in Jquery ajax calling
<cfquery datasource = "myDb" name = "compare">
select *
from users
where cnic = #form.cnic#
</cfquery>
<cfif compare.recordcount GT 0>
<p> *CNIC already Exists </p>
</cfif>
Depending on your database, too, there are other options. MySQL has some features for INSERT ON DUPLICATE KEY UPDATE (https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html)
In MSSQL you can do:
IF NOT EXISTS (SELECT 1 FROM [users] u WITH (NOLOCK) WHERE cnic = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.cnic#")
INSERT INTO [users].....
(My cfsqltype syntax might not be 100% correct, but always use . Always.
Those might give you some other ways to handle your scenario.

Issue with ColdFusion Query of Query after upgrading ColdFusion server from CF9 to CF21

I cannot figure this out. My company recently upgraded our ColdFusion Server from CF9 to CF2021. One of my pages uses queries of queries to run. Prior to the upgrade the page worked fine. However after the upgrade the query of query where statement is not returning any results. Even though the original query has the data. The data is coming from DB2 data source in case that changed with the new version.
<cfquery name = "query_data_sample" dbtype="query">
SELECT
SAMPLE_DATE
, SAMPLE_NBR
, SAMPLE_MISC_NBR
, SUM (RECD_QTY) AS TTL_RECD_QTY
, SUM (MISC_QTY_1) AS TTL_MISC_QTY_1
, SUM ( 1 ) AS TTL_COUNT
FROM original_query_result
WHERE 1=1
AND SAMPLE_DATE = <cfqueryparam value = "#original_query_result.SAMPLE_DATE#" cfsqltype = "CF_SQL_DATE">
AND SAMPLE_NBR = <cfqueryparam value = "#trim(original_query_result.SAMPLE_NBR)#" cfsqltype = "CF_SQL_CHAR">
AND SAMPLE_MISC_NBR = <cfqueryparam value = "#trim(original_query_result.SAMPLE_MISC_NBR)#" cfsqltype = "CF_SQL_CHAR">
GROUP BY
SAMPLE_DATE
, SAMPLE_NBR
, SAMPLE_MISC_NBR
</cfquery>
When I comment out the AND statements and dump out the above query I can see the output of the original_query_result with all the TTL values and Sample rows. However if I want to grab just one row with the AND statements then the query comes back as not finding the row. I am doing a cfoutput query = original_query_result and trying to get the total quantity to display on each row in my output grid table.
Any help would be greatly appreciated. I have been trying to figure this out for more then a week now.
I saw something similar a while back and found this post:
https://web.archive.org/web/20180210052449/http://blog.dkferguson.com/index.cfm/2010/2/17/Using-Querie-of-Queries-with-CFDirectory
Basically I had to CAST the date and use cfqueryparam (as you are):
SAMPLE_DATE = CAST(<cfqueryparam value="#original_query_result.SAMPLE_DATE#" cfsqltype="CF_SQL_DATE"> AS date)
The post said they had to cast both sides but I didn't find this.

ColdFusion cfset issue

I am new to ColdFusion. Anyone know why this code is not working. When I leave the form null it is not showing 100 in the database.
<cfif isdefined("FORM.Percentage")>
<cfset Form.Percentage = #Form.Percentage#>
<cfelse>
<cfset Form.Percentage = 100>
</cfif>
<cfquery name="percent" datasource ="abc">
Insert into Employees
(Percentage)
Values
(#Form.Percentage#)
</cfquery>
If you have a textbox it is submitted to the form even if it's left blank, so you want to check if the field was left blank. If it was then you can set the default.
You'll also want to do some server side validation that the value is a number and use cfqueryparam for inserting your value into the database.
<cfif NOT len(trim(FORM.Percentage))>
<cfset Form.Percentage = 100>
<cfif>
<cfquery result="percent" datasource="abc">
Insert into Employees (Percentage)
Values (
<cfqueryparam cf_sql_type="cf_sql_integer" value="#Form.Percentage#">
)
</cfquery>
When using cfquery with an INSERT the name attribute doesn't provide anything. Using result would allow you to view some data about the query if needed, but generally it shouldn't be used.
You could also have dumped form to the screen by using <cfdump var="#form#"> to see what it was returning. If you want to check that the key exists for a radio button or checkbox you can use structKeyExists(form,'myCheckbox') rather than using isDefined().

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.

can't define id ColdFusion

here is my ColdFusion code:
Example1:
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT PRODUCT_CATID
FROM PRODUCT_CAT
WHERE PRODUCT_CATID = PRODUCT_CATID
</cfquery>
#get_brand.product_catid#
But it shows all the time number 1, i just can't understand why, and how do i make it work properly, this code should have defined the brand_id, but instead shows 1.
The system is Workcube.
Here is my example for getting from the static product's id, its dynamic price:
Example 2:
<cfset product_id = 630>
<cfquery name="price_standart" datasource="#dsn3#">
SELECT
PRICE_STANDART.PRICE PRICE
FROM
PRICE_STANDART
WHERE
PRICE_STANDART.PRODUCT_ID =
<cfqueryparam value="#product_id#" cfsqltype="cf_sql_integer">
</cfquery>
But this time i need to get from dynamic product's ID its dynamic brand id.
This script works the same way as the Example 1:
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT BRAND_ID
FROM PRODUCT_BRANDS
WHERE BRAND_ID = BRAND_ID
</cfquery>
#get_brand.BRAND_ID#
As Andreas shows in his code, your query isn't going to work as written. The statement WHERE PRODUCT_CATID = PRODUCT_CATID doesn't actually pass a value - it would actually just be self-referential within the table values. In this case, it would return everything in the table.
You should instead have:
WHERE PRODUCT_CATID = #PRODUCT_CATID#
Where #PRODUCT_CATID# represents a variable. Better yet, use cfqueryparam as Andreas shows (this prevents SQL injection and improves query performance). However, I am not even sure that is what you intend since if you have the product ID why do you need to get it from the database? Instead, I assume you probably want to get the brands from the product in a particular category. Not knowing your table structure, it's hard to write that query for you but it might look something like:
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT PRODUCT.BRAND_ID
FROM PRODUCT
INNER JOIN PRODUCT_CAT
ON PRODUCT.PRODUCT_CATID = PRODUCT_CAT.PRODUCT_CATID
WHERE PRODUCT_CATID = <cfqueryparam cfsqltype="cf_sql_integer" value="#product_catid#">
</cfquery>
Lastly, as both comments indicate, you would need to loop through the results to see all the records returned.
You need to wrap the statement in tags like this.
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT PRODUCT_CATID FROM PRODUCT_CAT WHERE PRODUCT_CATID = PRODUCT_CATID
</cfquery>
<cfoutput query =GET_Brand">
#get_brand.product_catid#
</cfoutput>
It's not very clear what your question really is about, but let me guess:
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT PRODUCT_CATID
FROM PRODUCT_CAT
WHERE PRODUCT_CATID = <cfqueryparam cfsqltype="cf_sql_integer" value="#product_catid#">
</cfquery>
where #product_catid# refers to a variable you defined earlier in your code or received via form or url scope.
<cfloop query="GET_BRAND">
#get_brand.product_catid#<br />
</cfloop>
will show a list of all the product_catid's returned by the query.
It's not too clear what you are after here, but in the queries there are at least 2 problems. First your WHERE clause
WHERE PRODUCT_CATID = PRODUCT_CATID
is like saying
WHERE 1=1
This will return the full recordset. You can see this by adding
<cfdump var="#GET_BRAND#">
under your code to see the query output. I'm guessing this will show all records in the table.
To match just one record you need your WHERE clause to be like
WHERE PRODUCT_CATID = 3
or have the #...# wrapped around the variable you are trying to match to make it dynamic.
Secondly to the query result may be more than one record, and to see any more than the first record you need to loop over the output. One way is to use
<cfoutput query="GET_BRAND">
#BRAND_ID# <br>
</cfoutput>
My guess of what you are after is
<cfset ID_TO_MATCH=3>
<cfquery name="GET_BRAND" datasource="#dsn1#">
SELECT BRAND_ID
FROM PRODUCT_CAT
WHERE PRODUCT_CATID = #ID_TO_MATCH#
</cfquery>
<cfoutput query="GET_BRAND">
#BRAND_ID# <br>
</cfoutput>