ColdFusion: cfqueryparam for binary values - coldfusion

I wrote the below query based on the help provided in this link, querying binary column using like in sql server
SELECT * FROM myTable
WHERE TestData >= 0x00010000
AND TestData < 0x00020000;
It returned the expected results. I used cfqueryparam and updated the query as:
SELECT * FROM myTable
WHERE TestData >= <cfqueryparam value="0x00010000" cfsqltype="cf_sql_binary">
AND TestData < <cfqueryparam value="0x00020000" cfsqltype="cf_sql_binary">;
but it returned with errors, Error Message: Invalid data 0x00010000 for CFSQLTYPE CF_SQL_BINARY.
I tried with cfsqltype="CF_SQL_BLOB" but no results.
How to fix this issue? Thanks in advance

As it stands, there's nothing inherently wrong with keeping the query as:
SELECT * FROM myTable
WHERE TestData >= 0x00010000 AND TestData < 0x00020000
(You should ideally be listing individual columns rather than using * though.)
However, whilst there is no security benefit to parameterising these queries (they have no variables and thus are not prone to SQL injection), there may still be a benefit of having parameterised SQL for the purpose of caching a single execution plan.
If you have multiple queries, of the form:
<cfquery...>
SELECT * FROM myTable
WHERE TestData >= 0x00010000 AND TestData < 0x00020000
</cfquery>
<cfquery...>
SELECT * FROM myTable
WHERE TestData >= 0x00020000 AND TestData < 0x00030000
</cfquery>
<cfquery...>
SELECT * FROM myTable
WHERE TestData >= 0x00030000 AND TestData < 0x00040000
</cfquery>
Using cfqueryparam for these would allow a single execution plan to be cached for the multiple queries, potentially leading to better performance.
In this situation, you need to use BinaryDecode to convert your hex string into a binary value that cfqueryparam can handle, like so:
<cfquery...>
SELECT * FROM myTable
WHERE TestData >= <cfqueryparam value=#BinaryDecode('00010000','Hex')# cfsqltype="cf_sql_binary" />
AND TestData < <cfqueryparam value=#BinaryDecode('00020000','Hex')# cfsqltype="cf_sql_binary" />
</cfquery>
(Note that the 0x prefix is ommitted.)

Related

Compare a date in CFQUERY to current month

I am running a cfquery to pull records from a table:
<cfquery name="get_followups_monthly" datasource="#datasource#">
SELECT
a.DisplayName
, count(*) AS requested_count
FROM
users AS a
INNER JOIN
ticket_followup b ON b.requested_by = a.displayName
WHERE
a.active = 1 AND b.date_of_followup_request < '2022-02-01'
GROUP BY
a.DisplayName
ORDER BY requested_count DESC
</cfquery>
I would like to compare the dates returned in column b.date_of_followup_request to see if falls within the current month.
I looked through the builtin functions but don't see anything for that. How can this be accomplished?

Using Spreadsheet in Query of Queries

