这是我在cfquery输出之前从“employeeRatings”表中使用的RAW DATA示例:
(showcasing employeeID:1128 for the month of May)
employeeID | Possible_Factor | Factor | ratingDate
=======================================================================
1128 | .1 | .1 | 5/25/2013 2:05:13 PM
1128 | .1 | .0 | 5/22/2013 9:30:43 AM
1128 | .2 | .1 | 5/17/2013 9:42:09 AM
1128 | .1 | .1 | 5/13/2013 8:07:15 AM
1128 | .1 | .0 | 5/10/2013 7:52:51 AM
1128 | .4 | .0 | 5/6/2013 12:41:12 PM
这是cfquery(SQL语句):
SELECT ROUND(100 * (SUM(Factor) / SUM(Possible_Factor)), 2) AS employeeRating, CONVERT(CHAR(4), ratingDate, 100) + CONVERT(CHAR(4), ratingDate, 120) AS month, employeeID, DATEADD(MONTH, DATEDIFF(MONTH, 0, ratingDate), 0) AS shortdate
FROM employeeRatings
GROUP BY CONVERT(CHAR(4), ratingDate, 100) + CONVERT(CHAR(4), ratingDate, 120), DATEADD(MONTH, DATEDIFF(MONTH, 0, ratingDate), 0), employeeID
ORDER BY employeeID, DATEADD(MONTH, DATEDIFF(MONTH, 0, ratingDate), 0) DESC
在cfquery之后,输出将如下所示:
employeeID | employeeRating | month | shortdate
=======================================================================
1128 | 30 | May 2013 | 5/1/2013 12:00:00 AM
1128 | 60 | April 2013 | 4/1/2013 12:00:00 AM
1128 | 90 | Jan 2013 | 1/1/2013 12:00:00 AM
7310000 | 95 | April 2013 | 4/1/2013 12:00:00 AM
7310000 | 85 | Mar 2013 | 3/1/2013 12:00:00 AM
7310000 | 75 | Feb 2013 | 2/1/2013 12:00:00 AM
7310000 | 55 | Jan 2013 | 1/1/2013 12:00:00 AM
444981 | 27 | Mar 2013 | 3/1/2013 12:00:00 AM
444981 | 77 | Jan 2013 | 1/1/2013 12:00:00 AM
444981 | 97 | Nov 2012 | 11/1/2012 12:00:00 AM
444981 | 37 | Sept 2012 | 9/1/2012 12:00:00 AM
444981 | 47 | Aug 2012 | 8/1/2012 12:00:00 AM
我需要雇用一名员工并列出他们的最后三个评级(如果月份为空,则跳过空月并获得评级的下个月以显示最后三个记录的评级)。这是一个动态的cfquery,列出了200多名员工。以下是所需的输出:
supplierID | LastRating | SecondLastRating | ThirdLastRating
======================================================================
1128 | 30 | 60 | 90
7310000 | 95 | 85 | 75
444981 | 27 | 77 | 97
我在SQL Server 2000上使用ColdFusion(兼容性80),但我使用的ColdFusion版本不支持cfloop组属性。我想采用新的输出并将其放入一个新的查询中,因此它可以与另一个查询联接。解决方案=来自FB的星巴克礼物;)谢谢大家的时间和考虑!!!!
答案 0 :(得分:3)
另一个选择是使用SQL Server的PIVOT运算符
首先使用ROW_NUMBER()按员工和日期对记录进行排名。 (注意:如果您的表格不包含实际的日期时间列,您可以替换标识列,或使用datetime
将“月”投射到convert()
。
SELECT employeeID
, employeeRating
, ROW_NUMBER() OVER (
PARTITION BY employeeID
ORDER BY employeeID, theRatingDateCol DESC
) AS Row
FROM yourTable
...
<强>结果:强>
employeeID employeeRating Row
----------- -------------- --------------------
1128 30 1
1128 60 2
1128 90 3
444981 27 1
444981 77 2
444981 97 3
444981 37 4
7310000 95 1
7310000 85 2
7310000 75 3
7310000 55 4
然后PIVOT
排名前三(3)行的结果:
...
PIVOT
(
MIN(employeeRating)
FOR Row IN ( [1],[2],[3])
)
完整查询:
SELECT pvt.employeeID
, pvt.[1] AS LastRating
, pvt.[2] AS SecondLastRating
, pvt.[3] AS ThirdLastRating
FROM (
--- order by employee and rating date (descending)
SELECT employeeID
, employeeRating
, ROW_NUMBER() OVER (
PARTITION BY employeeID
ORDER BY employeeID, theRatingDateCol DESC
) AS Row
FROM yourTable
) data
PIVOT
( -- take top 3 values
MIN(employeeRating)
FOR Row IN ( [1],[2],[3])
) pvt
<强>结果:强>
employeeID LastRating SecondLastRating ThirdLastRating
----------- ----------- ---------------- ---------------
1128 30 60 90
444981 27 77 97
7310000 95 85 75
不幸的是,SQL Server 2000及更早版本不支持这些功能。虽然不像PIVOT
那样光滑,但您仍然可以使用子查询和CASE
来模拟它。
首先,使用子查询代替ROW_NUMBER()
。基本上你是count
具有较早评级日期的记录数,并使用它来代替行号。注意:这假定每个员工的评级日期是唯一的。如果不是,则需要添加另一列来打破平局。
然后使用CASE检查行号并为前三个记录生成列:
SELECT r.employeeID
, MAX( CASE WHEN r.Row = 0 THEN r.EmployeeRating ELSE 0 END ) AS LastRating
, MAX( CASE WHEN r.Row = 1 THEN r.EmployeeRating ELSE 0 END ) AS SecondLastRating
, MAX( CASE WHEN r.Row = 2 THEN r.EmployeeRating ELSE 0 END ) AS ThirdLastRating
FROM (
SELECT m.employeeID
, m.employeeRating
, m.theRatingDate
, ( SELECT COUNT(*)
FROM yourTable cnt
WHERE cnt.employeeID = m.employeeID
AND cnt.theRatingDate > m.theRatingDate
) AS Row
FROM yourTable m
GROUP BY m.employeeID
, m.employeeRating
, m.theRatingDate
) r
WHERE r.Row <= 2
GROUP BY r.employeeID
最后一个选项是使用ColdFusion。您可以调整James Mohler's answer来填充单独的“数据透视”查询。在查询循环之前,创建一个新的查询对象,并按顺序命名评级列,即rating1,rating2,rating3
。在外部循环内,为每个员工添加一行。最后,使用计数器填充内循环内的前三列。
注意:原始查询必须按employeeID, shortDate DESC
排序,否则代码将无法正常运行。
<cfset newQuery = queryNew("employeeID,rating1,rating2,rating3", "integer,Decimal,Decimal,Decimal")>
<cfoutput query="originalQuery" group="employeeID">
<!--- add new employee row --->
<cfset ratingRow = queryAddRow(newQuery, 1)>
<cfset newQuery["employeeID"][ratingRow] = employeeID>
<!--- initialize rating counter --->
<cfset ratingIndex = 0>
<cfoutput>
<cfset ratingColumn++>
<!--- populate top 3 rating columns --->
<cfif ratingColumn lte 3>
<cfset newQuery["rating"& ratingColumn][ratingRow] = employeeRating>
</cfif>
</cfoutput>
</cfoutput>
答案 1 :(得分:2)
以下是仅限ColdFusion的解决方案
<table>
<tr>
<td>SupplierID</td>
<td>LastRating</td>
<td>SecondLastRating</td>
<td>ThirdLastRating</td>
</tr>
<cfoutput name="qrySupplier" group="employeeID">
<cfset Rating = 0>
<tr>
<td>#employeeid#</td>
<cfoutput>
<cfset Rating++>
<cfif Rating LTE 3>
<td>#employeerating#</td>
</cfif>
</cfoutput>
</tr>
</cfoutput>
</table>
答案 2 :(得分:1)
以下是您可以尝试让您入门的内容。我留下了评论。我没有办法建立一个快速表,所以它未经测试但可能是一个很好的首发。我考虑到您的员工/供应商可能有多于或少于3个评级的事实。
<!--- Counter to count ratings --->
<Cfset x=0>
<table width="600" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>supplierid</td>
<td>last rating</td>
<td>second last rating</td>
<td>thirdlastrating</td>
</tr>
<!--- Group by employee --->
<cfoutput query="yourQuery" group="employeeid">
<!--- if previous employee had less then 3 ratings, close off table --->
<cfif x gt 0 and x lt 3>
<cfif x eq 1><td> </td><td> </td></tr></cfif>
<cfif x eq 2><td> </td></tr></cfif>
</cfif>
<!--- Loop through employee --->
<tr>
<td>#employeeid#</td>
<!--- Check counter to make sure we are only doing 3 ratings per line --->
<cfif x lt 3>
<cfoutput>
<td>#employeerating#</td>
<cfset x=x+1>
</cfoutput>
</cfif>
<!--- If at the 3rd rating, close off the row --->
<cfif x eq 3>
</tr>
<cfset x=0>
<!--- if at 3rd rating, reset counter --->
</cfif>
</cfoutput>
</table>