我怎样才能在另一个查询中正确地使用 CFLoop 查询?
How can I CFLoop a query in another query correctly?
Background/Purpose: 我正在创建一个包含 SQL 的 coldfusion 文档,用于从我公司的数据库中获取值。我正在查找我们团队中每位销售代表的转化率(已售出的许可证/已注册)。每个代表都有一个与用户关联的 ID (RegionalDirectorID
) 以帮助跟踪。
Question/Problem: 问题是我们还有其他员工在这里或那里销售许可证,例如我们的 CEO、首席开发人员等。我们有 8 个销售代表UserType
为 8。我正在使用另一个查询 select 那些 UserTypes,以区别于其他人,这样我们的数据就不会混淆 selecting 他们。
正如您在下面看到的,我正在使用 cfloop 循环遍历 getUsers
查询,特别是帮助行 (Users.RegionalDirectorID = #getUsers.UserID#)
打印出我们销售代表的所有 ID。 当我没有输入 cfloop 时,我只有一行显示一位销售代表。如果我有 cfloop,我会得到最后的销售代表。
代码:
<cfset myQuery = QueryNew("ID, ConversionRate")>
<cfquery name="getUsers" datasource="#dsn#">
Select UserID FROM USERS WHERE
UserTypeID = 8
AND ISACTIVE = 1
</cfquery>
<cfquery name="getREGRD" datasource="#dsn#">
Select COUNT(DISTINCT(Users.UserID)) AS TOTALREG, RegionalDirectorID
FROM Users
WHERE UserTypeID = 3
<!--- <cfloop query="getUsers">
AND (Users.RegionalDirectorID = #getUsers.UserID#)
</cfloop>--->
AND (PARENTID IS NULL OR PARENTID = 0)
<cfif len(selectMonth)>
AND MONTH(Users.DateStamp) = #selectMonth#
<cfelse>
AND MONTH(Users.DateStamp) = #MONTH(NOW())#
</cfif>
GROUP BY Users.RegionalDirectorID
</cfquery>
<cfquery name="getREGRDSold" datasource="#dsn#">
Select COUNT(DISTINCT(UserTractLicense.UserID)) AS TOTALSOLD, Users.RegionalDirectorID
FROM Users, UserTractLicense
WHERE Users.UserID = UserTractLicense.UserID
AND Users.UserTypeID = 3 AND
(PARENTID IS NULL OR PARENTID = 0)
<cfif len(selectMonth)>
AND MONTH(Users.DateStamp) = #selectMonth#
<cfelse>
AND MONTH(Users.DateStamp) = #MONTH(NOW())#
</cfif>
GROUP BY Users.RegionalDirectorID
</cfquery>
<!---<cfset newRow = QueryAddRow(myQuery, #getREGRD.RecordCount#)>
<cfloop query="getREGRD">
<cfset QuerySetCell(myQuery, "ID", #getREGRD.RegionalDirectorID#, getREGRD.currentRow) />
</cfloop>
<cfloop query="getREGRDSold">
<cfset QuerySetCell(myQuery, "ConversionRate", #getREGRDSold.TOTALSOLD#/#getREGRD.TOTALREG#, getREGRDSold.currentRow) />
</cfloop>
--->
<!---<cfdump var="#myQuery#">--->
<cfdump var="#getREGRD#">
<cfdump var="#getREGRDSold#">
<cfoutput query="getREGRDSold">
#getREGRDSold.RegionalDirectorID#
</cfoutput>
cfloop 导致 newQuery 发出以下错误。这就是为什么其中一些被注释掉的原因:
An error occurred while evaluating the QueryAddRow function: Parameter> 2, 0, of the QueryAddRow function must be a positive integer.
The
error occurred on line 70.
结果数据中有一些 RegionalDirectorID 的 UserTypeID 不是 8,例如 NULL 单元格,我想将其从查询结果中删除。
听起来您只需要一个 JOIN,而不是所有额外的循环和查询。
如果 Users
table 商店 同时 客户和销售代表,您将需要 self join. In other words, join the Users
table to itself by using aliases。然后根据适当的用户类型过滤每一个。像这样:
SELECT cust.RegionalDirectorID
, COUNT(DISTINCT(lic.UserID)) AS TOTALSOLD
FROM Users cust
INNER JOIN Users sales ON sales.UserID = cust.RegionalDirectorID
INNER JOIN UserTractLicense lic ON lic.UserID = cust.UserID
<!--- customers --->
WHERE cust.UserTypeID = 3
<!--- sales reps --->
AND sales.UserTypeID = 8
... etcetera
GROUP BY cust.RegionalDirectorID
其他一些评论:
虽然在技术上并不总是需要,但当查询涉及多个 table 时,完全限定 所有 列名是一个很好的做法。
同理,一定要确定所有变量的范围。例如,使用 FORM.selectMonth
或 URL.selectMonth
而不是 selectMonth
.
始终对所有可变查询参数使用 cfqueryparam
。最重要的原因是保护您的数据库免受 sql 注入。它还有助于提高多次执行查询的性能。
MONTH(Users.DateStamp) = #selectMonth#
我注意到查询只过滤月数(不是月 和 年)。因此,如果 selectedMonth = 8,查询将为 "August" 月份的 return 结果 - any 年。那是你的意图吗?如果没有,您显然也想添加一个年份过滤器。但是,在索引列上使用函数通常会阻止数据库使用索引。所以你可以考虑使用 this paradigm which is more index friendly:
WHERE TheDateColumn >= TheStartDateAtMidnight
AND TheDateColumn < TheDayAfterEndDateAtMidnight
Background/Purpose: 我正在创建一个包含 SQL 的 coldfusion 文档,用于从我公司的数据库中获取值。我正在查找我们团队中每位销售代表的转化率(已售出的许可证/已注册)。每个代表都有一个与用户关联的 ID (RegionalDirectorID
) 以帮助跟踪。
Question/Problem: 问题是我们还有其他员工在这里或那里销售许可证,例如我们的 CEO、首席开发人员等。我们有 8 个销售代表UserType
为 8。我正在使用另一个查询 select 那些 UserTypes,以区别于其他人,这样我们的数据就不会混淆 selecting 他们。
正如您在下面看到的,我正在使用 cfloop 循环遍历 getUsers
查询,特别是帮助行 (Users.RegionalDirectorID = #getUsers.UserID#)
打印出我们销售代表的所有 ID。 当我没有输入 cfloop 时,我只有一行显示一位销售代表。如果我有 cfloop,我会得到最后的销售代表。
代码:
<cfset myQuery = QueryNew("ID, ConversionRate")>
<cfquery name="getUsers" datasource="#dsn#">
Select UserID FROM USERS WHERE
UserTypeID = 8
AND ISACTIVE = 1
</cfquery>
<cfquery name="getREGRD" datasource="#dsn#">
Select COUNT(DISTINCT(Users.UserID)) AS TOTALREG, RegionalDirectorID
FROM Users
WHERE UserTypeID = 3
<!--- <cfloop query="getUsers">
AND (Users.RegionalDirectorID = #getUsers.UserID#)
</cfloop>--->
AND (PARENTID IS NULL OR PARENTID = 0)
<cfif len(selectMonth)>
AND MONTH(Users.DateStamp) = #selectMonth#
<cfelse>
AND MONTH(Users.DateStamp) = #MONTH(NOW())#
</cfif>
GROUP BY Users.RegionalDirectorID
</cfquery>
<cfquery name="getREGRDSold" datasource="#dsn#">
Select COUNT(DISTINCT(UserTractLicense.UserID)) AS TOTALSOLD, Users.RegionalDirectorID
FROM Users, UserTractLicense
WHERE Users.UserID = UserTractLicense.UserID
AND Users.UserTypeID = 3 AND
(PARENTID IS NULL OR PARENTID = 0)
<cfif len(selectMonth)>
AND MONTH(Users.DateStamp) = #selectMonth#
<cfelse>
AND MONTH(Users.DateStamp) = #MONTH(NOW())#
</cfif>
GROUP BY Users.RegionalDirectorID
</cfquery>
<!---<cfset newRow = QueryAddRow(myQuery, #getREGRD.RecordCount#)>
<cfloop query="getREGRD">
<cfset QuerySetCell(myQuery, "ID", #getREGRD.RegionalDirectorID#, getREGRD.currentRow) />
</cfloop>
<cfloop query="getREGRDSold">
<cfset QuerySetCell(myQuery, "ConversionRate", #getREGRDSold.TOTALSOLD#/#getREGRD.TOTALREG#, getREGRDSold.currentRow) />
</cfloop>
--->
<!---<cfdump var="#myQuery#">--->
<cfdump var="#getREGRD#">
<cfdump var="#getREGRDSold#">
<cfoutput query="getREGRDSold">
#getREGRDSold.RegionalDirectorID#
</cfoutput>
cfloop 导致 newQuery 发出以下错误。这就是为什么其中一些被注释掉的原因:
An error occurred while evaluating the QueryAddRow function: Parameter> 2, 0, of the QueryAddRow function must be a positive integer.
The error occurred on line 70.
结果数据中有一些 RegionalDirectorID 的 UserTypeID 不是 8,例如 NULL 单元格,我想将其从查询结果中删除。
听起来您只需要一个 JOIN,而不是所有额外的循环和查询。
如果 Users
table 商店 同时 客户和销售代表,您将需要 self join. In other words, join the Users
table to itself by using aliases。然后根据适当的用户类型过滤每一个。像这样:
SELECT cust.RegionalDirectorID
, COUNT(DISTINCT(lic.UserID)) AS TOTALSOLD
FROM Users cust
INNER JOIN Users sales ON sales.UserID = cust.RegionalDirectorID
INNER JOIN UserTractLicense lic ON lic.UserID = cust.UserID
<!--- customers --->
WHERE cust.UserTypeID = 3
<!--- sales reps --->
AND sales.UserTypeID = 8
... etcetera
GROUP BY cust.RegionalDirectorID
其他一些评论:
虽然在技术上并不总是需要,但当查询涉及多个 table 时,完全限定 所有 列名是一个很好的做法。
同理,一定要确定所有变量的范围。例如,使用
FORM.selectMonth
或URL.selectMonth
而不是selectMonth
.始终对所有可变查询参数使用
cfqueryparam
。最重要的原因是保护您的数据库免受 sql 注入。它还有助于提高多次执行查询的性能。
MONTH(Users.DateStamp) = #selectMonth#
我注意到查询只过滤月数(不是月 和 年)。因此,如果 selectedMonth = 8,查询将为 "August" 月份的 return 结果 - any 年。那是你的意图吗?如果没有,您显然也想添加一个年份过滤器。但是,在索引列上使用函数通常会阻止数据库使用索引。所以你可以考虑使用 this paradigm which is more index friendly:
WHERE TheDateColumn >= TheStartDateAtMidnight AND TheDateColumn < TheDayAfterEndDateAtMidnight