I am reading a spreadsheet any trying to then run it in a query or Queries
<cfspreadsheet action="read"
src="#request.dropfolder##arguments.DSN#"
name="qryFromFile"
excludeHeaderRow="true"
headerrow="true">
<cfquery name="qryResult" dbtype="query">
SELECT EID
, CAST(#arguments.Config[2]# AS Decimal) AS [Value]
, 0 AS Invalid
, '<li><span><b>Comments:</b></span>' + Comments + ' on <time>' + [Date] + '</time></li>' AS Skyhook
FROM qryFromFile
ORDER BY EID
</cfquery>
Do I have to beild the table piece by piece?
To get CF to stuff the contents into a query, you need to use the "query" attribute, not the "name" attribute
<cfspreadsheet action="read"
src="#request.dropfolder##arguments.DSN#"
query="qryFromFile"
excludeHeaderRow="true"
... >

How to order a query by values in different columns

I have a recordset named rsProductClass that is returned from a table in the database. It is a very simple SELECT * FROM Table WHERE ProductID = {ID Value Here} and the table is like this:
ProductID | UPPERTIER | LOWERTIER | NATIER | OTHERTIER
1 20 60 10 10
2 10 90 NULL NULL
3 NULL 40 NULL 5
The table may or may not have a value for each of the various tiers.
What I want to do is show to the user which column has the highest value and what the name of that column is. So for example, if you were looking at ProductID 2, then the page should display "This is likely to be a LOWERTIER product"
I need to sort the rsProductClass query in such a way that it returns me a list of columns in that query ordered by the value in each column. I want to treat the NULL values as zeros.
I tried to mess about with doing valuelist() and some ArrayToList() type functions but it crashes on the NULL values. Say I add columns to an array, and then use ArraySort() to get them in some kind of order, I'll get an error saying something like "Position 1 is not numeric" because it has a NULL value.
Is this something that can be done by ColdFusion? I suppose its some sort of pivoting of the recordset which is beyond my ability.
Something like this would work:
<cfquery name="tiers" datasource="...">
SELECT ProductID, UPPERTIER VALUE, 'UPPERTIER' TIER
WHERE UPPERTIER IS NOT NULL
UNION
SELECT ProductID, LOWERTIER VALUE, 'LOWERTIER' TIER
WHERE LOWERTIER IS NOT NULL
UNION
SELECT ProductID, OTHERTIER VALUE, 'OTHERTIER' TIER
WHERE OTHERTIER IS NOT NULL
UNION
SELECT ProductID, NATIER VALUE, 'NATIER' TIER
WHERE NATIER IS NOT NULL
ORDER BY ProductID, VALUE
</cfquery>
<cfset productGroup = StructNew()>
<cfoutput query="tiers" group="ProductID">
<cfset productGroup[ProductID].TIER = TIER>
<cfset productGroup[ProductID].VALUE = VALUE>
</cfoutput>
<cfdump var="#productGroup#">
Starting with ColdFusion 10 you can use <cfloop query="..." group="...">, before that <cfoutput> must be used.
If you're willing to unpivot your query, you might do something like the following. I used COALESCE() instead of ISNULL() (either one works in this situation, but COALESCE() is the ANSI standard). The column tier_rank will give the rank of the given tier -- that is, the tier with the highest value will have a rank of 1. If there are two tiers that both have the highest value, then both will have a value in tier_rank of 1 (this is why you would use RANK() instead of ROW_NUMBER() -- you could also use DENSE_RANK() if it better fits your requirements):
SELECT p1.product_id, p1.tier_name, p1.tier_value
, RANK() OVER ( PARTITION BY p1.product_id ORDER BY p1.tier_value DESC ) tier_rank
FROM (
SELECT product_id, 'UPPERTIER' AS tier_name
, COALESCE(uppertier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'LOWERTIER' AS tier_name
, COALESCE(lowertier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'NATIER' AS tier_name
, COALESCE(natier, 0) AS tier_value
FROM products
UNION ALL
SELECT product_id, 'OTHERTIER' AS tier_name
, COALESCE(othertier, 0) AS tier_value
FROM products
) p1
Please see SQL Fiddle demo here.
It might be possible to re-pivot the above unpivoted query, but I must admit my attempts at doing so failed.
I had to do something similar to this recently and looked into UNPIVOT in SQL Server. Going with the suggestion to Unpivot your query like David said, you could do something like this. This doesn't add RANK column, but it does order the values.
SELECT ProductID, Tier, TierValue
FROM
(SELECT ProductID, ISNULL(UpperTier,0) UpperTier, ISNULL(LowerTier,0) LowerTier, ISNULL(NaTier,0) NaTier, ISNULL(OtherTier,0) OtherTier
FROM products) p
UNPIVOT
(TierValue FOR Tier IN
(UpperTier, LowerTier, NaTier, OtherTier)
)AS unpvt
ORDER BY ProductID, TierValue Desc
SQL FIDDLE

Using cfqueryparam with constants

We religiously use cfqueryparam in our SQL queries.
Some of my predecessors seem to have been a little overzealous when using it with direct values rather than variables.
Isn't
record_is_deleted_bt = <cfqueryparam cfsqltype="cf_sql_bit" value="0">
overkill? I mean, there's no chance for SQL injection and I don't think that using a bind variable here does anything helpful vis-à-vis improving performance in the database. Wouldn't it be just as reasonable to do
record_is_deleted_bt = 0
?
Is there any advantage to using cfqueryparam in such an instance, besides ingraining the habit of using it? Is there a disadvantage?
No, this is not overkill. cfqueryparam's first job is data binding. It helps in sql injection prevention is just the add-on bonus. The prepared statements through data binding execute faster. You are wrong to assume that it is there to help on sql attack prevention only.
Important Note:
I am adding Test case provided by #Dan Bracuk on an oracle db.
<cfquery name="without" datasource="burns">
select count(*)
from burns_patient
where patientid = 1
</cfquery>
<cfquery name="with" datasource="burns">
select count(*)
from burns_patient
where patientid = <cfqueryparam cfsqltype="cf_sql_integer" value="1">
</cfquery>
<cfscript>
TotalWithout = 0;
TotalWith = 0;
</cfscript>
<cfloop from="1" to="1000" index="i" step="1">
<cfquery name="without" datasource="burns" result="resultwithout">
select count(*)
from burns_patient
where patientid = 1
</cfquery>
<cfquery name="with" datasource="burns" result="resultwith">
select count(*)
from burns_patient
where patientid = <cfqueryparam cfsqltype="cf_sql_integer" value="1">
</cfquery>
<cfscript>
TotalWithout += resultwithout.executiontime;
TotalWith += resultwith.executiontime;
</cfscript>
</cfloop>
<cfdump var="With total is #TotalWith# and without total is #TotalWithout#.">
The with total ranges from 700 to 900 total milliseconds. The without total ranges from 1800 to 4500 milliseconds. The without total is always at least double the with total.

Coldfusion 2 queries comparison

I have 2 Query object in Coldfusion now I want to create a small report on account of these 2 queries
queries may look like
Q1
ID CODE NAME ACTIVE
and
Q2
CODE PRICE BOOKABLE
The code CODE
field is common key between these 2 queries. Now I want to get records are that are in Q1 but not in Q2 and vice versa, how many recodes are common in both queries where CODE is unique.
<cfquery name="Q1" datasource="test">
select * from users where code not in (select code from system)
</cfquery>
<cfquery name="Q2" datasource="test">
select * from system where code not in (select code from users)
</cfquery>
you can use QoQ to solve this.
<cfquery name="Q1" datasource="test">
select * from table1
</cfquery>
<cfquery name="Q2" datasource="test">
select * from table2
</cfquery>
<cfset q1code = valuelist(q2.code,"," )>
<cfset q2code = valuelist(q1.code,"," )>
<cfquery name="q3" dbtype="query" >
select * from q1 where code Not in(#q1code#)
</cfquery>
<cfquery name="q4" dbtype="query" >
select * from q2 where code Not in(#q2code#)
</cfquery>
<cfquery name="q5" dbtype="query" >
select * from q1,q2 where q1.code = q2.code
</cfquery>
Agree with other people, make the DB do the work. If these are in the same db, then you do this to get the records common to both tables:
SELECT Q1.ID
,Q1.CODE
,Q1.NAME
,Q1.ACTIVE
,Q2.PRICE
,Q2.BOOKABLE
FROM Q1, Q2
WHERE Q1.CODE = Q2.CODE
In order to do the first part of your question .. get the records that are in Q1 but not in Q2, you can do that with an outer_join if I am understanding you correctly. Syntax is different for all db's on doing outer joins. I always have to go look it up, so I'm not going to write it here.
another option is to union the two tables, and let cold fusion pull the reports on column_name = ''
select * from Q1 UNION SELECT * FROM Q2
-- you can't actually do this (select *) because of duplicate 'code' column in both dbs.
you'll have to specify the columns explicitly and rename the first one to Q1Code, then Q2Code.
then in CF you do
<cfif q2Code EQ ''> print Q1: #Q1CODE# <cfelse> print Q2: #Q2CODE# </cfif>
or maybe you want:
<cfif q1code EQ Q2code> yay they match</cfif>