Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h2>SQL Server 2005+</h2> <p>Another option is using SQL Server's <a href="http://msdn.microsoft.com/en-us/library/ms177410%28v=SQL.105%29.aspx" rel="nofollow noreferrer">PIVOT</a> operator</p> <p>First use <a href="http://msdn.microsoft.com/en-us/library/ms186734.aspx" rel="nofollow noreferrer">ROW_NUMBER()</a> to rank the records by employee and date. (Note: If your table does not contain an actual datetime column, you could substitute an identity column, or cast the "month" into a <code>datetime</code> using <code>convert()</code>).</p> <pre><code> SELECT employeeID , employeeRating , ROW_NUMBER() OVER ( PARTITION BY employeeID ORDER BY employeeID, theRatingDateCol DESC ) AS Row FROM yourTable ... </code></pre> <p><strong>Results:</strong></p> <pre><code>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 </code></pre> <p>Then <code>PIVOT</code> the results of the top three (3) rows:</p> <pre><code> ... PIVOT ( MIN(employeeRating) FOR Row IN ( [1],[2],[3]) ) </code></pre> <hr> <p><strong>Full Query:</strong></p> <pre><code>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 </code></pre> <p><strong>Results:</strong></p> <pre><code>employeeID LastRating SecondLastRating ThirdLastRating ----------- ----------- ---------------- --------------- 1128 30 60 90 444981 27 77 97 7310000 95 85 75 </code></pre> <h2>SQL Server 2000</h2> <p>Unfortunately SQL Server 2000 and earlier do not support either of those functions. While not as slick as <code>PIVOT</code>, you can still simulate it using a subquery and <code>CASE</code>. </p> <p>First, use a subquery in place of <code>ROW_NUMBER()</code>. Essentially you <code>count</code> the number of records with an earlier rating date, and use it in place of a row number. Note: This assumes the rating dates are unique per employee. If they are not you will need to add another column to break the tie.</p> <p>Then use <a href="http://msdn.microsoft.com/en-us/library/ms181765.aspx" rel="nofollow noreferrer">CASE</a> to examine the row numbers and generate columns for the first three records:</p> <pre><code>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 &gt; m.theRatingDate ) AS Row FROM yourTable m GROUP BY m.employeeID , m.employeeRating , m.theRatingDate ) r WHERE r.Row &lt;= 2 GROUP BY r.employeeID </code></pre> <h2>ColdFusion</h2> <p>A last option is to use ColdFusion. You could adapt <a href="https://stackoverflow.com/a/16943786/104223">James Mohler's answer</a> to populate a separate "pivot" query. Before the query loop, create a new query object, and name the rating columns sequentially ie <code>rating1,rating2,rating3</code>. Inside the outer loop, add a row for each employee. Finally, use the counter to populate the first three columns inside the inner loop.</p> <p>Note: The original query <strong>must</strong> be ordered by <code>employeeID, shortDate DESC</code> or the code will not work correctly.</p> <pre><code>&lt;cfset newQuery = queryNew("employeeID,rating1,rating2,rating3", "integer,Decimal,Decimal,Decimal")&gt; &lt;cfoutput query="originalQuery" group="employeeID"&gt; &lt;!--- add new employee row ---&gt; &lt;cfset ratingRow = queryAddRow(newQuery, 1)&gt; &lt;cfset newQuery["employeeID"][ratingRow] = employeeID&gt; &lt;!--- initialize rating counter ---&gt; &lt;cfset ratingIndex = 0&gt; &lt;cfoutput&gt; &lt;cfset ratingColumn++&gt; &lt;!--- populate top 3 rating columns ---&gt; &lt;cfif ratingColumn lte 3&gt; &lt;cfset newQuery["rating"&amp; ratingColumn][ratingRow] = employeeRating&gt; &lt;/cfif&gt; &lt;/cfoutput&gt; &lt;/cfoutput&gt; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload