Question

I'm working on a Coldfusion8/MySQL query in which I'm scanning a database for A-B pairs, for example:

 S=2, M=2, L=2, XL=2

I'm trying to improve the script that originally handled this, which limited entries to 4 pairs and because I'm wondering, why it first selects all records with one matching pair and then uses HAVING to only select the records, with all pairs matching.

Here is the original query, afterwards my current version:

<!--- placeholders --->
<cfparam name="s01" default="">
<cfparam name="s02" default="">
<cfparam name="s03" default="">
<cfparam name="s04" default="">
<cfparam name="q01" default="">
<cfparam name="q02" default="">
<cfparam name="q03" default="">
<cfparam name="q04" default="">
<!--- check length of user inputs --->
<cfset sizes = ListLen(s_lot_groesse,",")>
<cfset qtys   = ListLen(s_lot_menge,",")>
<!--- populate placeholders --->
<cfif sizes gt 0><cfset s01 = trim(ListGetAt(s_lot_groesse, 1,","))></cfif>
<cfif sizes gt 1><cfset s02 = trim(ListGetAt(s_lot_groesse, 2,","))></cfif>
<cfif sizes gt 2><cfset s03 = trim(ListGetAt(s_lot_groesse, 3,","))></cfif>
<cfif sizes gt 3><cfset s4 = trim(ListGetAt(s_lot_groesse, 4,","))></cfif>
<cfif qtys gt 0><cfset q01 = trim(ListGetAt(s_lot_menge, 1,","))></cfif>
<cfif qtys gt 1><cfset q02 = trim(ListGetAt(s_lot_menge, 2,","))></cfif>
<cfif qtys gt 2><cfset q03 = trim(ListGetAt(s_lot_menge, 3,","))></cfif>
<cfif qtys gt 3><cfset q04 = trim(ListGetAt(s_lot_menge, 4,","))></cfif>
<!--- query --->
<cfquery datasource="db" name="lotsuche">
SELECT styleno, count(*) as total_styles
FROM styles
WHERE 1 = 1
AND (
    <cfif s01 neq "" AND q01 neq "">(groesse = "#s01#" AND bestand >= "#q01#")</cfif>
    <cfif s02 neq "" AND q02 neq "">OR (groesse = "#s02#" AND bestand >= "#q02#")</cfif>
    <cfif s03 neq "" AND q03 neq "">OR (groesse = "#s03#" AND bestand >= "#q03#")</cfif>
    <cfif s04 neq "" AND q04 neq "">OR (groesse = "#s04#" AND bestand >= "#q04#")</cfif>
    )
GROUP BY styleno
HAVING total_styles= "#sizes#"
</cfquery>

New version:

<!--- build a 2D array --->
<cfscript>
    variables.lotArray = ArrayNew(2);
    variables.sizeCounter = 1;
    variables.qtyCounter = 1;
</cfscript>
<cfloop list="#LOCAL.Search.s_lot_groesse#" delimiters=", " item="size">
    <cfscript>
        variables.lotArray[variables.lotCounter][1] = size;
        variables.lotCounter = variables.lotCounter + 1;
    </cfscript>
</cfloop>
<cfloop list="#LOCAL.Search.s_lot_menge#" delimiters=", " item="qty">
    <cfscript>
        variables.lotArray[variables.qtyCounter][2] = qty;
        variables.qtyCounter = variables.qtyCounter + 1;
    </cfscript>
</cfloop>
<!--- get array length --->
<cfset variables.lotArrayLen = arrayLen(variables.lotArray)>

<!--- query --->
<cfquery datasource="ds" name="lotsuche">
SELECT art.styleNo, count(*) as total_styles
FROM styles AS art
WHERE 1 = 1
<cfloop from="1" to="#variables.lotArrayLen#" index="i">
    AND ( art.groesse = <cfqueryparam cfsqltype="cfsql_varchar" value="#variables.lotArray[i][1]#"> 
    AND art.bestand >= <cfqueryparam cfsqltype="cfsql_varchar" value="#variables.lotArray[i][2]#">
</cfloop>
GROUP BY art.styleno
<!--- HAVING anzahl = "#variables.lotArrayLen#" --->
</cfquery>

Question:
I don't understand why OR and HAVING are being used in the original query, because doesn't this select all records with one matching pair vs just picking the records with all pairs matching? Which approach is better/faster if you have a few million entries to scan? Also, does it make sense to re-factor the whole thing like I did?

Thanks for help!

Was it helpful?

Solution

The HAVING clause is used with aggregate functions and OR is used to test for multiple conditions in a query. I'm not sure of the purpose of the having clause in the old query. Have you thoroughly tested your new query to ensure that your getting expected results?

After looking over the two queries, your second query won't work the same. The two records may have multiple conditions that they need to meet and the query could return an empty recordset.

I think your looking for something more like this.

AND
 <cfloop from="1" to="#variables.lotArrayLen#" index="i">
 (  OR (art.groesse = <cfqueryparam cfsqltype="cfsql_varchar" value="#variables.lotArray[i][1]#"> 
AND art.bestand >= <cfqueryparam cfsqltype="cfsql_varchar" value="#variables.lotArray[i][2]#"> ) )

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top