I have a really weird issue with an SQL query I've been working with for some time. I'm using SQL Server 2005.
Here's an example table from which the query is made:
Log: Log_ID | FB_ID | Date | Log_Name | Log_Type 7 | 4 | 2007/11/8 | Nina | Critical 6 | 4 | 2007/11/6 | John | Critical 5 | 4 | 2007/11/6 | Mike | Critical 4 | 4 | 2007/11/6 | Mike | Critical 3 | 3 | 2007/11/3 | Ben | Critical 2 | 3 | 2007/11/1 | Ben | Critical
Now, the idea is to return the first date for the Log_Person working on each FB_ID, however, in the case there are several Log_Names, I only want the SECOND Log_Name (first time the responsibility is handed over to another). The result should look like this:
Desired result Log_ID | FB_ID | Date | Log_Name | Log_Type 6 | 4 | 2007/11/6 | John | Critical 2 | 3 | 2007/11/1 | Ben | Critical
In an earlier thread, Peter Lang and Quassnoi gave brilliant answers which are below. Sadly I can barely understand what happens there, but they worked like a charm. Here's the code:
Quassnoi SELECT lo4.* FROM (SELECT CASE WHEN ln.log_id IS NULL THEN lo2.log_id ELSE ln.log_id END AS log_id, ROW_NUMBER() OVER (PARTITION BY lo2.fb_id ORDER BY lo2.cdate) AS rn FROM (SELECT lo.*, (SELECT TOP 1 log_id FROM t_log li WHERE li.fb_id = lo.fb_id AND li.cdate >= lo.cdate AND li.log_id lo.log_id AND li.log_name lo.log_name ORDER BY cdate, log_id) AS next_id FROM t_log lo) lo2 LEFT OUTER JOIN t_log ln ON ln.log_id = lo2.next_id) lo3, t_log lo4 WHERE lo3.rn = 1 AND lo4.log_id = lo3.log_id
Peter Lang SELECT * FROM log WHERE log_id IN (SELECT MIN(log_id) FROM log WHERE (SELECT COUNT(DISTINCT log_name) FROM log log2 WHERE log2.fb_id = log.fb_id ) = 1 OR log.log_name (SELECT log_name FROM log log_3 WHERE log_3.log_id = (SELECT MIN(log_id) FROM log log4 WHERE log4.fb_id = log.fb_id )) GROUP BY fb_id )
Now if you've read this far, here's the question. Why do they both work fine, but as soon as I apply other filters on them, everything gets mixed?
I even tried to create a temporary table with the WITH clause, and use Date and Log_Type filters on that, but it still didn't work. Several results that should've been included with the filters were suddenly left out. When originally I would get the first dated only name, or the second name if there were several from the Log_Name column, now I would randomly get whatever, if any. In a similar manner, using WHERE (DATE BETWEEN '2007/11/1' AND '2007/11/30') would cause a permaloop, where using WHERE (MONTH(Date) = '11') AND (YEAR(Date) = '2007') would work fine. But if I added one more filter to the latter option, for example .. AND WHERE Log_Type = 'Critical', it'd be on permaloop again. Both permaloops happened with Lang's solution.
I need to combine this type of search with another using UNION ALL, so I'm wondering if I'm going to run into any more similarly weird problems in the future with that? There's clearly something I don't understand about SQL here, and my DL for the query is today so I'm kinda stressed out here. Thx for all the help. :)
Edit: To clarify. In need the result of the queries above, and those results need to be filtered to 'critical' cases over a given time (month) ONLY.
This will then be united with another search that returns the first time a FB_ID with 'Support' status (Log_Type) has been logged. The idea is to give a picture of how many new cases are recorded in the DB each month.
Edit 2: Update, Russ Cam's suggestion below is working, but it rules out any FB_ID's that were first dated outside the given range, even if the query result row where the Log_Name changes, would exist within range.