Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Ok, so here is a CLR stored proc that solves the problem. This returns an the sustained min/max from a case containing 1.1 million records in about 3:05 (minutes). Please let me know if there is a plain T-SQL way to accomplish this as I would rather not go down this road. However, comments on how to speed this one up would also be appreciated.</p> <pre><code>public partial class StoredProcedures { [Microsoft.SqlServer.Server.SqlProcedure] public static void ComputeCaseSustainedChannelValues(int caseId, int seconds) { SqlConnection con = new SqlConnection(); SqlCommand cmd = new SqlCommand(); try { con = new SqlConnection("context connection=true"); con.Open(); cmd = new SqlCommand(String.Format("Select channel_index, start_time, dms_value, value_duration from continuous_data where case_id = {0} and dms_type = 0 and error_code is NULL order by channel_index, start_time", caseId), con); SqlDataReader reader = cmd.ExecuteReader(); Queue&lt;ContinuousData&gt; window = new Queue&lt;ContinuousData&gt;(); ArrayList channelValues = new ArrayList(); float? sus_min = null, sus_max = null; float? min = null, max = null; int currentChannel = -1; bool recalc = true; int recalccounter = 0; int rowcounter = 0; using (reader) { while (reader.Read()) { var cd = new ContinuousData { ChannelIndex = reader.GetInt16(0), StartTime = reader.GetDateTime(1), DmsValue = (float)reader.GetSqlDouble(2), Duration = reader.GetInt16(3) }; // check to make sure we are on the same channel. If not // clear the queue and start over with the new channel if (currentChannel != cd.ChannelIndex) { if (currentChannel != -1) { SqlContext.Pipe.Send(String.Format("Channel: {0} Min: {1} Max: {2}", currentChannel, sus_min, sus_max)); } currentChannel = cd.ChannelIndex; window.Clear(); sus_max = null; sus_min = null; recalc = true; } rowcounter++; window.Enqueue(cd); if (cd.StartTime.Subtract(window.Peek().StartTime).TotalSeconds &gt;= seconds) { if (recalc) { recalccounter++; // a current sustained min max value was removed so recalc the window's min max MinMax(window.ToArray(), out min, out max); recalc = false; } else { // update the rolling min max based on the new value coming in max = max == null || cd.DmsValue &gt; max ? cd.DmsValue : max; min = min == null || cd.DmsValue &lt; min ? cd.DmsValue : min; } // update the sustained min max based on the current window's min max sus_min = sus_min == null || max &lt; sus_min ? max : sus_min; sus_max = sus_max == null || min &gt; sus_max ? min : sus_max; // now that we calculated remove the first item var firstitem = window.Dequeue(); if (firstitem.DmsValue == sus_min || firstitem.DmsValue == sus_max || firstitem.DmsValue == min || firstitem.DmsValue == max) { recalc = true; } } } } if (sus_max != null &amp;&amp; sus_min != null) { SqlContext.Pipe.Send(String.Format("Channel: {0} Min: {1} Max: {2}", currentChannel, sus_min, sus_max)); } window.Clear(); window = null; SqlContext.Pipe.Send(String.Format("Rows: {0}, Recalcs performed: {1}", rowcounter, recalccounter)); SqlContext.Pipe.Send("Done!"); } catch (Exception) { throw; } finally { con.Close(); con.Dispose(); cmd.Dispose(); } } private static void MinMax(ContinuousData[] cd, out float? min, out float? max) { min = cd[0].DmsValue; max = cd[0].DmsValue; for (int i = 0; i &lt; cd.Length; i++) { if (min &gt; cd[i].DmsValue) min = cd[i].DmsValue; if (max &lt; cd[i].DmsValue) max = cd[i].DmsValue; } } public class ContinuousData { public int ChannelIndex { get; set; } public DateTime StartTime { get; set; } public float DmsValue { get; set; } public int Duration { get; set; } } public class ChannelValues { public int ChannelIndex { get; set; } public float SustainedMin { get; set; } public float SustainedMax { get; set; } } }; </code></pre>
    singulars
    1. This table or related slice is empty.
    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. This table or related slice is empty.
    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