Coldfusion 动态变量 (?) 解析为 SQL 查询
Coldfusion Dynamic Variable (?) parsed to SQL Query
这是我第一次尝试将变量解析为 CF 查询,但我 运行 遇到了一些小问题。
总而言之,我正在创建运营商每周销售额的枢轴 table。手动,没有麻烦,但我只想要几周的一部分,而不是全部。同样,如果我想要硬编码的周数也没有真正的问题,但是当我尝试将周数解析为 SQL 查询以创建动态周数的子集时,问题就来了。
CFDUMP 告诉我查询是根据我发送给它的内容执行的,但是当涉及到输出字段值(星期)时,它采用变量名称值,而不是字段值(如果有意义的话)?
我知道我不应该将字段名称作为值,但我现在仍在尝试进行测试。通过手动查询,我在周数前加上 'W' 例如W9,但是当我尝试这样做时,我得到
手动查询
SELECT UserName,
ISNULL([W6], 0) AS [W6],
ISNULL([W7], 0) AS [W7],
ISNULL([W8], 0) AS [W8],
ISNULL([W9], 0) AS [W9],
ISNULL([W10], 0) AS [W10]
FROM ( SELECT CASE
WHEN SUBSTRING(Username, 1, 3) = 'd.S' THEN 'DS'
WHEN SUBSTRING(Username, 1, 3) = 'p.R' THEN 'PR'
WHEN SUBSTRING(Username, 1, 3) = 'j.G' THEN 'JG'
WHEN SUBSTRING(Username, 1, 3) = 'b.c' THEN 'BC'
ELSE 'Other' END AS Username,
CONCAT('W', DATEPART(isowk, ERCFullAuditDate)) as XWeek,
COUNT(1) [SalesCount]
FROM [ERC-Transactions].[dbo].[ERC-Audit]
WHERE ( ERCModule = 'Carriage Return on Account'
AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE())
OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE()))
and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE()))))
GROUP BY DATEPART(isowk, ERCFullAuditDate),
UserName) ST
PIVOT ( SUM(SalesCount)
for XWeek in ([W6], [W7], [W8], [W9], [W10])) as StorePivot
以上产生了这个结果。
COLDFUSION 动态查询
现在,当我尝试做同样的事情时,但通过将变量解析为查询,CFDUMP 产生了正确的值,但正如我所说,当我尝试输出它时,我得到的是字段名称而不是值.
老实说,我这里有两个问题需要解决。可变字段名称,而且当我将 'W' 的串联添加到周数时,我看到一个 'Error converting data type nvarchar to int.' 我想我可能需要一个 cfqueryparam,但我不确定。
<cfset WEEK_2 = DATETImeFormat(DateAdd("ww",-2,now()),"w")>
<cfoutput>Week: #WEEK_2#</cfoutput> (This is the value of the WEEK_2 variable)<br>
<cfset XX = "">
<cfset XX = XX & "SELECT UserName, ">
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
<cfset XX = XX & "FROM ( SELECT CASE ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'd.S' THEN 'DS' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'p.R' THEN 'PR' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'j.G' THEN 'JG' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'b.c' THEN 'BC' ">
<cfset XX = XX & "ELSE 'Other' END AS Username, ">
<cfset XX = XX & "DATEPART(isowk, ERCFullAuditDate) as XWeek, ">
<cfset XX = XX & "COUNT(1) [SalesCount] ">
<cfset XX = XX & "FROM [EBS-ERC-Transactions].[dbo].[ERC-Audit] ">
<cfset XX = XX & "WHERE ( ERCModule = 'Carriage Return on Account' ">
<cfset XX = XX & "AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE()) ">
<cfset XX = XX & "OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE())) ">
<cfset XX = XX & "and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE())))) ">
<cfset XX = XX & "GROUP BY DATEPART(isowk, ERCFullAuditDate), ">
<cfset XX = XX & "UserName) ST ">
<cfset XX = XX & "PIVOT ( SUM(SalesCount) ">
<cfset XX = XX & "for XWeek in ([#WEEK_2#])) as StorePivot ">
<cfquery name = "QueryTest" dataSource = "EBSERC">
#PreserveSingleQuotes(XX)#
</cfquery>
<br>
<cfoutput Query="QueryTest">
#UserName#, #WEEK_2#<br>
</cfoutput>
<br>
<cfdump var="#QueryTest#" />
这是结果...
最终,如前所述,我想将 'W' 连接到周数字段。
任何正确方向的指导或指导将不胜感激,感谢您抽出宝贵时间。
非常感谢您的阅读。
如果您尝试完全复制 SQL,我认为您错过了顶部 cfset 中的 'W':
输出:
第 9 周(这是 WEEK_2 变量的值)
你有这个命令:
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
由于 week_2 变量的值为 9,当该命令被执行时,它变成这样:
<cfset XX = XX & "ISNULL([9], 0) AS [9] ">
您的查询变为
select username
, 9 as 9
from etc
您将不得不多加考虑以生成周数。
评论太长了。
由于列标签是动态的并且与数据库密切相关,我可能会在数据库端完成这一切。最好在存储过程中。
如果您使用的是 SQL Server 2017+,则可以使用 CTE 生成所需日期范围内的周数。然后 STRING_AGG() 用于将结果转换为逗号分隔列表。
; WITH dates AS (
-- Generate range between -56 and -52 weeks ago
SELECT DateAdd(wk, -56, GETDATE()) AS WeekDate
UNION ALL
SELECT DateAdd(wk, 1, WeekDate)
FROM dates
WHERE DateAdd(wk, 1, WeekDate) <= DateAdd(wk, -52, GETDATE())
)
, dateLabels AS (
-- extract week number and construct label "W1","W2",etc..
SELECT DATEPART(isowk, WeekDate) AS WeekNum
, QUOTENAME( CONCAT('W', DATEPART(isowk, WeekDate) )) AS WeekLabel
FROM dates
)
-- convert to comma separated lists
SELECT STRING_AGG( WeekLabel, ',')
WITHIN GROUP (ORDER BY WeekNum) AS PivotColumns
, STRING_AGG( CONCAT('ISNULL(', WeekLabel, ',0) AS ', WeekLabel ), ',')
WITHIN GROUP (ORDER BY WeekNum) AS SelectColumns
FROM dateLabels
;
结果看起来像这样(减去任何换行)
PivotColumns
SelectColumns
[W6],[W7],[W8],[W9],[W10]
ISNULL([W6],0) AS [W6],ISNULL([W7],0) AS [W7],ISNULL([W8],0) AS [W8],ISNULL([W9],0) AS [W9],ISNULL([W10],0) AS [W10]
然后只需将这两个列表插入 SQL 查询即可。在 CF 中:
<cfscript>
// ...
sqlString = "
SELECT UserName
, #SelectColumns#
FROM (
...
) ST
PIVOT
(
SUM(SalesCount)
FOR XWeek IN ( #PivotColumns# )
) AS StorePivot
";
qPivot = queryExecute( sqlString );
// ...
</cfscript>
结果:
SELECT UserName
, ISNULL([W6],0) AS [W6]
, ISNULL([W7],0) AS [W7]
, ISNULL([W8],0) AS [W8]
, ISNULL([W9],0) AS [W9]
, ISNULL([W10],0) AS [W10]
FROM (
...
) ST
PIVOT (
SUM(SalesCount)
FOR XWeek IN (
[W6],[W7],[W8],[W9],[W10]
)
) AS StorePivot
WHERE
哦,括号在哪里?
关于原始查询的一些观察:
当前的 WHERE
子句不正确。混合使用AND/OR运算符时,必须使用括号来保证运算顺序。 概念上,当前查询是这样做的:
WHERE Condition1 AND Condition2 OR Condition3
这里应该用括号:
WHERE Condition1 AND ( Condition2 OR Condition3 )
GETDATE() 已经 returns 一个 datetime
值,因此无需在此处再次将其转换为日期时间:
DATEADD(week, -52, convert(datetime, GETDATE()))
最后,不需要所有的串联。字符串通常可以跨越多行,如果需要,总是有 cfsavecontent。删除所有 &
将大大提高可读性。
这是我第一次尝试将变量解析为 CF 查询,但我 运行 遇到了一些小问题。
总而言之,我正在创建运营商每周销售额的枢轴 table。手动,没有麻烦,但我只想要几周的一部分,而不是全部。同样,如果我想要硬编码的周数也没有真正的问题,但是当我尝试将周数解析为 SQL 查询以创建动态周数的子集时,问题就来了。
CFDUMP 告诉我查询是根据我发送给它的内容执行的,但是当涉及到输出字段值(星期)时,它采用变量名称值,而不是字段值(如果有意义的话)?
我知道我不应该将字段名称作为值,但我现在仍在尝试进行测试。通过手动查询,我在周数前加上 'W' 例如W9,但是当我尝试这样做时,我得到
手动查询
SELECT UserName,
ISNULL([W6], 0) AS [W6],
ISNULL([W7], 0) AS [W7],
ISNULL([W8], 0) AS [W8],
ISNULL([W9], 0) AS [W9],
ISNULL([W10], 0) AS [W10]
FROM ( SELECT CASE
WHEN SUBSTRING(Username, 1, 3) = 'd.S' THEN 'DS'
WHEN SUBSTRING(Username, 1, 3) = 'p.R' THEN 'PR'
WHEN SUBSTRING(Username, 1, 3) = 'j.G' THEN 'JG'
WHEN SUBSTRING(Username, 1, 3) = 'b.c' THEN 'BC'
ELSE 'Other' END AS Username,
CONCAT('W', DATEPART(isowk, ERCFullAuditDate)) as XWeek,
COUNT(1) [SalesCount]
FROM [ERC-Transactions].[dbo].[ERC-Audit]
WHERE ( ERCModule = 'Carriage Return on Account'
AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE())
OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE()))
and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE()))))
GROUP BY DATEPART(isowk, ERCFullAuditDate),
UserName) ST
PIVOT ( SUM(SalesCount)
for XWeek in ([W6], [W7], [W8], [W9], [W10])) as StorePivot
以上产生了这个结果。
COLDFUSION 动态查询
现在,当我尝试做同样的事情时,但通过将变量解析为查询,CFDUMP 产生了正确的值,但正如我所说,当我尝试输出它时,我得到的是字段名称而不是值.
老实说,我这里有两个问题需要解决。可变字段名称,而且当我将 'W' 的串联添加到周数时,我看到一个 'Error converting data type nvarchar to int.' 我想我可能需要一个 cfqueryparam,但我不确定。
<cfset WEEK_2 = DATETImeFormat(DateAdd("ww",-2,now()),"w")>
<cfoutput>Week: #WEEK_2#</cfoutput> (This is the value of the WEEK_2 variable)<br>
<cfset XX = "">
<cfset XX = XX & "SELECT UserName, ">
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
<cfset XX = XX & "FROM ( SELECT CASE ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'd.S' THEN 'DS' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'p.R' THEN 'PR' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'j.G' THEN 'JG' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'b.c' THEN 'BC' ">
<cfset XX = XX & "ELSE 'Other' END AS Username, ">
<cfset XX = XX & "DATEPART(isowk, ERCFullAuditDate) as XWeek, ">
<cfset XX = XX & "COUNT(1) [SalesCount] ">
<cfset XX = XX & "FROM [EBS-ERC-Transactions].[dbo].[ERC-Audit] ">
<cfset XX = XX & "WHERE ( ERCModule = 'Carriage Return on Account' ">
<cfset XX = XX & "AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE()) ">
<cfset XX = XX & "OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE())) ">
<cfset XX = XX & "and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE())))) ">
<cfset XX = XX & "GROUP BY DATEPART(isowk, ERCFullAuditDate), ">
<cfset XX = XX & "UserName) ST ">
<cfset XX = XX & "PIVOT ( SUM(SalesCount) ">
<cfset XX = XX & "for XWeek in ([#WEEK_2#])) as StorePivot ">
<cfquery name = "QueryTest" dataSource = "EBSERC">
#PreserveSingleQuotes(XX)#
</cfquery>
<br>
<cfoutput Query="QueryTest">
#UserName#, #WEEK_2#<br>
</cfoutput>
<br>
<cfdump var="#QueryTest#" />
这是结果...
最终,如前所述,我想将 'W' 连接到周数字段。
任何正确方向的指导或指导将不胜感激,感谢您抽出宝贵时间。
非常感谢您的阅读。
如果您尝试完全复制 SQL,我认为您错过了顶部 cfset 中的 'W':
输出:
第 9 周(这是 WEEK_2 变量的值)
你有这个命令:
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
由于 week_2 变量的值为 9,当该命令被执行时,它变成这样:
<cfset XX = XX & "ISNULL([9], 0) AS [9] ">
您的查询变为
select username
, 9 as 9
from etc
您将不得不多加考虑以生成周数。
评论太长了。
由于列标签是动态的并且与数据库密切相关,我可能会在数据库端完成这一切。最好在存储过程中。
如果您使用的是 SQL Server 2017+,则可以使用 CTE 生成所需日期范围内的周数。然后 STRING_AGG() 用于将结果转换为逗号分隔列表。
; WITH dates AS ( -- Generate range between -56 and -52 weeks ago SELECT DateAdd(wk, -56, GETDATE()) AS WeekDate UNION ALL SELECT DateAdd(wk, 1, WeekDate) FROM dates WHERE DateAdd(wk, 1, WeekDate) <= DateAdd(wk, -52, GETDATE()) ) , dateLabels AS ( -- extract week number and construct label "W1","W2",etc.. SELECT DATEPART(isowk, WeekDate) AS WeekNum , QUOTENAME( CONCAT('W', DATEPART(isowk, WeekDate) )) AS WeekLabel FROM dates ) -- convert to comma separated lists SELECT STRING_AGG( WeekLabel, ',') WITHIN GROUP (ORDER BY WeekNum) AS PivotColumns , STRING_AGG( CONCAT('ISNULL(', WeekLabel, ',0) AS ', WeekLabel ), ',') WITHIN GROUP (ORDER BY WeekNum) AS SelectColumns FROM dateLabels ;
结果看起来像这样(减去任何换行)
PivotColumns SelectColumns [W6],[W7],[W8],[W9],[W10] ISNULL([W6],0) AS [W6],ISNULL([W7],0) AS [W7],ISNULL([W8],0) AS [W8],ISNULL([W9],0) AS [W9],ISNULL([W10],0) AS [W10]
然后只需将这两个列表插入 SQL 查询即可。在 CF 中:
<cfscript>
// ...
sqlString = "
SELECT UserName
, #SelectColumns#
FROM (
...
) ST
PIVOT
(
SUM(SalesCount)
FOR XWeek IN ( #PivotColumns# )
) AS StorePivot
";
qPivot = queryExecute( sqlString );
// ...
</cfscript>
结果:
SELECT UserName , ISNULL([W6],0) AS [W6] , ISNULL([W7],0) AS [W7] , ISNULL([W8],0) AS [W8] , ISNULL([W9],0) AS [W9] , ISNULL([W10],0) AS [W10] FROM ( ... ) ST PIVOT ( SUM(SalesCount) FOR XWeek IN ( [W6],[W7],[W8],[W9],[W10] ) ) AS StorePivot
WHERE
哦,括号在哪里?
关于原始查询的一些观察:
当前的 WHERE
子句不正确。混合使用AND/OR运算符时,必须使用括号来保证运算顺序。 概念上,当前查询是这样做的:
WHERE Condition1 AND Condition2 OR Condition3
这里应该用括号:
WHERE Condition1 AND ( Condition2 OR Condition3 )
GETDATE() 已经 returns 一个 datetime
值,因此无需在此处再次将其转换为日期时间:
DATEADD(week, -52, convert(datetime, GETDATE()))
最后,不需要所有的串联。字符串通常可以跨越多行,如果需要,总是有 cfsavecontent。删除所有 &
将大大提高可读性。