Using Spreadsheet in Query of Queries - coldfusion

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"
... >

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?

Distinct QoQ automatically applying order by

I am using CFSpreadsheet to read a .xlsx file.
The file has about 3000 duplicates which I can safely ignore so I thought I'd do a select distinct QoQ but once I do this, the results are ordered as if order by col_1, col_2 was added to the query which is a very bad thing.
<cfspreadsheet query = "qSheet" ...>
<cfquery dbtype="query" name = "qDistinctSheet">
select distinct
col_1
, col_2
from
qSheet
</cfquery>
<cfdump var = "#qDistinctSheet#">
If I remove distinct I get the expected results which SHOULD be:
[empty string]
Name
John
John
Adam
Steve
Bob
Bob
When I add distinct I get
[Empty String]
Adam
Bob
John
Name
Steve
Any idea how to prevent this unwanted ordering?
Edit
End solution is to apply a row number and use group by as suggested by Matt and Dan
<cfset ids = []>
<cfloop query="qSheet">
<cfset ids[qSheet.currentRow] = qSheet.currentRow>
</cfloop>
<cfset queryAddColumn(qSheet,"id",ids)>
<cfquery dbtype="query" name="qDistinct">
SELECT
col_1
, col_2
, min(ID) AS firstID
FROM
qSheet
GROUP BY
col_1
, col_2
ORDER BY
firstID
</cfquery>
You can use a GROUP BY option instead and use the ID row from the spreadsheet query
<cfquery dbtype="query" name="qDistinct">
SELECT
col_1
, col_2
, min(ID) AS firstID
FROM
qSheet
GROUP BY
col_1
, col_2
ORDER BY
firstID

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: cfqueryparam for binary values

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.)

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>