<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Arcane Code</title>
	<atom:link href="https://arcanecode.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://arcanecode.com</link>
	<description></description>
	<lastBuildDate>Mon, 28 Aug 2023 02:41:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='arcanecode.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://s0.wp.com/i/buttonw-com.png</url>
		<title>Arcane Code</title>
		<link>https://arcanecode.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://arcanecode.com/osd.xml" title="Arcane Code" />
	<atom:link rel='hub' href='https://arcanecode.com/?pushpress=hub'/>
	<item>
		<title>Welcome To Kent!</title>
		<link>https://arcanecode.com/2023/08/28/welcome-to-kent/</link>
					<comments>https://arcanecode.com/2023/08/28/welcome-to-kent/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 28 Aug 2023 13:00:00 +0000</pubDate>
				<category><![CDATA[Big Thinkers]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5353</guid>

					<description><![CDATA[Welcome To Kent]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>I’m happy to announce that effective today, August 28th, 2023 I will be going work for the <a href="http://kentww.com">Kent Corporation</a> as a Business Intelligence Engineer.</p>
<p>This opportunity came about from a friend, <a href="https://www.linkedin.com/in/phelanp/">Patrick Phelan</a>. He works for Kent, and reached out to me to see I was interested in the job. After looking at the company, and the role, I was very interested!</p>
<p>Kent is an agriculture manufacturing company that was started in 1927. They use various types of grains, such as wheat, and make a variety of products. Animal food for horses, sheep, dogs, cats and more. They make distilled grain alcohol for medical use or distilleries. In addition they make additives for a variety of food products such as bread. Another aspect I really appreciate about Kent is their environmental consciousness. They strive to reduce waste by-products as much as possible.</p>
<p>In my role I’ll be working to upgrade and expand their SQL Server Data Warehouse, working with their SSIS packages, create cubes in SSAS, and lots of SSRS reports. I’ll also be working heavily in PowerBI. At some point in the future we plan to be shifting a lot of this up to Azure. Along the way I’ll be whipping up some PowerShell scripts to help automate as much work as possible.</p>
<h2>The Future</h2>
<p>For the next few months I’ll be focused on Kent. At some point though I plan to resume my videos for Pluralsight working on the evenings / weekends.</p>
<p>In addition, my blogging will become irregular. Previously I’ve been posting weekly, the blog posts focused on the subjects in my videos. Working full time for Kent I won’t have time to dedicate to blogging. I’ll still blog, and while I will try for weekly there may be some weeks that get skipped due to my daytime workload especially in the first few months.</p>
<p>The subjects will also vary, tied more toward some of the BI subjects I’ll be working with at Kent, such as Data Warehousing, SSIS/SSAS/SSRS, PowerBI, and of course PowerShell!</p>
<h2>Conclusion</h2>
<p>Thanks for joining me on my journey over the last few years as a full time Pluralsight video course author and book writer. I hope you’ll keep my company as I begin a new phase in my career!</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/08/28/welcome-to-kent/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Row_Window_Session</title>
		<link>https://arcanecode.com/2023/08/21/fun-with-kql-windowing-functions-row_window_session/</link>
					<comments>https://arcanecode.com/2023/08/21/fun-with-kql-windowing-functions-row_window_session/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 21 Aug 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[KQL]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5346</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Row_Window_Session]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>This post will conclude our look at the Kusto Query Language with the <code>row_window_session</code> function. It can be used to group rows of data in a time range, and will return the starting time for that range of data in each row.</p>
<p>If you’ve not read my introductory post on Windowing Functions, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a> yet, you should do so now as it introduced several important concepts needed to understand how these Windowing Functions work.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Row_Window_Session Basics</h2>
<p>The <code>row_window_session</code> function allows you to group data into time based groups. It will find the beginning of a time group, which KQL calls a <em>session</em>, then will return the beginning time of the session (along with other data) until the conditions are met to cause a new session to start.</p>
<p>Let’s look at an example query, then we’ll break down the various parts.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png"><img data-attachment-id="5349" data-permalink="https://arcanecode.com/2023/08/21/fun-with-kql-windowing-functions-row_window_session/052-02_row_window_session_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png" data-orig-size="997,772" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="052.02_row_window_session_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=997" width="997" height="772" src="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=997" alt="" class="wp-image-5349" srcset="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png 997w, https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=768 768w" sizes="(max-width: 997px) 100vw, 997px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We begin by declaring a <code>datatable</code> to hold our sample data. It has three columns. The <code>rowNum</code> is included to make it easier to discuss the logic of <code>row_window_session</code> in a moment, otherwise it’s just an extra piece of data.</p>
<p>I then include a <code>groupVal</code> column. It will be used to trigger the beginning of a new time group (aka session). Working with real world data, you may use something like the name of a computer for the group.</p>
<p>Finally we have a column of datatype <code>datetime</code>. When working with log data from, for example, the <strong>Perf</strong> table this would typically be the <code>TimeGenerated</code> column but it doesn’t have to be. Any <code>datetime</code> datatype column can be used. I’ve crafted the data to make it easier to explain how <code>row_window_session</code> works.</p>
<p>Next, I take our <code>SomeData</code> dataset and pipe it into a <code>sort</code>, sorting by the group and time in ascending order. The <code>sort</code> has the added benefit of creating a dataset that is <em>serializable</em>. See my <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">previous post on serialization</a>, mentioned in the introduction, for more on why this is important.</p>
<p>Finally we fall into an <code>extend</code> where we create a new column I named <code>SessionStarted</code>. We then assign it the output of the <code>row_session_started</code> function, which requires four parameters.</p>
<p>The first parameter is the datetime column to be used for determining the session window. Here it is <code>timeStamp</code>. The next three parameters are all conditions which will trigger the beginning of a new “session” or grouping.</p>
<p>The second parameter is a <code>timespan</code>, here I used a value of <code>5m</code>, or five minutes. If more than five minutes have elapsed since the current row and the first row in this group, it will trigger the creation of a new window session (group).</p>
<p>The third parameter is also a <code>timespan</code>, and indicates the maximum amount of time that can elapse between the current row and the previous row before a new window session is started. Here we used <code>30s</code>, or thirty seconds. Even if the current row is still within a five minute window from the first row in the group, if the current row is more than thirty seconds in the future from the previous row a new session is created.</p>
<p>The final parameter is a way to trigger a change when the group changes. Here we use the <code>groupVal</code> column, but it’s more likely you’d use a computer name or performance counter here.</p>
<h2>Breaking it Down</h2>
<p>Since this can get a bit confusing, let’s step through the logic on a row by row basis. You can use the <code>rowNum</code> column for the row numbers.</p>
<p>Row 1 is the first row in our dataset, with a <code>timeStamp</code> of <code>12:01:01</code>. Since it is first, KQL will use the same value in the <code>SessionStarted</code> column.</p>
<p>In row 2, we have a <code>timeStamp</code> of <code>12:01:10</code>. Since this is less than five minutes from our first record, no new session is created.</p>
<p>Next, it compares the <code>timeStamp</code> from this row with the previous row, row 1. Less than 30 seconds have elapsed, so we are still in the same window session.</p>
<p>Finally it compares the <code>groupVal</code> with the one from row 1. Since the group is the same, no new session window is triggered and the <code>SessionStarted</code> time of <code>12:01:01</code>, the time from row 1 is used.</p>
<p>Now let’s move to row 3. It has a time stamp of <code>12:11:11</code>. This is more than five minutes since the time in row 1, which is the beginning of the session, so it then begins a new window session. It’s time of <code>12:11:11</code> is now used for the <code>SessionStarted</code>.</p>
<p>Row 4 comes next. It’s time of <code>12:21:13</code> also exceeds the five minute window since the start of the session created in row 3, so it begins a new session.</p>
<p>Now we move into row 5. Because the <code>groupVal</code> changed, we begin a new session with a new session start time of <code>12:01:17</code>.</p>
<p>In row 6 we have a time of <code>02:01:20</code>. Well a two am time is definitely more than five minutes from the row 5’s time, so a new session is started.</p>
<p>The time in row 7 is <code>02:01:22</code>. That’s less than five minutes from row 6, and it’s also less than 30 seconds. Since it is in the same group, no new session occurs and it returns <code>02:01:20</code> for the <code>SessionStarted</code>.</p>
<p>Now we get to row 8. The time for this row is <code>02:03:30</code>, so we are still in our five minute window that began in row 6. However, it is more than 30 seconds from row 7’s time of <code>02:01:22</code> so a new window session begins using row 8’s time of <code>02:03:30</code>.</p>
<p>Finally we get to row 9. By now I’m sure you can figure out the logic. Its time of <code>02:11:35</code> is more than five minutes from the session start (begun in row 8), so it triggers a new session window.</p>
<h2>Remember the Logic</h2>
<p>While this seems a bit complex at times, if you just remember the logic it can be pretty easy to map out what you want.</p>
<p>Did the group change as defined in the fourth parameter? If yes, then start a new window session.</p>
<p>Compared to the session <em>start</em> row, is the time for the current row greater in the future by the value specified in parameter 2? Then start a new window session.</p>
<p>Compared to the <em>previous</em> row, is the time for the current row farther in the future then the amount of time in parameter 3? If so, start a new window session.</p>
<h2>TimeSpans</h2>
<p>In this example I used small values for the timespans, <code>5m</code> and <code>30s</code>. You can use any valid timespan though, including days and hours.</p>
<p>For a complete discussion on the concept of timespans, see my blog post <a href="https://arcanecode.com/2022/09/19/fun-with-kql-format_timespan/">Fun With KQL &#8211; Format_TimeSpan</a>.</p>
<h2>Let’s Use Real Data</h2>
<p>For completeness I wanted to include a final example that uses the <strong>Perf</strong> table from the LogAnalytics demo website.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png"><img data-attachment-id="5350" data-permalink="https://arcanecode.com/2023/08/21/fun-with-kql-windowing-functions-row_window_session/052-03_real_example/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png" data-orig-size="1031,490" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="052.03_real_example" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=1024" width="1024" height="486" src="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=1024" alt="" class="wp-image-5350" srcset="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png 1031w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>The logic is similar to the previous example. Since you now have an understanding of the way <code>row_window_session</code> works, I’ll leave it up to you to step through the data and identify the new window sessions.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a></p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2022/09/19/fun-with-kql-format_timespan/">Fun With KQL &#8211; Format_TimeSpan</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/">Fun With KQL Windowing Functions &#8211; Prev and Next</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>With this post on <code>row_window_session</code>, we complete our coverage of Kusto’s Windowing Functions. You saw how to use it to group data into timespans based on a beginning date, with the ability to group on total elapsed time since the start of a window or since the previous row of data.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/08/21/fun-with-kql-windowing-functions-row_window_session/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/052.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/052.99_featured_image.png" medium="image">
			<media:title type="html">052.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/052.02_row_window_session_basics.png?w=997" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/052.03_real_example.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Row_Rank_Dense</title>
		<link>https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/</link>
					<comments>https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 14 Aug 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[KQL]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5337</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Row_Rank_Dense]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>The Kusto Windowing Function <code>row_rank_dense</code> is an interesting function. It lets you get a unique count of a specific column in a dataset. Unlike other methods of getting counts, <code>row_rank_dense</code> allows you to see each individual row of data.</p>
<p>First though, if you’ve not read the introductory post on Windowing Functions, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a>, you should do so now as it introduced several important concepts needed to understand how these Windowing Functions work.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Row_Rank_Dense Basics</h2>
<p>The <code>row_rank_dense</code> is used to determine the <em>density</em> of a value. By passing in a sorted dataset, you can get a rank number for each item. The rank number changes only when the value we’re evaluating changes.</p>
<p>An example will make this much clearer. We start by creating a <code>datatable</code> with three columns. The <code>rowNum</code> is just used to make it easier to discuss the output in a moment. Likewise <code>rowVal</code> provides some easy to consume text.</p>
<p>The important column is <code>valToRankOn</code>. It is this value that is going to be evaluated within our <code>row_rank_dense</code> Windowing Function.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png"><img data-attachment-id="5339" data-permalink="https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/051-02_row_rank_dense_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png" data-orig-size="791,754" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="051.02_row_rank_dense_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=791" width="791" height="754" src="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=791" alt="" class="wp-image-5339" srcset="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png 791w, https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=768 768w" sizes="(max-width: 791px) 100vw, 791px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>The <code>SomeData</code> dataset is piped into a <code>sort</code>, where we sort on the value we are evaluating in ascending order. We will also sort on the <code>rowVal</code>, so when we have two identical values in <code>valToRankOn</code>, we can display the output in a logical fashion. In a real world situation, this might be the name of computer or perhaps a counter of some kind.</p>
<p>Using a <code>sort</code> will also mark the data as <em>serializable</em>, which is required in order to use <code>row_rank_dense</code>. For more on serialization, see the <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a> post I mentioned in the introduction.</p>
<p>Finally we fall into an <code>extend</code>, creating a new column <code>Rank</code>. We’ll assign it the output of our <code>row_rank_dense</code> function. In it we use one parameter, the name of the column to be evaluated, here it is <code>valToRankOn</code>.</p>
<p>In the output, our first row is row 7, with a <code>valToRankOn</code> of <code>1</code>. Thus it is assigned a <code>Rank</code> of <code>1</code>.</p>
<p>The next row is row 8, it has the next smallest value of <code>6</code> in the <code>valToRankOn</code> column, so it gets a <code>Rank</code> of 2.</p>
<p>Rows 6 and 9 both have the same <code>valToRankOn</code>, 17. Since 17 is the third smallest value, both rows are given a <code>Rank</code> of 3. Because we included <code>rowVal</code> in the <code>sort</code>, they are listed in order of the <code>rowVal</code>, <code>Value 06</code> then <code>Value 09</code>.</p>
<p>This continues for the remaining rows of data. We can see both how many unique values we have, six, and still see each individual row of data.</p>
<h2>Density by Largest Value</h2>
<p>In the above example, by sorting the <code>valToRankOn</code> in ascending order the smallest values come first, then increase with a <code>Rank</code> of 1 being given to the smallest value.</p>
<p>If we had instead sorted <code>valToRankOn</code> in descending order, <code>sort by valToRankOn desc, ...</code>, then the <code>Rank</code> of 1 would have been assigned to the largest value, then as the <code>valToRankOn</code> decreased the <code>Rank</code> would have increased. I’ll leave it as an exercise for you to play with this by altering the sort order for your sample queries.</p>
<h2>Grouping In Row_Rank_Dense</h2>
<p>It is also possible to organize rankings within a group. For example, within a single computer you might want to rank a counter value. With the next computer you’d want the rankings to begin again. This would allow you to have rankings that are unique to each computer.</p>
<p>In the example below I’ve added a new column to the <code>datatable</code> named <code>groupVal</code>. We’ll be using this column for our grouping. It was also added to the <code>sort</code> operator so we’ll sort by group first, then the value to rank on, and finally the <code>rowVal</code> text.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png"><img data-attachment-id="5341" data-permalink="https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/051-03_row_rank_dense_grouping/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png" data-orig-size="922,747" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="051.03_row_rank_dense_grouping" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=922" loading="lazy" width="922" height="747" src="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=922" alt="" class="wp-image-5341" srcset="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png 922w, https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=768 768w" sizes="(max-width: 922px) 100vw, 922px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>The <code>row_rank_dense</code> function supports a second parameter, a boolean value that when true will trigger a new group to begin. Here we are using an equation, which will compare the <code>groupVal</code> for the current row to the one of the previous row using the <code>prev</code> Windowing Function. If they are not equal, the comparison will return true and trigger <code>row_rank_dense</code> to begin a new dense rank grouping.</p>
<p>In the output, rows 1 and 3 (from the <code>rowNum</code> column) have the same <code>valToRankOn</code>, so are both given the <code>Rank</code> of <code>1</code>. The third row in this group, row 2, is assigned a <code>Rank</code> of <code>2</code>.</p>
<p>With row 4, we see the <code>groupVal</code> has changed. So the <code>row_rank_dense</code> function reset and began a new ranking, assigning this row a <code>Rank</code> of <code>1</code>.</p>
<p>When the group changes again in row 7, the <code>Rank</code> value is again reset to <code>1</code> and we work our way up.</p>
<h2>Row_Rank_Dense in the Real World</h2>
<p>Let’s take a look now at an example of using <code>row_rank_dense</code> for a “real world” query. Here, we are going to query the <strong>Perf</strong> table to bring back rows for the last five minutes where the <code>CounterValue</code> is <code>Bytes Sent/sec</code>, and we’ll remove any rows with a value of zero.</p>
<p>We’ll project each column we need and sort the data. Here we’ll again sort in ascending order so the smallest counter values come first, but we could just have easily sorted the <code>CounterValue</code> in descending order so the largest values came first.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png"><img data-attachment-id="5342" data-permalink="https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/051-04_row_rank_dense_real_example/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png" data-orig-size="786,968" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="051.04_row_rank_dense_real_example" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=244" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=786" loading="lazy" width="786" height="968" src="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=786" alt="" class="wp-image-5342" srcset="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png 786w, https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=122 122w, https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=244 244w, https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=768 768w" sizes="(max-width: 786px) 100vw, 786px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>When we call <code>row_rank_dense</code>, we’ll pass in the value we want to rank in the first parameter, <code>CounterValue</code>. In the second parameter we’ll compare the name of the computer in this row to the one of the previous row using the <code>prev</code> function. When they don’t match the comparison will return true, which will trigger the <code>row_rank_dense</code> function to begin a new group.</p>
<p>As you can see, we begin with computer <code>CH-AMAVM</code>, with its value of 2.26333 given the rank of <code>1</code>, then the rank values increase as the counter values increase.</p>
<p>When we hit computer <code>CH1-AVSMGMTVM</code>, note the <code>Rank</code> reset itself. The first row for this computer, with a counter value of 2.34613 has a <code>Rank</code> of <code>1</code>.</p>
<p>This pattern will repeat for the remaining rows of data from our query.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a></p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/">Fun With KQL Windowing Functions &#8211; Prev and Next</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>In this post you saw how to use the <code>row_rank_dense</code> Windowing Function to order and rank values in a dataset from smallest to largest, or largest to smallest.</p>
<p>The next and final post in the Kusto Window Functions series will cover the use of <code>row_window_session</code> to group and organize data into time windows.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/08/14/fun-with-kql-windowing-functions-row_rank_dense/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/051.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/051.90_featured_image.png" medium="image">
			<media:title type="html">051.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/051.02_row_rank_dense_basics.png?w=791" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/051.03_row_rank_dense_grouping.png?w=922" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/051.04_row_rank_dense_real_example.png?w=786" medium="image" />
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Row_Rank_Min</title>
		<link>https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/</link>
					<comments>https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 07 Aug 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[KQL]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5328</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Row_Rank_Min]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In this post we’ll cover the next in our series on KQL Windowing Functions, <code>row_rank_min</code>. The <code>row_rank_min</code> function will assign rank numbers to an incoming dataset, with the rank of 1 being assigned to the minimal value in the dataset and increasing as the values increase.</p>
<p>First though, if you’ve not read the introductory post on Windowing Functions, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a>, you should do so now as it introduced several important concepts needed to understand how these Windowing Functions work.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Row_Rank_Min Basics</h2>
<p>We being by using <code>let</code> to define a <code>datatable</code> with some values to use for our example. The <code>rowNum</code> and <code>rowVal</code>  are just included to have some data to look at.</p>
<p>The important column is <code>valToRankOn</code>. This is the column that will be evaluated and used to rank the data. Let’s see how our query works.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png"><img data-attachment-id="5331" data-permalink="https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/050-02_row_rank_min_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png" data-orig-size="909,735" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="050.02_row_rank_min_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=909" loading="lazy" width="909" height="735" src="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=909" alt="" class="wp-image-5331" srcset="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png 909w, https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=768 768w" sizes="(max-width: 909px) 100vw, 909px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We take our <code>SomeData</code> and pipe it into a <code>sort</code>, sorting by the value to rank on and the row value (<code>rowVal</code>). Note we need to sort the <code>valToRankOn</code> in ascending order to get the <code>row_rank_min</code> to work correctly, and while we are at it we’ll sort the <code>rowVal</code> in ascending order as well.</p>
<p>The <code>sort</code> has the added benefit as making the data <em>serializable</em>, so it can be used with KQL Windowing Functions, in this case <code>row_rank_min</code>. For more on serialization see the post I referenced in the introduction, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a>.</p>
<p>After the <code>sort</code> we have an <code>extend</code> where we create a new column <code>Rank</code>. To it we assign the output of <code>row_rank_min</code>. Into the function we pass the column to evaluate for the rank, here we are using <code>valToRankOn</code>.</p>
<p>The smallest value is given a rank of 1, as you can see with <code>rowNum</code> 7. The next smallest value, found on <code>rowNum</code> 8 is assigned a rank of 2. Row 3 has a <code>valToRankOn</code> of 15, which is the next smallest value so it was given a rank of 3.</p>
<p>Rows 6 and 9 both have a value of 17, so both are assigned the same minimal rank number of 4. Because we added the <code>rowVal</code> to the <code>sort</code>, the rows are sorted in ascending order by the <code>rowVal</code> within the <code>Rank</code> of 4.</p>
<p>This pattern is repeated for the remaining rows, with the rank value increasing as the values in <code>valToRankOn</code> increases. As you can see, this provides an easy way to rank values from smallest to largest.</p>
<h2>Ranking Within a Group</h2>
<p>Similar to the <code>row_cumsum</code> Windowing Function we looked at in the <a href="https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/">previous post</a>, we can create rankings within a group. In the following sample, a new column of <code>groupVal</code> was added to the <code>SomeData</code> sample dataset.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png"><img data-attachment-id="5332" data-permalink="https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/050-03_row_rank_min_grouping/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png" data-orig-size="925,745" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="050.03_row_rank_min_grouping" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=925" loading="lazy" width="925" height="745" src="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=925" alt="" class="wp-image-5332" srcset="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png 925w, https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=768 768w" sizes="(max-width: 925px) 100vw, 925px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>In the example we made two changes from the previous sample. First, the <code>groupVal</code> was added to the <code>sort</code> statement.</p>
<p>The next change occurred in the <code>row_rank_min</code> function. It supports a second parameter that will trigger a reset of the ranking value. It needs to evaluate to a boolean true/false value. When true, it resets the ranking value.</p>
<p>Here, we are comparing the <code>groupVal</code> of the current row to the <code>groupVal</code> of the previous row using the <code>prev</code> function. If the group name for the current row is different from the previous row, the comparison will return true since they are not equal. This will trigger the ranking to restart.</p>
<p>In <code>rowNum</code> 4 the group changes to <code>Group 2</code>, so Kusto starts the ranking again. Within <code>Group 2</code>, the value of 22 on row 4 is the smallest, so it gets the rank of 1.</p>
<p>This technique lets us create minimal ranking values within individual groups of data. Here we are using <code>groupVal</code>, in a real world you might use something like a computer name or performance counter name.</p>
<h2>Real World Example</h2>
<p>In this query we’ll create something you might use in the “real world”. We’re going to look at the <strong>Perf</strong> table for the counter “Bytes Sent/rec”, where there is data (the counter value is greater than zero).</p>
<p>We’ll <code>project</code> only the columns we need, then <code>sort</code> the output. We want to create rankings for each computer, from the smallest counter value to the biggest. By doing so we can easily see what times we had the smallest and largest values.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png"><img data-attachment-id="5334" data-permalink="https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/050-04_row_rank_min_real_example/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png" data-orig-size="783,990" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="050.04_row_rank_min_real_example" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=237" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=783" loading="lazy" width="783" height="990" src="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=783" alt="" class="wp-image-5334" srcset="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png 783w, https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=119 119w, https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=237 237w, https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=768 768w" sizes="(max-width: 783px) 100vw, 783px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Here we use <code>row_rank_min</code> to evaluate the <code>CounterValue</code>. In the second parameter we are checking to see if the <code>Computer</code> name has changed, if so the rank will reset for the next computer.</p>
<p>Looking at one example, when the <code>Computer</code> changed from <code>CH-AMAVM</code> changes to <code>CH1-AVSMGMTVM</code>, the rank reset so the smallest value of 16.4175 is given the rank of 1.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a></p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/">Fun With KQL Windowing Functions &#8211; Prev and Next</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/">Fun With KQL Windowing Functions &#8211; Row_CumSum</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>With this post we saw how to create rankings for values using the <code>row_rank_min</code> function. This allows us to easily identify the smallest value, with a rank of 1 and work up to the largest value.</p>
<p>In our next post we’ll continue our KQL Windowing Function series by looking at the <code>row_rank_dense</code> function, which is similar to this posts <code>row_rank_min</code>.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/08/07/fun-with-kql-windowing-functions-row_rank_min/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/050.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/050.90_featured_image.png" medium="image">
			<media:title type="html">050.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/050.02_row_rank_min_basics.png?w=909" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/050.03_row_rank_min_grouping.png?w=925" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/050.04_row_rank_min_real_example.png?w=783" medium="image" />
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Row_CumSum</title>
		<link>https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/</link>
					<comments>https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 31 Jul 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[KQL]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5319</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Row_CumSum]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>Seeing cumulative totals on a row by row basis is a common need. Think of your bank account, when you look at your ledger it shows each individual transaction. Beside each individual transaction is the current amount in your account, as offset by the amount of the current transaction.</p>
<p>This technique is known as <em>cumulative sums</em>. The Kusto Query Language provides the ability to create cumulative sums using the Windowing Function, <code>row_cumsum</code>. In this post we’ll see how to implement it.</p>
<p>First though, if you’ve not read the introductory post on Windowing Functions, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a>, you should do so now as it introduced several important concepts needed to understand how these Windowing Functions work.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this KQL series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Row_CumSum Basics</h2>
<p>For this example I’ll be using <code>let</code> to generate a simple dataset using the <code>datatable</code> operator. It will have two columns, the row number <code>rowNum</code>, and a value <code>rowVal</code>. For more information on <code>let</code>, <code>datatable</code>, <code>serialize</code>, and other functions used in this post refer to the <strong>See Also</strong> later in this post.</p>
<p>Using <code>row_cumsum</code> is simple. First, we need to pipe the dataset <code>SomeData</code> into a <code>serialize</code> so we can use it with Windowing Functions. The <code>serialize</code> also lets us  create a new column we named <code>cumSum</code>, and set it equal to the <code>row_cumsum</code> output. As a parameter, I pass in the numeric column I want to add up, here I used the <code>rowNum</code> column.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png"><img data-attachment-id="5322" data-permalink="https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/049-02_row_cumsum_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png" data-orig-size="636,719" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="049.02_row_cumsum_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=265" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=636" loading="lazy" width="636" height="719" src="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=636" alt="" class="wp-image-5322" srcset="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png 636w, https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=133 133w, https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=265 265w" sizes="(max-width: 636px) 100vw, 636px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>As you can see in row 1, the row number (<code>rowNum</code>) has a value of 1. There is no data since there are no previous rows, so it just returns 1.</p>
<p>In the second row, the value of <code>rowNum</code> is 2. The <code>cumSum</code> column already had a value of 1, so we’ll add 2 to it, for a result of 3.</p>
<p>With the third row, we’ll add the value in <code>rowNum</code> (3) to the value in <code>cumSum</code> (which also happened to be 3) and we’ll now have a cumulative sum of 6.</p>
<p>This repeats for each row, creating a cumulative summary.</p>
<p>You can also create a way to decrement the data by using a negative value for the <code>row_cumsum</code> parameter. For example, <code>row_cumsum(rowNum * -1)</code> could have been used to create a decrementing value much as spending money out of your checking account would decrement your balance. You’d just want to determine the best way to handle the beginning value (first row) of the dataset.</p>
<h2>Resetting the Cumulative Counter</h2>
<p>It’s possible you may not want to keep accumulating for all rows, but instead only have the accumulation for a group of rows. A common task is to reset the sum when a computer name changes, or perhaps the calendar month.</p>
<p>For this example, I’ve added a third column to our <code>datatable</code>, <code>rowBucket</code>. Whenever the value in <code>rowBucket</code> changes, I want to reset the cumulative sum value.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png"><img data-attachment-id="5323" data-permalink="https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/049-03_row_cumsum_reset/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png" data-orig-size="773,750" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="049.03_row_cumsum_reset" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=773" loading="lazy" width="773" height="750" src="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=773" alt="" class="wp-image-5323" srcset="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png 773w, https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=768 768w" sizes="(max-width: 773px) 100vw, 773px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>The <code>row_cumsum</code> supports a second parameter that is a <em>boolean</em> value. When true, the counter resets. Here, I’m using an equation to calculate “is the current rows <code>rowBucket</code> value not equal to the one from the previous row”. If this is true, in other words not equal, then the counter will reset.</p>
<p>Sure enough, on row 4 the <code>rowBucket</code> changed to <code>2</code>. On this row the cumulative sum reset itself. It now keeps adding up until the bucket number changes again, as it does with row 6.</p>
<h2>A Real World Example</h2>
<p>Using a <code>datatable</code> made the examples easy to understand, but it’s time to look at an example you might want to use in the “real world”.</p>
<p>Let’s imagine a scenario where you’ve detected a large amount of network traffic coming from one of the computers on your Azure network. You’d like to check the performance log table (<strong>Perf</strong>) to see how many bytes each computer sent in the last five minutes.</p>
<p>You need to see the number of bytes sent by a computer for each log entry, but you also want to see the total bytes sent by a computer for that time period. Let’s look at a query to accomplish this goal.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png"><img data-attachment-id="5325" data-permalink="https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/049-04_real_world/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png" data-orig-size="961,974" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="049.04_real_world" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=296" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=961" loading="lazy" width="961" height="974" src="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=961" alt="" class="wp-image-5325" srcset="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png 961w, https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=148 148w, https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=296 296w, https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=768 768w" sizes="(max-width: 961px) 100vw, 961px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We begin with our old buddy the <strong>Perf</strong> table. A <code>where</code> will limit the data to the last five minutes. A second where will limit the counter to just the one we are interested in, <code>Bytes Sent/sec</code>. Since we only need to see this data when the virtual Azure server sent data, we’ll add a final <code>where</code> to remove any rows where the <code>CounterValue</code> is zero.</p>
<p>Next, we’ll use a <code>project</code> to strip down the columns to only the three we are interested in: the <code>Computer</code>, <code>TimeGenerated</code>, and <code>CounterValue</code>.</p>
<p>We then want to use a <code>sort</code>, so the data for each computer will be grouped together, then within a Computer the time the performance data was generated. Note that since the default for a <code>sort</code> is descending order, an <code>asc</code> was added after the <code>TimeGenerated</code> so the entries would go from the oldest to the most recent.</p>
<p>I normally might include an <code>asc</code> after the <code>Computer</code> so the computer names would be sorted alphabetically from A to Z, but left it off for this example just to remind you that with a <code>sort</code> you can mix and match the <code>asc</code> and <code>desc</code> columns.</p>
<p>Using a <code>sort</code> has another benefit. If you did go back and read my post <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a> as I suggested in the introduction, you’ll know that the <code>sort</code> marks a dataset as safe for <em>serialzation</em>. In order to use Windowing Functions, such as <code>row_cumsum</code> and <code>prev</code>, a dataset needs to be safe for serialization.</p>
<p>The final line of the query is where the magic happens. Since using <code>sort</code> eliminated the need to use <code>serialize</code>, we can just use an <code>extend</code> to create a new column. I chose to name it <code>cumulativeBytes</code>.</p>
<p>We assign it the output of our <code>row_cumsum</code> Windowing Function. In the first parameter we pass in the <code>CounterValue</code>. In the second column we create an expression that will evaluate to true or false. We compare the <code>Computer</code> column for the current row and call the <code>prev</code> Windowing Function to get the <code>Computer</code> from the previous row of data.</p>
<p>If they are not equal, then the equation returns true. This will cause the <code>row_cumsum</code> to reset the cumulative sum.</p>
<p>Looking at the output, you can indeed see that occurred. The first computer in the list is <code>CH1-VM-CTS</code>. With each row it begins accumulating the <code>CounterValue</code> into the <code>cumulativeBytes</code> column.</p>
<p>When the <code>Computer</code> changed to <code>CH-DMAVM</code>, you can see the <code>cumulativeBytes</code> counter was reset. It kept accumulating the values for <code>CH-DMAVM</code> until the <code>Computer</code> changed to <code>CH-AVSMGMTVM</code> at which point it was again reset, and the pattern continues.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/">Fun With KQL Windowing Functions &#8211; Prev and Next</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>Cumulative sums are not an uncommon need when retrieving data. Kusto provides this ability with the Windowing Function <code>row_cumsum</code>, which you saw how to use in this post.</p>
<p>Our next post will continue the coverage of Kusto Windowing Functions by looking at the <code>row_rank_min</code> function.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/07/31/fun-with-kql-windowing-functions-row_cumsum/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/049.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/049.90_featured_image.png" medium="image">
			<media:title type="html">049.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/049.02_row_cumsum_basics.png?w=636" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/049.03_row_cumsum_reset.png?w=773" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/049.04_real_world.png?w=961" medium="image" />
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Prev and Next</title>
		<link>https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/</link>
					<comments>https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 24 Jul 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[KQL]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5307</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Prev and Next]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In this post we’ll continue our series on Kusto’s Windowing Functions by covering <code>prev</code> and <code>next</code>. If you’ve not read the introductory post, <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a>, you should do so now as it introduced several important concepts needed to understand how these functions are used.</p>
<p>So what do <code>prev</code> and <code>next</code> do? They allow you to retrieve a value in a column from a previous row, or the next (or upcoming) row. This can be very useful in many situations. For instance, calculating the time between two rows based on a datetime column, or the change in a value from one row to the next.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Prev Basics</h2>
<p>To make these examples simple, I’m going to use the <code>datatable</code> operator to generate a very simple dataset. For more on how <code>datatable</code> works, please see my post <a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png"><img data-attachment-id="5309" data-permalink="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/048-02_prev_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png" data-orig-size="716,764" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="048.02_prev_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=281" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=716" loading="lazy" width="716" height="764" src="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=716" alt="" class="wp-image-5309" srcset="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png 716w, https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=141 141w, https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=281 281w" sizes="(max-width: 716px) 100vw, 716px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Using a <code>let</code>, I’ve created a dataset named <code>SomeData</code>. It has nine rows and two columns: <code>rowNum</code> and <code>rowVal</code>.</p>
<p>After my <code>let</code>, I take the <code>SomeData</code> dataset and pipe it into a <code>serialize</code> so it can be used with Windowing Functions like <code>prev</code>. Refer back to my <a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">previous post</a> on <code>serialize</code> for more information on how serializing a dataset lets you use Windowing Functions.</p>
<p>Now the data pipes into an <code>extend</code>, where we add a new column I named <code>prvVal</code> (short for previous value). We then use <code>strcat</code> to combine a text string, <code>Previous Value was </code> with the output of our <code>prev</code> Windowing Function.</p>
<p>Into <code>prev</code> we pass one parameter, the name of the column from the previous row we want the data for. Here we want to pull data from the column <code>rowVal</code>.</p>
<p>As you can see in the output, the right most column displays our <code>Previous Value was </code> text string, plus the value from the <code>rowVal</code> column in the previous row.</p>
<h2>Even More Previous</h2>
<p>We can go back more than just one row. The <code>prev</code> function supports a second parameter that indicates the number of rows to go back.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png"><img data-attachment-id="5311" data-permalink="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/048-03_prev_back_two/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png" data-orig-size="1057,790" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="048.03_prev_back_two" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=1024" loading="lazy" width="1024" height="765" src="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=1024" alt="" class="wp-image-5311" srcset="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png 1057w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>First, I decided to use two extends. The first will copy the previous value into a variable, <code>prvVal2</code>. Into the <code>prev</code> function I pass two values, the first is the column name we want the data from. Here we’ll use <code>rowVal</code> again. The second parameter is the number of rows we want to go back, in this case we just used the value of <code>2</code>.</p>
<p>In the next <code>extend</code> I user <code>strcat</code> to combine the <code>prvVal2</code> variable with a text string and put it into the new column <code>prvValOutput</code>. I did this just to demonstrate you could pull a value from a previous row and use it in the query. I could have done other things with <code>prvVal2</code>, such as use it in a calculation.</p>
<h2>Previous Value? What Previous Value?</h2>
<p>You probably noticed that when we are on the first row, there is no previous value. Likewise, when on the first or second rows, and going back two there was no data. In this case the <code>prev</code> just returned a <code>null</code> value.</p>
<p>In the past I’ve written about functions like <code>iif</code> and <code>isnull</code> to help handle null values. Fortunately, <code>prev</code> eliminates the need for these as it supports and optional third parameter. Into it you can supply a value to use when the value returned by <code>prev</code> would otherwise be <code>null</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png"><img data-attachment-id="5312" data-permalink="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/048-04_prev_is_null/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png" data-orig-size="1094,777" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="048.04_prev_is_null" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=1024" loading="lazy" width="1024" height="727" src="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=1024" alt="" class="wp-image-5312" srcset="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png 1094w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>In our <code>prev</code> we first pass the column from the previous row we want the data from, <code>rowVal</code>. In this example we are only going to go back one row, but since we want to use the third parameter we have to supply a value in the second parameter position. In this example we’ll use the number <code>1</code>.</p>
<p>Finally in our third parameter we supply a value to be returned when the result of a <code>prev</code> would be null. Here we used the text <code>not valid for this row</code>, although we could have used a different datatype such as a numeric value or a datetime if that would have been more appropriate to our query.</p>
<h2>Next</h2>
<p>Next, let’s look at <code>next</code>. The <code>next</code> function behaves just like <code>prev</code>, except it will get data from the next row in our serialized dataset instead of a previous row.</p>
<p>Just like with <code>prev</code>, as the parameter to <code>next</code> we pass in the name of the column to get the data from.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png"><img data-attachment-id="5314" data-permalink="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/048-05_next_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png" data-orig-size="756,757" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="048.05_next_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=756" loading="lazy" width="756" height="757" src="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=756" alt="" class="wp-image-5314" srcset="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png 756w, https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=300 300w" sizes="(max-width: 756px) 100vw, 756px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>The <code>next</code> function also supports the optional second and third parameters. The second being a number indicating how many rows to go forward, the third being a value to use when <code>next</code> would otherwise return a null value.</p>
<p>Since you’ve already seen these in play I won’t create samples here, but you should be able to easily create them for yourself following the examples from <code>prev</code>.</p>
<h2>Calculating a Moving Average</h2>
<p>So it’s time for a more realistic example. Here I want to get the <code>% Processor Time</code> from the <strong>Perf</strong> table for a particular computer. I’m going to summarize it by hour. Then I want to create a moving average for the last three hours.</p>
<p>Most of the query will be pretty straightforward if you’ve been following my KQL series. I capture a start and end time using <code>let</code>. I then use the <strong>Perf</strong> table, followed by several <code>where</code> statements to limit the data.</p>
<p>Next I use <code>summarize</code> to create an average, bucketed by hour. In essence I’ll have an average of all the processor times for the 1 am hour, then 2 am, and so on.</p>
<p>After that we’ll sort them by the time of the day. Not only will the <code>sort</code> put the data in the order we want, it will also mark them as <em>serialized</em>. This means we can use them with our Window Function <code>prev</code>.</p>
<p>The last line is where the exciting things happen, so take a look and we’ll break it down.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png"><img data-attachment-id="5316" data-permalink="https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/048-06_moving_average/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png" data-orig-size="946,790" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="048.06_moving_average" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=946" loading="lazy" width="946" height="790" src="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=946" alt="" class="wp-image-5316" srcset="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png 946w, https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=768 768w" sizes="(max-width: 946px) 100vw, 946px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We begin with <code>extend</code> in order to create a new column, <code>movAvg</code>. We are then going to add three values. The first value is the <code>PctCpuTime</code> from the current row, which was calculated during the <code>summarize</code>.</p>
<p>Next, I want to add in the <code>PctCpuTime</code> from the previous row. To do that we’ll use the <code>prev</code> function, pass in the <code>PctCpuTime</code> as the column to get, <code>1</code> to indicate we want to go back one row, then tell it to return a <code>0</code> (zero) when the previous row would return <code>null</code>.</p>
<p>This is then repeated only we pass in a value of <code>2</code>, indicating we should go back two rows.</p>
<p>After the closing parentheses we divide by <code>3.0</code>. Note its important to include the <code>.0</code> otherwise it would try to create an integer output and we want a full decimal value.</p>
<p>And there you go, we now have an average for the last three rows of data.</p>
<p>Let me acknowledge, by returning a <code>0</code> for missing (null) values from the <code>prev</code>, the averages for the first two rows will be off. In a real world situation you’d want to make sure to take this into account, creating a solution appropriate to your situation. For this example I used zero in order to keep things simple.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/07/11/fun-with-kql-ago/">Fun With KQL &#8211; Ago</a></p>
<p><a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a></p>
<p><a href="https://arcanecode.com/2022/10/03/fun-with-kql-iif/">Fun With KQL &#8211; IIF</a></p>
<p><a href="https://arcanecode.com/2022/10/17/fun-with-kql-isnull-and-isempty/">Fun With KQL &#8211; IsNull and IsEmpty</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2022/07/04/fun-with-kql-now/">Fun With KQL &#8211; Now</a></p>
<p><a href="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/">Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/10/31/fun-with-kql-strcat/">Fun With KQL &#8211; StrCat</a></p>
<p><a href="https://arcanecode.com/2022/05/16/fun-with-kql-summarize/">Fun With KQL &#8211; Summarize</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>This post continued our journey with KQL Windowing Functions, seeing how the useful <code>prev</code> and <code>next</code> functions could get data from adjacent rows of a serialized dataset. In our next post we’ll be looking at a Windowing Function to let us get cumulative sums.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/07/24/fun-with-kql-windowing-functions-prev-and-next/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/048.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.90_featured_image.png" medium="image">
			<media:title type="html">048.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.02_prev_basics.png?w=716" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.03_prev_back_two.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.04_prev_is_null.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.05_next_basics.png?w=756" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/048.06_moving_average.png?w=946" medium="image" />
	</item>
		<item>
		<title>Fun With KQL Windowing Functions &#8211; Serialize and Row_Number</title>
		<link>https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/</link>
					<comments>https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Tue, 18 Jul 2023 03:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[Kusto]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5290</guid>

					<description><![CDATA[Fun With KQL Windowing Functions - Serialize and Row_Number]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>The Kusto Query Language includes a set of functions collectively known as <em>Window Functions</em>. These special functions allow you to take a row and put it in context of the entire dataset. For example, creating row numbers, getting a value from the previous row, or maybe the next row.</p>
<p>In order for Window Functions to work, the dataset must be <em>serialized</em>. In this post we’ll cover what serialization is and how to create serialized datasets. This is a foundational post, as we’ll be referring back to it in future posts that will cover some of the KQL Windowing Functions.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Serialization</h2>
<p>When a dataset is serialized, its data is placed in a specific order and that order is retained as the dataset goes through various transformations. Some of the Windowing Functions that require a serialized dataset to work are <code>row_number</code>, <code>next</code>, and <code>prev</code> to name just a few that will be covered in this and future posts.</p>
<p>There are some KQL functions that by their nature emit a dataset that is already ordered, in other words <em>serialized</em>. These include functions that I’ve already written about such as <a href="https://arcanecode.com/2022/06/20/fun-with-kql-top/"><code>top</code></a> and <a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/"><code>sort</code></a>.</p>
<p>There are also some operators that if they receive a serialized dataset as input, will preserve the serialized ordering when the data is output. I’ve written about all of these in past posts, and they include: <a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/"><code>extend</code></a>, <a href="https://arcanecode.com/2022/11/21/fun-with-kql-mv-expand/"><code>mv-expand</code></a>, <a href="https://arcanecode.com/2022/08/01/fun-with-kql-parse/"><code>parse</code></a>, <a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/"><code>project</code></a>, <a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-away</code></a>, <a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-rename</code></a>, <a href="https://arcanecode.com/2022/05/02/fun-with-kql-take/"><code>take</code></a> and <a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/"><code>where</code></a>.</p>
<p>So the big question is, what if I need to use a Window Function but my data is not already serialized?</p>
<h2>The Serialize Operator</h2>
<p>For situations when you do not have an already serialized dataset you can easily create one using the <code>serialize</code> operator. Here’s a simple example.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png"><img data-attachment-id="5293" data-permalink="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/047-02_serialize_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png" data-orig-size="1191,633" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="047.02_serialize_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=1024" loading="lazy" width="1024" height="544" src="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=1024" alt="" class="wp-image-5293" srcset="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png 1191w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>All we have to do is take our dataset and pipe it into the <code>serialize</code> operator. The dataset will then have its order preserved, and will mark the dataset safe for use with KQLs Windowing Functions, similar to when a social media site lets you mark yourself safe from a hurricane, tornado, or all night <a href="https://www.youtube.com/@HeavyDSparks">HeavyDSparks</a> marathon on YouTube. (#GuiltyPleasures)</p>
<p>Of course we don’t see any visible change here, but now we can use it with a Windowing Function. If you peeked at the post title, you’ve probably guessed already that for this post we’ll use the Window Function <code>row_number</code>.</p>
<p>But first…</p>
<h2>A Warning!</h2>
<p>Eagle eyed readers may notice the <code>serialze</code> in the screen shot above is underlined with red squiggles. This indicates there is a warning associated with this operator.</p>
<p>If we hover over the <code>serialize</code> operator the interface will display the specific warning to us.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png"><img data-attachment-id="5294" data-permalink="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/047-03_serialize_warning/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png" data-orig-size="1362,205" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="047.03_serialize_warning" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=1024" loading="lazy" width="1024" height="154" src="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=1024" alt="" class="wp-image-5294" srcset="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png 1362w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>It’s letting us know that in addition to being marked safe for Kusto Window Functions, the dataset will also be stored in memory. This could adversely affect the query runtime.</p>
<p>Sometimes it’s necessary to use <code>serialize</code> in order to get the results you need, but keep it in mind. Should you have a slow running query think about reducing the size of the dataset or see if there are other ways to accomplish the same results.</p>
<p>That said, let’s see how to use a basic Window Function, the <code>row_number</code>.</p>
<h2>Row_Number</h2>
<p>Calling the <code>row_number</code> function is easy. After the <code>serialize</code> operator we first provide a new column name that will hold our row number, here I used <code>MyRowNumber</code>. I then assign it the function <code>row_number()</code>. Note because it is a function we have to include the parenthesis after the function name.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png"><img data-attachment-id="5296" data-permalink="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/047-04_row_number_with_serialize/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png" data-orig-size="1205,838" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="047.04_row_number_with_serialize" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=1024" loading="lazy" width="1024" height="712" src="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=1024" alt="" class="wp-image-5296" srcset="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png 1205w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>In the very right most column you can see our new row number column, <code>MyRowNumber</code>. The value is incremented with each row.</p>
<h2>Row_Number Without Serialize</h2>
<p>It’s possible to call the <code>row_number</code> function without using the <code>serialize</code> operator. As discussed earlier in this post the Windowing Functions need a serialized dataset to work with, and there are a few operators that will produce a dataset that is already safe to be serialized, such as <a href="https://arcanecode.com/2022/06/20/fun-with-kql-top/"><code>top</code></a> and <a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/"><code>sort</code></a>.</p>
<p>In addition we have the operators that will preserve serialization when a serialized dataset is passed in. As a refresher these operators include: <a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/"><code>extend</code></a>, <a href="https://arcanecode.com/2022/11/21/fun-with-kql-mv-expand/"><code>mv-expand</code></a>, <a href="https://arcanecode.com/2022/08/01/fun-with-kql-parse/"><code>parse</code></a>, <a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/"><code>project</code></a>, <a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-away</code></a>, <a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-rename</code></a>, <a href="https://arcanecode.com/2022/05/02/fun-with-kql-take/"><code>take</code></a> and <a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/"><code>where</code></a>.</p>
<p>In this example, we’ll use a <code>sort</code> to get our data in the order we want, then use an <code>extend</code> to add the new <code>MyRowNumber</code> column by calling the <code>row_number()</code> function.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png"><img data-attachment-id="5298" data-permalink="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/047-05_row_number_without_serialize/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png" data-orig-size="1013,840" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="047.05_row_number_without_serialize" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=1013" loading="lazy" width="1013" height="840" src="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=1013" alt="" class="wp-image-5298" srcset="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png 1013w, https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=768 768w" sizes="(max-width: 1013px) 100vw, 1013px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>As you can see, after the <code>sort</code> we call <code>extend</code> and use the same syntax as before, creating the new column of <code>MyRowNumber</code> and assigning it the function <code>row_number()</code>. Looking to the right you can see the new <code>MyRowNumber</code> column in the output.</p>
<p>You also may notice the <code>row_number</code> function now has a red squiggly line under it, indicating a warming. Let’s go see what that’s all about…</p>
<h2>Another Warning!</h2>
<p>Hovering over the <code>row_number</code> displays the following warning:</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png"><img data-attachment-id="5299" data-permalink="https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/047-06_row_number_warning/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png" data-orig-size="1542,210" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="047.06_row_number_warning" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=1024" loading="lazy" width="1024" height="139" src="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=1024" alt="" class="wp-image-5299" srcset="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png 1542w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>This warning is similar to the one you saw when we used the <code>serialzie</code> operator. It states that by calling <code>row_number</code> the data will be stored in memory, which could slow down the query.</p>
<p>It does have an interesting implication though. Using <code>sort</code> means the data <em>can</em> be serialized, but doesn’t mean it is. The warning states it’s the calling of a Windowing Function, such as our new friend <code>row_number</code>, that actually triggers the data to be serialized.</p>
<h2>Serialize and Window Functions Recap</h2>
<p>When we talk about Windowing Functions, I wanted to stress an important point. The <code>serialize</code> operator is used to convert a dataset that is not already safe for serialization into one that is. The serialization is required in order to use a Windowing Function such as <code>row_number</code> or one of the other’s we’ll cover in this series.</p>
<p>There are a list of other operators though that output data that is already safe for serialization, in other words if we use one of these operators then we can use a Windowing Function without the need to use <code>serialize</code>. I mentioned <a href="https://arcanecode.com/2022/06/20/fun-with-kql-top/"><code>top</code></a> and <a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/"><code>sort</code></a> already, but for completeness here is the full list.</p>
<ul>
<li><a href="https://arcanecode.com/2022/06/20/fun-with-kql-top/"><code>top</code></a></li>
<li><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/"><code>sort</code></a></li>
<li><code>range</code></li>
<li><code>getschema</code></li>
<li><code>top-hitters</code></li>
</ul>
<p>I’ve already done blog posts for the first two (you can click on the command to follow the link to the post), and have one planned for <code>range</code>. If there’s interest I may cover the other two.</p>
<p>For completeness, let me go ahead and list the operators that will preserve the serialized state of the data when used. Note each is linked to a blog post I’ve done previously which covers each operator.</p>
<ul>
<li><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/"><code>extend</code></a></li>
<li><a href="https://arcanecode.com/2022/11/21/fun-with-kql-mv-expand/"><code>mv-expand</code></a></li>
<li><a href="https://arcanecode.com/2022/08/01/fun-with-kql-parse/"><code>parse</code></a></li>
<li><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/"><code>project</code></a></li>
<li><a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-away</code></a></li>
<li><a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/"><code>project-rename</code></a></li>
<li><a href="https://arcanecode.com/2022/05/02/fun-with-kql-take/"><code>take</code></a></li>
<li><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/"><code>where</code></a></li>
</ul>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2022/11/21/fun-with-kql-mv-expand/">Fun With KQL &#8211; MV-Expand</a></p>
<p><a href="https://arcanecode.com/2022/08/01/fun-with-kql-parse/">Fun With KQL &#8211; Parse</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/06/06/fun-with-kql-variants-of-project/">Fun With KQL &#8211; Project &#8211; Variants of Project</a> (Project-Away and Project-Rename)</p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/05/02/fun-with-kql-take/">Fun With KQL &#8211; Take</a></p>
<p><a href="https://arcanecode.com/2022/06/20/fun-with-kql-top/">Fun With KQL &#8211; Top</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>In this post we learned hot to use <code>serialize</code> to create a dataset with which we can call one of the Kusto Languages Windowing Functions. We also learned there are a handful of operators that already produce datasets safe for serialization, and can be used with Windowing Functions without the requirement to use the <code>serialize</code> operator.</p>
<p>Finally we saw the <code>row_number</code> Windowing Function in action. In future posts we’ll cover more of the Windowing Functions built into the Kusto Query Language.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/07/17/fun-with-kql-windowing-functions-serialize-and-row_number/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/07/047.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.90_featured_image.png" medium="image">
			<media:title type="html">047.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.02_serialize_basics.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.03_serialize_warning.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.04_row_number_with_serialize.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.05_row_number_without_serialize.png?w=1013" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/07/047.06_row_number_warning.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL &#8211; Datatable and Calculations</title>
		<link>https://arcanecode.com/2023/07/10/fun-with-kql-datatable-and-calculations/</link>
					<comments>https://arcanecode.com/2023/07/10/fun-with-kql-datatable-and-calculations/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 10 Jul 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<category><![CDATA[Datatable]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5272</guid>

					<description><![CDATA[Fun With KQL - Datatable and Calculations]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In the conclusion of my last post, <a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a>, I mentioned a <code>datatable</code> can also be useful when you need to do special calculations. I decided it really needed further explanation and created this post to dive in a bit deeper.</p>
<p>If you haven’t read my <code>datatable</code> post yet, you should as I’ll refer back to it. Go ahead, I’ll wait.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Datatable and Calculations</h2>
<p>For this example we’ll revisit the <strong>Perf</strong> table. The <strong>Perf</strong> table has two main columns that we’ll use in this example, <code>CounterName</code> and <code>CounterValue</code>.</p>
<p>Our goal for this query is to multiply the <code>CounterValue</code> by some number, based on the <code>CounterName</code>. We could of course use a <code>case</code> or <code>iif</code> within the query, but that would result in a query that is long and hard to read and later modify if we need to.</p>
<p>Using a <code>datatable</code> will result in a query that is much more readable and maintainable. As the actual code for the query is a bit long I’ll place it below to make it easy to follow along. Note I’ll only skim over things we covered in the <a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">previous post</a>, refer to it for more detailed explanations.</p>
<pre><code>let CounterMultipliers = datatable (CounterName:string, Multiplier:int)
[
  &quot;CounterName&quot;, 2,
  &quot;restartTimeEpoch&quot;, 3,
  &quot;memoryWorkingSetBytes&quot;, 4,
  &quot;memoryRssBytes&quot;, 5,
  &quot;memoryRequestBytes&quot;, 2,
  &quot;memoryLimitBytes&quot;, 3,
  &quot;memoryCapacityBytes&quot;, 4,
  &quot;memoryAllocatableBytes&quot;, 5,
  &quot;cpuUsageNanoCores&quot;, 2,
  &quot;cpuRequestNanoCores&quot;, 3,
  &quot;cpuLimitNanoCores&quot;, 4,
  &quot;cpuCapacityNanoCores&quot;, 5,
  &quot;cpuAllocatableNanoCores&quot;, 2,
  &quot;Total Bytes Transmitted&quot;, 3,
  &quot;Total Bytes Received&quot;, 4,
  &quot;Logical Disk Bytes/sec&quot;, 5,
  &quot;Free Megabytes&quot;, 2,
  &quot;Disk Writes/sec&quot;, 3,
  &quot;Disk Write Bytes/sec&quot;, 4,
  &quot;Disk Transfers/sec&quot;, 5,
  &quot;Disk Reads/sec&quot;, 2,
  &quot;Disk Read Bytes/sec&quot;, 3,
  &quot;Disk Bytes/sec&quot;, 4,
  &quot;Bytes Sent/sec&quot;, 5,
  &quot;Bytes Received/sec&quot;, 2,
  &quot;Avg. Disk sec/Write&quot;, 3,
  &quot;Avg. Disk sec/Transfer&quot;, 4,
  &quot;Avg. Disk sec/Read&quot;, 5,
  &quot;Available MBytes Memory&quot;, 2,
  &quot;Available MBytes&quot;, 3,
  &quot;% Used Space&quot;, 4,
  &quot;% Processor Time&quot;, 5,
  &quot;% Free Space&quot;, 6
];
let PerfData = view() {
Perf
| project CounterName
        , CounterValue
        , Computer
        , ObjectName
        , TimeGenerated
};
PerfData
| join CounterMultipliers on CounterName
| project CounterName
        , CounterValue
        , Multiplier
        , CounterExpanded = CounterValue * Multiplier
        , Computer
        , ObjectName
        , TimeGenerated
</code></pre>
<p>We begin with a <code>let</code>, where we will create a new <code>datatable</code>. I chose to name it <code>CounterMultipliers</code>, but we could have used any name we wanted.</p>
<p>The <code>datatable</code> will have two columns, the <code>CounterName</code> which is a <code>string</code>, and the <code>Multiplier</code> which I made an <code>int</code>.</p>
<p>I used a simple query to get the list of <code>CounterName</code> values:</p>
<pre><code>Perf
| distinct CounterName
| sort by CounterName
</code></pre>
<p>I then copied the output into my query editor. I wrapped the names in quotes so they would be interpreted as strings. Next I have a comma, then the integer value to use for the multiplier.</p>
<p>Note I just picked a few random values to use here. In a real world situation this kind of operation, multiplying counter values, might not make much sense, but it will serve OK for this example.</p>
<p>After finishing the <code>datatable</code> definition I use a second <code>let</code> to create a temporary view on top of the <strong>Perf</strong> table and named the view <code>PerfData</code>. For more on this technique refer back to the <a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a> post.</p>
<p>Now we take our <code>PerfData</code> view and join it to our <code>datatable</code>, <code>CounterMultipliers</code>. Note that I used the best practice of naming the counter name column in the <code>datatable</code> the same as in the <code>PerfData</code> view. It makes the query easier to read, and avoids the need for <code>$left</code> and <code>$right</code> as I described in the previous post.</p>
<p>Finally we pipe the output of the <code>join</code> into a <code>project</code> operator. I return all the columns, but add a new one, <code>CounterExpanded</code>. For its calculation I simply take the <code>CounterValue</code> column from the <code>PerfData</code> view and multiply it by the <code>Multiplier</code> column from the `datatable.</p>
<p>Below you can see the output from the query.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png"><img data-attachment-id="5274" data-permalink="https://arcanecode.com/2023/07/10/fun-with-kql-datatable-and-calculations/046-11_first_try/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png" data-orig-size="1790,868" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="046.11_first_try" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=1024" loading="lazy" width="1024" height="496" src="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=1024" alt="" class="wp-image-5274" srcset="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png 1790w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>If you look in the lower right though, you will spot an issue. The query only returned 32 rows.</p>
<p>This demonstrates a critical piece of information when it comes to the <code>join</code>. For each row in the first table, <code>PerfData</code>, it grabs a row from the second table. Since we had 32 rows in the <code>datatable</code>, only 32 rows were returned.</p>
<h2>Fixing the Query</h2>
<p>Fixing the query is simple. All we need to do is swap the order of the two tables.</p>
<pre><code>CounterMultipliers
| join PerfData on CounterName
| project CounterName
        , CounterValue
        , Multiplier
        , CounterExpanded = CounterValue * Multiplier
        , Computer
        , ObjectName
        , TimeGenerated
</code></pre>
<p>Note I only included the last part of the query, everything above this piece is still the same.</p>
<p>Now look at the output.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png"><img data-attachment-id="5275" data-permalink="https://arcanecode.com/2023/07/10/fun-with-kql-datatable-and-calculations/046-12_fixed_query/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png" data-orig-size="1782,952" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="046.12_fixed_query" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=1024" loading="lazy" width="1024" height="547" src="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=1024" alt="" class="wp-image-5275" srcset="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png 1782w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>In the lower right, as well as in the blue area at the top of the output, you can see over 300,000 rows were returned. This is the output we expect, every row in the <strong>Perf</strong> table (from the view) linked to each row in the <code>CounterMultipliers</code> <code>datatable</code>.</p>
<h2>Including and Excluding Columns</h2>
<p>In this example, in the output I included the <code>Multiplier</code> column. This was done so you could see the data and test the calculation for yourself. In a normal situation you likely wouldn’t be doing this.</p>
<p>I also included the <code>CounterValue</code> column. Again, this may or may not be needed, you could choose to have just the <code>CounterExpanded</code> column.</p>
<p>Think about the output, and how it will be used to decide if you want to include these types of columns in your query output.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/10/10/fun-with-kql-case/">Fun With KQL &#8211; Case</a></p>
<p><a href="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/">Fun With KQL &#8211; Datatable</a></p>
<p><a href="https://arcanecode.com/2022/10/03/fun-with-kql-iif/">Fun With KQL &#8211; IIF</a></p>
<p><a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/05/16/fun-with-kql-summarize/">Fun With KQL &#8211; Summarize</a></p>
<h2>Conclusion</h2>
<p>In this post we learned how to use a <code>datatable</code> to create calculated values. This made the code much cleaner, and easier to read.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/07/10/fun-with-kql-datatable-and-calculations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/046.90_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.90_featured_image.png" medium="image">
			<media:title type="html">046.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.11_first_try.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.12_fixed_query.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL &#8211; Datatable</title>
		<link>https://arcanecode.com/2023/07/03/fun-with-kql-datatable/</link>
					<comments>https://arcanecode.com/2023/07/03/fun-with-kql-datatable/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 03 Jul 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<category><![CDATA[Datatable]]></category>
		<category><![CDATA[Kusto Query Language]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5264</guid>

					<description><![CDATA[Fun With KQL - Datatable]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>As you’ve seen with the <code>join</code> in my <a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a> post it can be useful to combine two tables in order to clarify the output. What if, though, you need data that isn’t in an existing table?</p>
<p>That’s where the <code>datatable</code> operator comes into use. The <code>datatable</code> allows you to create a table of data right within the query. We’ll see a few useful examples in this post.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>DataTable Basics</h2>
<p>Let’s say you have a table that stores colors. These colors though are stored in decimal format, the application that uses them converts them to an HTML hex color. For our report though, we’d like to convert these to a friendly name, which is not stored in the source data.</p>
<p>To accomplish this we can create a color table with the codes as well as friendly color names. We’ll use the <code>datatable</code> operator to do this.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png"><img data-attachment-id="5265" data-permalink="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/046-01_basic_datatable/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png" data-orig-size="1745,1061" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="046.01_basic_datatable" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=1024" loading="lazy" width="1024" height="622" src="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=1024" alt="" class="wp-image-5265" srcset="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png 1745w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We’ll need to use our old friend <code>let</code>. Following we declare a name for our <code>datatable</code>, here we used <code>HTMLColors</code> although we could use any name we want.</p>
<p>After the equal sign we use the <code>datatable</code> operator. In the parenthesis we declare our column names and their data types. The first is <code>Name</code>, then a colon, then the data type of <code>string</code>. Our second column is also a string, with the name of <code>HexCode</code>.</p>
<p>The final column is <code>DecimalValue</code>, and its datatype is <code>int</code>. You can find a complete list of Kusto data types in the Microsoft documentation, <a href="https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/scalar-data-types/">Scalar data types</a>.</p>
<p>After we finish the <code>datatable</code> declaration with a closing right parenthesis, we have an opening square bracket then declare our data. Here I put each row of data on a line by itself, this is a good practice to make it easy to read and modify.</p>
<p>As you can see, our first row is:</p>
<pre><code>&quot;Red&quot;,	&quot;#FF0000&quot;, 16711680,
</code></pre>
<p>First is what I call our <em>friendly name</em> associated with the color, followed by a comma. We wrapped it in double quotes, since it is a string datatype.</p>
<p>Then we have the hex color code, also wrapped in quotes to make it a string, followed by a comma. Finally comes the decimal value, which is just an integer number, no quotes required.</p>
<p>Then line ends in a comma, then we proceed to the next line of data. At the end of our data, the row with <code>Aquamarine</code>, we do not have a comma since that is the last row of data. We have a closing square bracket to finish off the <code>datatable</code> data, then a semicolon as the KQL query will continue.</p>
<p>Next have the name of our datatable, piped into a <code>project</code>, then we listed the three columns in the datatable.</p>
<p>As you can see in the image above, the output section has a list of colors, hex values, and decimal value. Note that a few scrolled off the bottom of the screen.</p>
<p>Now we could join this to a table, linking on the <code>DecimalValue</code> column and display the friendly <code>Name</code> column in the output.</p>
<h2>Datatable In Practice</h2>
<p>Let’s look at an example of the <code>datatable</code> in practice. The <strong>Perf</strong> table has a column, <code>ComputerName</code>. A lot of the computer names are rather cryptic though. It’d be nice to have a friendly, human readable name that clearly says what the computer is used for, rather than unclear like <code>JBOX10</code>.</p>
<p>Let’s take a look at the query needed to add friendly names to our <strong>Perf</strong> table output.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png"><img data-attachment-id="5267" data-permalink="https://arcanecode.com/2023/07/03/fun-with-kql-datatable/046-02_datatable_realistic/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png" data-orig-size="1329,982" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="046.02_datatable_realistic" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=1024" loading="lazy" width="1024" height="756" src="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=1024" alt="" class="wp-image-5267" srcset="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png 1329w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>We begin with a <code>let</code> and define a <code>datatable</code> we’ll call <code>computers</code>. It will have two columns, <code>ComputerName</code> and <code>FriendlyName</code>, both of which are strings.</p>
<p>We fall into our data, each line is simply the computer name as found in the <strong>Perf</strong> table, followed by the friendly name we want to use.</p>
<p>Next comes another <code>let</code> in which we create a datatable from <strong>Perf</strong> for the last five minutes, and use <code>project</code> to pick out a few columns. We’ve named this datatable <code>PerfInfo</code>.</p>
<p>Now we take our <code>computer</code> datatable and join it to <code>PerfInfo</code>. Because the column we are joining on has different names in each table, I had to use the <code>$left</code> and <code>$right</code>, as described in my <a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a> post.</p>
<p>We then <code>project</code> the columns we want, and use <code>sort</code> to order the output.</p>
<p>I should mention I just guessed at the friendly names for some of the computer names in the <strong>Perf</strong> table. I have no idea if JBOX10 is really the XBox Java Server, but it just sounded good for this demo.</p>
<h2>Naming DataTable Columns</h2>
<p>I just wanted to mention that normally I would use the same column name in the <code>datatable</code> that is used in the table I’m joining. For example, I would use just <code>Computer</code> in the <code>datatable</code> so it would match up with the <code>Computer</code> column in the <strong>Perf</strong> table. That way I wouldn’t have to use the <code>$left</code> and <code>$right</code> syntax.</p>
<p>For this example though, I deliberately used a different name so I could remind you of the ability to use <code>$left</code> and <code>$right</code> to join tables when the column name is different.</p>
<p>The most frequent time you’d need this is when you are joining multiple tables with different column names for the same data, which as anyone who has worked with databases for any length of time happens far too often.</p>
<p>Again, for more information on this technique see my <a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a> post.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/07/11/fun-with-kql-ago/">Fun With KQL &#8211; Ago</a></p>
<p><a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>The <code>datatable</code> can be a useful operator for situations where you want to provide user friendly names, but don’t have an existing table that contains them.</p>
<p>It could also be used if you needed to do calculations. For example, rather than using <code>iif</code> statements you could create a <code>datatable</code> with a country code and a standard shipping amount, then in the table use that shipping amount in a calculation, perhaps adding it to the total value of a purchase.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses <a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a> and <a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a>, two of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a> . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/07/03/fun-with-kql-datatable/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/046.98_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.98_featured_image.png" medium="image">
			<media:title type="html">046.98_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.01_basic_datatable.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/046.02_datatable_realistic.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL &#8211; Union Modifiers</title>
		<link>https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/</link>
					<comments>https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 26 Jun 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5253</guid>

					<description><![CDATA[Fun With KQL - Union Modifiers]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In my previous post, <a href="https://arcanecode.com/2023/06/19/fun-with-kql-union/">Fun With KQL &#8211; Union</a> I covered how to use the <code>union</code> operator to merge two tables or datasets together. The <code>union</code> has a few helpful <em>modifiers</em>, which I’ll cover in this post.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>The Kind Modifier</h2>
<p>By default, when executing a Kusto Query if a column is <em>null</em> for every row in the result, that column is not displayed in the output. This is the behavior when using <code>union</code> without the <code>kind</code> a modifier. By default the kind modifier is set to <code>kind=inner</code>.</p>
<p>It is possible to force the <code>union</code> to display all columns, even if all the values for a column are null. To do so, after the <code>union</code> add <code>kind=outer</code> as shown in the example below.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png"><img data-attachment-id="5256" data-permalink="https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/045-12_kind_outer/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png" data-orig-size="1157,1028" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.12_kind_outer" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=1024" loading="lazy" width="1024" height="909" src="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=1024" alt="" class="wp-image-5256" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png 1157w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Unfortunately, there’s not enough space to display all the output, but if you execute your own queries you’ll find columns for which every value is null in the output.</p>
<p>As a side note, the order of the modifiers isn’t important. The <code>withsource</code> could have been placed before the <code>kind</code>, for example.</p>
<h2>The IsFuzzy Modifier</h2>
<p>We’ve all been there. You have a query that’s been working fine, then all of a sudden it fails because someone deleted a table.</p>
<p>You may also be in a situation where you wish to union two tables, but the second table is a temporary table. Sometimes its there, sometimes not. You’d like to write a query to handle it.</p>
<p>Fortunately <code>union</code> has a modifier, <code>isfuzzy</code>. When you set it to true, it will successfully execute the query even if the second table is absent.</p>
<p>In this example I will <code>union</code> two tables, <code>Update</code> and <code>ArcaneCode</code>. Obviously there is no table named <code>ArcaneCode</code> in the LogAnalytics sample database.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png"><img data-attachment-id="5258" data-permalink="https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/045-13_isfuzzy/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png" data-orig-size="1120,554" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.13_isfuzzy" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=1024" loading="lazy" width="1024" height="506" src="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=1024" alt="" class="wp-image-5258" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png 1120w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>As you can see, Kusto still executed the query successfully. It simply ignored the absence of <code>ArcaneCode</code>.</p>
<h2>Putting It All Together</h2>
<p>I’ll wrap this series on <code>union</code> up with a more complex but real world example. This query might be one you want to use for troubleshooting.  Let’s look at the query first, then we’ll see the results.</p>
<pre><code>let compName = &quot;JBOX10&quot;;
let dateDiffInDays = ( date1:datetime, date2:datetime = datetime(2023-01-01) )
                     { 
                       (date1 - date2) / 1d 
                     };
let UpdtSum = view() {
  UpdateSummary
  | where Computer == compName
  | project Computer
          , ComputerEnvironment
          , ManagementGroupName
          , OsVersion
          , Resource
          , ResourceGroup
          , SourceSystem
          , Type
          , NETRuntimeVersion
          , TimeGenerated
  } ;
let Updt = view() {
  Update
  | where Computer == compName
  | project Computer
          , ComputerEnvironment
          , ManagementGroupName
          , OSVersion
          , Resource
          , ResourceGroup
          , SourceSystem
          , Type
          , Title
          , UpdateState
          , TimeGenerated 
  } ;
union withsource = &quot;SourceTable&quot;
      UpdtSum
    , Updt
| extend DaysSinceStartOfYear=dateDiffInDays(TimeGenerated)

</code></pre>
<p>It begins with a <code>let</code>, in which we define a variable, <code>compName</code>, to hold the name of the computer we want to get data for. This will make it easy to reuse the query with other computers.</p>
<p>In the next <code>let</code> we will create our own <em>function</em> to calcuate the difference between two dates. I’ll cover functions in more detail in a future post, but for now let me provide a simple overview.</p>
<p>After giving the function a name, here <code>dateDiffInDays</code>, we have a set of parenthesis. Inside we declare the parameters for the function. The first parameter is named <code>date1</code>, although we could use any name we want here such as <code>endDate</code>, <code>thruDate</code>, or even <code>HeyHereIsTheThruDateWeWantToUse</code>.</p>
<p>Following is a colon, then the <em>datatype</em> for the variable. In this case it will be a <code>datetime</code> datatype. After this is a comma, then the second parameter.</p>
<p>We’ll call this one <code>date2</code> and it also be of type <code>datetime</code>. Then we have something interesting, an equal sign. With this we can assign a default value to this parameter, if the user fails to pass in a value the default is used.</p>
<p>In this example we want it to be from the start of the year, so we entered <code>2023-01-01</code>. If that’s all we were to put though, KQL would try to do a calculation and generate an error, since the result of 2021 isn’t a datetime datatype.</p>
<p>To fix this we need to wrap the date in the <code>datetime()</code> function, which is built into KQL. This will correctly convert the date to January 1, 2023.</p>
<p>We then have a set of squiggly braces {}, in which we define our function. Here the function is only one line. We subtract date2 from date1, and wrap it in parenthesis so that calculation will be done first.</p>
<p>We then divide it by <code>1d</code> to convert it to the number of days. The result is then returned. For more on datetime math, see my post <a href="https://arcanecode.com/2022/08/08/fun-with-kql-datetime-arithmetic/">Fun With KQL &#8211; DateTime Arithmetic</a>.</p>
<p>Next are two <code>let</code> statements where I create views on top of the <code>UpdateSummary</code> and <code>Update</code> tables. Since I covered this method in the previous post <a href="https://arcanecode.com/2023/06/19/fun-with-kql-union/">Fun With KQL &#8211; Union</a>, I won’t go into any further detail here.</p>
<p>We then fall into the hero of our story, the <code>union</code>. Having declared our data with the <code>let</code> statements its very easy to read.</p>
<p>Finally we finish up with an <code>extend</code>. We create a new column, <code>DaysSinceStartOfYear</code>. We assign it the function <code>dateDiffInDays</code>, and pass in the <code>TimeGenerated</code> column. This will be placed in the functions <code>date1</code> parameter.</p>
<p>Since we didn’t pass in a second parameter, the default value of Jan 1, 2023 will be used as the value for <code>date2</code>.</p>
<p>Let’s take a look at the result of our query.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png"><img data-attachment-id="5260" data-permalink="https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/045-14_all_together/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png" data-orig-size="1040,754" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.14_all_together" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=1024" loading="lazy" width="1024" height="742" src="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=1024" alt="" class="wp-image-5260" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png 1040w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>I expanded one of the rows from the <code>Updt</code> dataset so you could see all the columns (there were too many to fit on a single screen width wise). At the bottom of the expanded rows you can see our calculated value of <code>DateSinceStartOfYear</code>, showing <code>146.465</code> days.</p>
<p>This worked, by the way, because both tables had a column named <code>TimeGenerated</code>. If the column name was different between the tables, for example table one called it <code>TimeGen</code> and table two <code>GeneratedTime</code>, you could just rename them within the view definitions using <code>project</code>. For example:</p>
<p><code>project MyTimeGenerated = TimeGen, ...more columns</code></p>
<p>and</p>
<p><code>project MyTimeGenerated = GeneratedTime, ...more columns</code></p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/08/08/fun-with-kql-datetime-arithmetic/">Fun With KQL &#8211; DateTime Arithmetic</a></p>
<p><a href="https://arcanecode.com/2022/05/23/fun-with-kql-extend/">Fun With KQL &#8211; Extend</a></p>
<p><a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2023/06/19/fun-with-kql-union/">Fun With KQL &#8211; Union</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>With this post we’ve added to our knowledge of the KQL <code>union</code> operator. We saw two of its useful modifiers, <code>kind</code> and <code>isfuzzy</code>. Finally we wrapped it up with an example that put everything we’ve learned together, plus introduced the concept of <em>functions</em> within the Kusto Query Language.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses on the Kusto Query Language, part of their Kusto Learning Path.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/06/26/fun-with-kql-union-modifiers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/045.95_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.95_featured_image.png" medium="image">
			<media:title type="html">045.95_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.12_kind_outer.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.13_isfuzzy.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.14_all_together.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL &#8211; Union</title>
		<link>https://arcanecode.com/2023/06/19/fun-with-kql-union/</link>
					<comments>https://arcanecode.com/2023/06/19/fun-with-kql-union/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 19 Jun 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5235</guid>

					<description><![CDATA[Fun With KQL - Union]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In today’s post we will look at the <code>union</code> operator. A <code>union</code> will create a result set that combines data from two or more tables into a single result set.</p>
<p>Unlike the <code>join</code>, which was covered in my previous post <a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a>, the <code>union</code> does not combine the columns from each table into single rows. Rather it returns rows from the first table, then rows from the second table, then if supplied third, forth and so on.</p>
<p>The examples in this post will demonstrate the <code>union</code> and make its use clearer.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>Union Explained</h2>
<p>Let’s say we have two tables. The first table might be called <strong>SalesPeople</strong>.</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>District</th>
<th>Sales Quota</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fred</td>
<td>US</td>
<td>33,000</td>
</tr>
<tr>
<td>Gunther</td>
<td>Europe</td>
<td>42,000</td>
</tr>
</tbody>
</table>
<p>Now let’s say we also have a <strong>Sales</strong> table.</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>District</th>
<th>Company</th>
<th>Sale Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fred</td>
<td>US</td>
<td>Big Tech Inc</td>
<td>1,033</td>
</tr>
<tr>
<td>Fred</td>
<td>US</td>
<td>Fun Chemicals</td>
<td>927</td>
</tr>
<tr>
<td>Fred</td>
<td>US</td>
<td>Farm Stuff Corporation</td>
<td>2,237</td>
</tr>
<tr>
<td>Gunter</td>
<td>Europe</td>
<td>Satellites R Us</td>
<td>383</td>
</tr>
<tr>
<td>Gunther</td>
<td>Europe</td>
<td>Fox Brothers</td>
<td>5,235</td>
</tr>
</tbody>
</table>
<p>When you union these tables, the result would look like:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>District</th>
<th>Sales Quota</th>
<th>Company</th>
<th>Sale Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fred</td>
<td>US</td>
<td>33,000</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Gunther</td>
<td>Europe</td>
<td>42,000</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Fred</td>
<td>US</td>
<td></td>
<td>Big Tech Inc</td>
<td>1,033</td>
</tr>
<tr>
<td>Fred</td>
<td>US</td>
<td></td>
<td>Fun Chemicals</td>
<td>927</td>
</tr>
<tr>
<td>Fred</td>
<td>US</td>
<td></td>
<td>Farm Stuff Corporation</td>
<td>2,237</td>
</tr>
<tr>
<td>Gunter</td>
<td>Europe</td>
<td></td>
<td>Satellites R Us</td>
<td>383</td>
</tr>
<tr>
<td>Gunther</td>
<td>Europe</td>
<td></td>
<td>Fox Brothers</td>
<td>5,235</td>
</tr>
</tbody>
</table>
<p>The empty cells are due to columns that are only in one table or the other (or, they could be empty in the source table). <code>Sales Quota</code> is only in the first table, <strong>SalesPeople</strong>, so there is no data for it in the lower rows where <strong>Sales</strong> is displayed.</p>
<p>When the column names are identical, they are lined up, as happened with <code>Name</code> and <code>District</code>.</p>
<h2>Union Basics</h2>
<p>In this example, we will be unioning two tables, <strong>Update</strong> and <strong>UpdateSummary</strong>. You’ll find these under the <strong>Security and Audit</strong> branch in the Log Analytics samples.</p>
<p>If we were to run <code>UpdateSummary | count</code>, it would show we had 47 rows (at least at the time of this writing). Running <code>Update | count</code> shows there are 997 rows.</p>
<p>Let’s create our first <code>union</code> query. We start with the name of the first table, <code>UpdateSummary</code>, the comes the pipe character. Next comes the <code>union</code>, and the second table, <code>Update</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png"><img data-attachment-id="5237" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-01_union_basics/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png" data-orig-size="1210,732" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.01_union_basics" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=1024" loading="lazy" width="1024" height="619" src="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=1024" alt="" class="wp-image-5237" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png 1210w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>If you look on the lower right, you see the query returned 1044 rows, which is the sum of 47 + 997.</p>
<p>If you scroll through the output though, you have a problem. You can’t tell which rows came from which table. There is a way to fix that however. The <code>union</code> operator has a <em>modifier</em> which will add a column that indicates which table the data comes from, <code>withsource</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png"><img data-attachment-id="5240" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-02_withsource/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png" data-orig-size="1174,735" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.02_withsource" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=1024" loading="lazy" width="1024" height="641" src="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=1024" alt="" class="wp-image-5240" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png 1174w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>As you can see, there is a new column, <code>SourceTable</code>, which indicates which table the data came from. Here I picked <code>SourceTable</code> as the column name, but you can use anything you want, <code>FromTable</code>, <code>TheSource</code>, even <code>WhichTableDidThisComeFrom</code>.</p>
<h2>Union &#8211; The Preferred Way</h2>
<p>Since I first began using KQL, the language has evolved a bit. The method I just showed was created to make users coming from the world of SQL more comfortable with the language. Today, the preferred way of doing a <code>union</code> though is to place the <code>union</code> first.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png"><img data-attachment-id="5241" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-03_union_preferred/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png" data-orig-size="1176,825" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.03_union_preferred" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=1024" loading="lazy" width="1024" height="718" src="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=1024" alt="" class="wp-image-5241" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png 1176w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>As you can see, we begin with the <code>union</code> which is then followed by the <code>withsource</code>. Afterward we list the tables to be unioned separated by commas. Here we only have two, but you could list more as needed.</p>
<p>This is an opportune time to point out that by default the order of the rows is not set. If you were to keep scrolling down, you would see more rows from the <strong>Update</strong> table.</p>
<p>This can easily be fixed though by adding a <code>sort</code> after the <code>union</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png"><img data-attachment-id="5243" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-04_union_with_sort/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png" data-orig-size="1126,754" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.04_union_with_sort" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=1024" loading="lazy" width="1024" height="685" src="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=1024" alt="" class="wp-image-5243" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png 1126w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><h2>A More Complex Union</h2>
<p>Let’s look at a slightly more complex example. Here, we are going to union the results of two queries.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png"><img data-attachment-id="5245" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-05_more_complex_union/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png" data-orig-size="1152,945" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.05_more_complex_union" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=1024" loading="lazy" width="1024" height="840" src="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=1024" alt="" class="wp-image-5245" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png 1152w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Instead of table names, we supply two queries each wrapped in parenthesis. If you look in the <code>SourceTable</code> though, the names aren’t really very clear.</p>
<p>The first is <code>union_arg0</code>. This indicates the data came from the first query in the <code>union</code>. Then we have <code>union_arg1</code>, which is the second query in the <code>union</code>.</p>
<p>We can create better names for the sources, and make the query easier to read, by using our old friend the <code>let</code> operator.</p>
<h2>Using Let to Name Sources</h2>
<p>In this demo we’ll use <code>let</code> to create new datatables. Well, sort of. By using <code>= view()</code> in front we create a view on top of the query. This is more memory efficient than actually pulling all the data into memory.</p>
<p>After this we have our query. Note that instead of parenthesis we wrap the query in squiggly braces <code>{}</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png"><img data-attachment-id="5247" data-permalink="https://arcanecode.com/2023/06/19/fun-with-kql-union/045-06_using_let/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png" data-orig-size="1109,977" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="045.06_using_let" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=1024" loading="lazy" width="1024" height="902" src="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=1024" alt="" class="wp-image-5247" srcset="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png 1109w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>After declaring our <code>let</code> statements we fall into the <code>union</code>. All we have to do is list the names of the tables to be combined. In the results it uses the name of our view in the <code>SourceTable</code> column.</p>
<p>As you can see this structure makes the query much easier to read and modify in the future.</p>
<h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2023/06/12/fun-with-kql-join/">Fun With KQL &#8211; Join</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<h2>Conclusion</h2>
<p>It can be useful to combine two tables, or queries, in the output of our data. As you’ve seen in this post, the <code>union</code> operator will let you do just this.</p>
<p>The <code>union</code> has a few more options, formally called <em>modifiers</em>, you can use with it. We’ll look at those in the next post in this Kusto Query Language series.</p>
<p>There are three courses in this series so far:</p>
<ul>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-getting-started/table-of-contents">Kusto Query Language: Getting Started</a></p>
</li>
<li>
<p><a href="https://app.pluralsight.com/library/courses/kusto-query-language-operators/table-of-contents">Kusto Query Language: Beginning Operators</a>.</p>
</li>
<li>
<p><a href="https://www.pluralsight.com/courses/kusto-query-language-scalar-operators">Kusto Query Language: Scalar Operators</a></p>
</li>
</ul>
<p>I have two previous Kusto courses on Pluralsight as well. They are older courses but still valid.</p>
<ul>
<li>
<p><a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a></p>
</li>
<li>
<p><a href="https://pluralsight.pxf.io/2rQXjQ">Introduction to the Azure Data Migration Service</a></p>
</li>
</ul>
<p>These are a few of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a>. On the page is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/06/19/fun-with-kql-union/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/045.90_featured_image-1.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.90_featured_image-1.png" medium="image">
			<media:title type="html">045.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.01_union_basics.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.02_withsource.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.03_union_preferred.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.04_union_with_sort.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.05_more_complex_union.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/045.06_using_let.png?w=1024" medium="image" />
	</item>
		<item>
		<title>Fun With KQL &#8211; Join</title>
		<link>https://arcanecode.com/2023/06/12/fun-with-kql-join/</link>
					<comments>https://arcanecode.com/2023/06/12/fun-with-kql-join/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 12 Jun 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[KQL]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5224</guid>

					<description><![CDATA[Fun With KQL - Join]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>I’m still working on my <a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">ArcaneBooks</a> project, mostly documentation, so I thought I’d take a quick break and go back to a few posts on KQL (Kusto Query Language). In this post we’ll cover the <code>join</code> operator.</p>
<p>A <code>join</code> in KQL operates much as it does in SQL. It will join two datasets together into a single result.</p>
<p>The samples in this post will be run inside the LogAnalytics demo site found at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>. This demo site has been provided by Microsoft and can be used to learn the Kusto Query Language at no cost to you.</p>
<p>If you’ve not read my introductory post in this series, I’d advise you to do so now. It describes the user interface in detail. You’ll find it at <a href="https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/">https://arcanecode.com/2022/04/11/fun-with-kql-the-kusto-query-language/</a>.</p>
<p>Note that my output may not look exactly like yours when you run the sample queries for several reasons. First, Microsoft only keeps a few days of demo data, which are constantly updated, so the dates and sample data won’t match the screen shots.</p>
<p>Second, I’ll be using the column tool (discussed in the introductory post) to limit the output to just the columns needed to demonstrate the query. Finally, Microsoft may make changes to both the user interface and the data structures between the time I write this and when you read it.</p>
<h2>A Basic Join</h2>
<p>Here is a basic <code>join</code>. Since the image is a bit small I’ll reproduce the query first.</p>
<pre><code>Perf
| where TimeGenerated &gt;= ago(30d)
| take 1000
| join (Alert) on Computer
</code></pre>
<p>We start with the first table, <strong>Perf</strong>. We use a <code>where</code> to limit the data to the last thirty days, then use <code>take</code> to grab 1000 rows.</p>
<p>Then comes the <code>join</code>. After the join comes the table we want to join to, enclosed in parethesis. In this case we are joining to the <strong>Alert</strong> table.</p>
<p>After the table name we have the keyword <code>on</code>, then the column name to use for the <code>join</code>, here <code>Computer</code>.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png"><img data-attachment-id="5226" data-permalink="https://arcanecode.com/2023/06/12/fun-with-kql-join/044-01_basic_join/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png" data-orig-size="2370,395" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="044.01_basic_join" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=1024" loading="lazy" width="1024" height="170" src="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=1024" alt="" class="wp-image-5226" srcset="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=1024 1024w, https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=1020 1020w, https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=2040 2040w, https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=768 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Here you can see the query returned three rows. The first set of columns come from the <strong>Perf</strong> table. There is a second <code>TimeGenerated (UTC)</code> column, this came from the <strong>Alert</strong> table, as well as the rows to the right of it. Note there are more columns that are off to the right.</p>
<h2>A More Complex Join</h2>
<p>Here we have a more complex, and realistic join. Because the image is a bit small I’ll reproduce it below.</p>
<pre><code>Perf
| where TimeGenerated &gt;= ago(10m)
| where CounterName == &quot;% Free Space&quot;
| project PerfComputer = Computer
        , CounterName
        , CounterValue
        , PerfTime=TimeGenerated
| join ( InsightsMetrics
       | where TimeGenerated &gt;= ago(10m)
       | project IMComputer = Computer
               , Namespace
               , Name
               , Val
               , IMTime=TimeGenerated
       )
    on $left.PerfComputer == $right.IMComputer
</code></pre>
<p>We grab the <strong>Perf</strong> table, and use some <code>where</code> statements to limit the results. The query then falls into a <code>project</code> so we can limit the number of columns. Note we are renaming two of the columns, the <code>Computer</code> and <code>TimeGenerated</code>.</p>
<p>Next comes the <code>join</code>. In parenthesis we have a second query that access the <strong>InsightsMetrics</strong> table. We have a <code>where</code>, then a <code>project</code>. Within it we rename the <code>Computer</code> and <code>TimeGenerated</code> columns.</p>
<p>Next we have the <code>on</code>, followed by the columns to join on. Because we are joining on different column names we need to specify both names, and use <code>==</code> to show they match.</p>
<p>We also have to indicate which sides of the query the columns come from. To do so we prefix the column names with <code>$left</code> and <code>$right</code>. The left side is the first query coming into the <code>join</code>, the right side will be the second query.</p>
<p>Here is the query, with the results.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png"><img data-attachment-id="5228" data-permalink="https://arcanecode.com/2023/06/12/fun-with-kql-join/044-02_complex_join/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png" data-orig-size="1990,820" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="044.02_complex_join" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=300" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=1024" loading="lazy" width="1024" height="421" src="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=1024" alt="" class="wp-image-5228" srcset="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=1022 1022w, https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=150 150w, https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=300 300w, https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png 1990w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>Note that in a real world query we’d probably want to add the <code>TimeGenerated</code> to the query, and perhaps other columns, but I kept it to just one for simplicity. If we had more, we would just add the conditions after a comma.</p>
<h2>Join Types</h2>
<p>Similar to SQL, <code>join</code> supports multiple types. By default it uses an <em>innerunique</em>, but there are quite a few.</p>
<ul>
<li>fullouter</li>
<li>inner</li>
<li>innerunique</li>
<li>leftanti</li>
<li>leftantisemi</li>
<li>leftouter</li>
<li>leftsemi</li>
<li>rightanti</li>
<li>rightantisemi</li>
<li>rightouter</li>
<li>rightsemi</li>
</ul>
<p>To use one of these, after the <code>join</code> just specify the kind.</p>
<pre><code>join kind=fullouter
</code></pre>
<h2>Join Kind Reference</h2>
<p>Below is an explanation of the various types of joins.</p>
<ul>
<li>innerunique</li>
</ul>
<p>Only one row from the left is matched for each value of the on key. Output contains a match for each row on the right with a row on the left. NOTE: This is the default. If you are coming from a SQL background, you might expect the behavior to be <code>inner</code>, so be careful to look over your results. If you wanted a SQL style inner join you will need to
explicitly specify kind=inner when you execute the query!</p>
<ul>
<li>inner</li>
</ul>
<p>Output has one row for every combination of left and right.</p>
<ul>
<li>leftouter</li>
</ul>
<p>In addition to every match, there’s a row for every row on the left even if there’s no match on the right</p>
<ul>
<li>rightouter / fullouter</li>
</ul>
<p>Same as left outer, but either includes all rows from the right side, or all rows, regardless of matches.</p>
<ul>
<li>leftanti / rightanti</li>
</ul>
<p>The reverse of outer joins, only returns rows who do NOT have a match on the right (or left depending on which was used).</p>
<ul>
<li>leftsemi / rightsemi</li>
</ul>
<p>Returns rows who have a match on both sides, but only includes the columns from the left side (or right if rightsemi was used)</p>
<h2>A Complex Example</h2>
<p>Let’s wrap this up with a more complex example. This query will make use of the <code>let</code> operator which I covered in my <a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">pervious post</a> on KQL.</p>
<p>We start with two <code>let</code> statements to set the start and end time ranges. This will make it easy to update these when we need to use the query in the future. Note that we need to end each line in a semicolon since we have multiple KQL queries we are joining together to make our ultimate query.</p>
<p>The next <code>let</code> will create a new <em>datatable</em> and store the result of a query. We give it a name, <code>ProcData</code>, then assign it by creating a valid KQL query within parenthesis.</p>
<p>We repeat to create a second <em>datatable</em>, named <code>MemData</code>. Again note the use of semicolons.</p>
<p>Now we fall into the main query. By using the <em>datatable</em> names it makes the join query very easy to read. After the main query we fall into a <code>project</code> to limit the output columns, then a <code>sort</code> to get the columns in the order we want.</p>
<pre><code>let startTime = ago(1d);
let endTime = now();
let ProcData = (
    Perf
    | where TimeGenerated between (startTime .. endTime)
    | where CounterName == &quot;% Processor Time&quot;
    | where ObjectName == &quot;Processor&quot;
    | where InstanceName == &quot;_Total&quot;
    | summarize PctCpuTime = avg(CounterValue)
            by Computer, bin(TimeGenerated, 1h)
);
let MemData = (
    Perf
    | where TimeGenerated between (startTime .. endTime)
    | where CounterName == &quot;Available MBytes&quot;
    | summarize AvailableMB = avg(CounterValue)
            by Computer, bin(TimeGenerated, 1h)
);
ProcData
| join kind= inner (
   MemData
) on Computer, TimeGenerated
| project TimeGenerated, Computer, PctCpuTime, AvailableMB
| sort by TimeGenerated desc, Computer asc
</code></pre>
<p>Here is the result of the query.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png"><img data-attachment-id="5229" data-permalink="https://arcanecode.com/2023/06/12/fun-with-kql-join/044-03_complex/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png" data-orig-size="1010,1153" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="044.03_complex" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=263" data-large-file="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=897" loading="lazy" width="897" height="1024" src="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=897" alt="" class="wp-image-5229" srcset="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=897 897w, https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=131 131w, https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=263 263w, https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=768 768w, https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png 1010w" sizes="(max-width: 897px) 100vw, 897px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><h2>See Also</h2>
<p>The following operators, functions, and/or plugins were used or mentioned in this article’s demos. You can learn more about them in some of my previous posts, linked below.</p>
<p><a href="https://arcanecode.com/2022/07/11/fun-with-kql-ago/">Fun With KQL &#8211; Ago</a></p>
<p><a href="https://arcanecode.com/2023/02/20/fun-with-kql-let/">Fun With KQL &#8211; Let</a></p>
<p><a href="https://arcanecode.com/2022/07/04/fun-with-kql-now/">Fun With KQL &#8211; Now</a></p>
<p><a href="https://arcanecode.com/2022/05/30/fun-with-kql-project/">Fun With KQL &#8211; Project</a></p>
<p><a href="https://arcanecode.com/2022/07/18/fun-with-kql-sort/">Fun With KQL &#8211; Sort</a></p>
<p><a href="https://arcanecode.com/2022/05/16/fun-with-kql-summarize/">Fun With KQL &#8211; Summarize</a></p>
<p><a href="https://arcanecode.com/2022/05/02/fun-with-kql-take/">Fun With KQL &#8211; Take</a></p>
<p><a href="https://arcanecode.com/2022/04/25/fun-with-kql-where/">Fun With KQL &#8211; Where</a></p>
<h2>Conclusion</h2>
<p>In this post, we learned how to use a <code>join</code> operator to merge two tables together.</p>
<p>The demos in this series of blog posts were inspired by my Pluralsight courses <a href="https://pluralsight.pxf.io/MXDo5o">Kusto Query Language (KQL) from Scratch</a> and <a href="https://pluralsight.pxf.io/2rQXjQ">Introduction  the Azure Data Migration Service</a>, two of the many courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don’t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a> . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/06/12/fun-with-kql-join/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/044.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/044.99_featured_image.png" medium="image">
			<media:title type="html">044.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/044.01_basic_join.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/044.02_complex_join.png?w=1024" medium="image" />

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/044.03_complex.png?w=897" medium="image" />
	</item>
		<item>
		<title>Fun With PowerShell &#8211; Showing Book Data at the Library of Congress with Start-Process</title>
		<link>https://arcanecode.com/2023/06/05/fun-with-powershell-showing-book-data-at-the-library-of-congress-with-start-process/</link>
					<comments>https://arcanecode.com/2023/06/05/fun-with-powershell-showing-book-data-at-the-library-of-congress-with-start-process/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 05 Jun 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[PowerShell]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5219</guid>

					<description><![CDATA[Fun With PowerShell - Showing Book Data at the Library of Congress with Start-Process]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><p>In my previous post, <a href="https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/">Fun With PowerShell – Opening Websites with Start-Process</a>, I showed how to use the <code>Start-Process</code> cmdlet to open a website. This is part of my ongong <a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">ArcaneBooks Project</a>, in which I created a new function to display the webpage for a book at the OpenLibrary website by using the ISBN.</p>
<p>I wanted to create a similar function to work with the Library of Congress website, and so let me present the <code>Show-LCCNBookData</code> function.</p>
<h2>Show-LCCNBookData</h2>
<p>The function I created, <code>Show-LCCNBookData</code> is almost identical to the <code>Show-ISBNBookData</code> function I covered in the <a href="https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/">previous post</a>, so I won&#8217;t go into a lot of depth in this post.</p>
<p>As with the ISBN version, I made this an advanced function so users could pipe data into it.</p>
<pre><code class="language-powershell">function Show-LCCNBookData
{
  [CmdletBinding(HelpURI=&quot;https://github.com/arcanecode/ArcaneBooks/blob/1ebe781951f1a7fdf19bb6731487a74fa12ad08b/ArcaneBooks/Help/Get-ISBNBookData.md&quot;)]
  [alias(&quot;slccn&quot;)]
  param (
         [Parameter( Mandatory = $true,
                     ValueFromPipeline = $true,
                     HelpMessage = 'Please enter the LCCN (Library of Congress Control Number).'
                     )]
         [string] $LCCN
        )
</code></pre>
<p>Note I still need to update the help URL to the correct one, but the rest of the function opening is complete, with the sole parameter being the <code>$LCCN</code>.</p>
<p>Now we fall into the process block.</p>
<pre><code class="language-powershell">  process
  {
    foreach($number in $LCCN)
    {
      Write-Verbose &quot;Beginning Show-LCCNBookData for $ISBN at $(Get-Date).ToString('yyyy-MM-dd hh:mm:ss tt')&quot;

      $lccnCleaned = $LCCN.Replace('-', '').Replace(' ', '')
      $lccnPrefix = $lccnCleaned.Substring(0,2)
      $lccnPadded = $lccnCleaned.Substring(2).PadLeft(6, '0')

      # Now combine the reformatted LCCN and save it as a property
      $lccnFormatted =&quot;$($lccnPrefix)$($lccnPadded)&quot;

      $baseURL = &quot;https://lccn.loc.gov/&quot;

      $url = &quot;$($baseURL)$($lccnFormatted)&quot;

      Write-Verbose 'Opening the Book on Library of Congress Number'

      Start-Process $url

      Write-Verbose &quot;Finished Getting Data for $($LCCN)&quot;
    }

    Write-Verbose &quot;Done opening the web pages at Library of Congress&quot;

  }
</code></pre>
<p>When we fall into the process loop we first need to clean up the LCCN that was passed in. As was documented in my <a href="https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/">LCCN overview post</a> the LCCN is the two digit year at front, then six digits. If the number of digits after the first two isn&#8217;t six in length we have to zero pad it to become six, which will make the entire LCCN string eight digits.</p>
<p>We then append the formatted LCCN to the base URL for the LOC website. Then we use the <code>Start-Process</code> cmdlet to open the webpage.</p>
<h2>Calling Show-LCCNBookData</h2>
<p>Calling the function is pretty easy, you can either pass in a Library of Congress Control Number as a parameter or via the pipeline. All these examples should open the Library of Congress website, in your default browser, with the book associated with the LCCN you passed in.</p>
<pre><code class="language-powershell"># Pass in a single LCCN as a parameter
$LCCN = '54009698'
Show-LCCNBookData -LCCN $LCCN -Verbose

# Alias
$LCCN = '54009698'
slccn -LCCN $LCCN -Verbose

# Pipe in a single ISBN
$LCCN = '54-9698'
$LCCN | Show-LCCNBookData

.EXAMPLE
# Pipe in an array of LCCNs
$LCCNs = @( '54-9698'
          , '40-33904'
          , '41-3345'
          , '64-20875'
          , '74-75450'
          , '76-190590'
          , '71-120473'
          )
$LCCNs | Show-LCCNBookData -Verbose
</code></pre>
<p>In the final example we can actually pipe in an array of LCCNs, it should open up a page for each one.</p>
<p>Note the Library of Congress isn&#8217;t perfect, sometimes it will bring up a page with multiple items for the number passed in as it may have multiple entries. It&#8217;s still faster though than having to do manual searches on the LoC website.</p>
<h2>See Also</h2>
<p>You may find more helpful information at the links below.</p>
<p><a href="https://github.com/arcanecode/ArcaneBooks/tree/main/ArcaneBooks">ArcaneBooks Project at GitHub</a></p>
<p><a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">ArcaneBooks Project Introduction</a></p>
<p><a href="https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/">ArcaneBooks &#8211; Library of Congress Control Number (LCCN) &#8211; An Overview</a></p>
<p><a href="https://arcanecode.com/2021/09/06/fun-with-powershell-advanced-functions/">Fun With PowerShell &#8211; Advanced Functions</a></p>
<p><a href="https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/">Fun With PowerShell – Opening Websites with Start-Process</a></p>
<p><a href="https://arcanecode.com/2021/07/12/fun-with-powershell-strings/">Fun With PowerShell &#8211; Strings</a></p>
<p><a href="https://arcanecode.com/2021/09/27/fun-with-powershell-write-verbose/">Fun With PowerShell &#8211; Write-Verbose</a></p>
<h2>Conclusion</h2>
<p>This post and the previous one demonstrates how easy it can be to create helper functions for your modules. My two show functions are designed to let users quickly bring up the webpage for the books they are working with.</p>
<p>If you like PowerShell, you might enjoy some of my Pluralsight courses. <a href="https://pluralsight.pxf.io/jWzbre">PowerShell 7 Quick Start for Developers on Linux, macOS and Windows</a> is one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don&#8217;t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a> . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/06/05/fun-with-powershell-showing-book-data-at-the-library-of-congress-with-start-process/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/06/007.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/06/007.99_featured_image.png" medium="image">
			<media:title type="html">007.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>Fun With PowerShell &#8211; Opening Websites with Start-Process</title>
		<link>https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/</link>
					<comments>https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 22 May 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[ArcaneBooks]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5215</guid>

					<description><![CDATA[Fun With PowerShell - Opening Websites with Start-Process]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>As part of my <a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">ArcaneBooks Project</a> I described how to use the <a href="https://arcanecode.com/2023/03/20/arcanebooks-isbn-overview-powershell-and-the-simple-openlibrary-isbn-api/">OpenLibrary Simple API</a> to get book data.</p>
<p>In that post I also showed a way to bring up the webpage for an ISBN. I had a thought, why not build a function to add to the module to do that? This way a user would have an easy way to compare the output of the web API call to what the site holds.</p>
<p>In this post I&#8217;ll describe how to use the <code>Start-Process</code> cmdlet to open a target webpage.</p>
<h2>Show-ISBNBookData</h2>
<p>I created a new <em>advanced function</em> and named it <code>Show-ISBNBookData</code>. Here is the opening of the function.</p>
<pre><code class="language-powershell">function Show-ISBNBookData
{
  [CmdletBinding(HelpURI=&quot;https://github.com/arcanecode/ArcaneBooks/blob/1ebe781951f1a7fdf19bb6731487a74fa12ad08b/ArcaneBooks/Help/Get-ISBNBookData.md&quot;)]
  [alias(&quot;sisbn&quot;)]
  param (
         [Parameter( Mandatory = $true,
                     ValueFromPipeline = $true,
                     HelpMessage = 'Please enter the ISBN.'
                     )]
         [string] $ISBN
        )
</code></pre>
<p>If you want to learn more about advanced functions, see my post <a href="https://arcanecode.com/2021/09/06/fun-with-powershell-advanced-functions/">Fun With PowerShell &#8211; Advanced Functions</a>. Briefly, the <code>CmdletBinding</code> attribute will turn this into an advanced function. Advanced functions allow you to input one or more parameters via the pipeline.</p>
<p>It has one parameter, the ISBN number you want to find. This can be passed in normally, or via the pipeline.</p>
<h2>The Process Loop</h2>
<p>In order to process multiple items from the pipeline you must enclose the heart of the function inside a <code>process { }</code> block. The <code>process</code> block is called once for each item passed in via the pipeline.</p>
<p>I then use the <code>Replace</code> method of the string object to remove any dashes or spaces from the ISBN that was passed in. This is then combined with the base OpenLibrary URL to create a new string, <code>$url</code>.</p>
<pre><code class="language-powershell">  process
  {
    foreach($number in $ISBN)
    {
      Write-Verbose &quot;Beginning Show-ISBNBookData for $ISBN at $(Get-Date).ToString('yyyy-MM-dd hh:mm:ss tt')&quot;

      $isbnFormatted = $ISBN.Replace('-', '').Replace(' ', '')
      $baseURL = &quot;https://openlibrary.org/isbn/&quot;

      $url = &quot;$($baseURL)$($isbnFormatted)&quot;

      Write-Verbose 'Opening the Book on OpenLibrary'

      Start-Process $url

      Write-Verbose &quot;Finished Getting Data for $($ISBN)&quot;
    }
</code></pre>
<p>The magic comes in the <code>Start-Process</code> cmdlet. This cmdlet analyzes the string that was passed in. It then looks for the default application for it, and attempts to open the associated application for the passed in string.</p>
<p>As an example, if you were to pass in the name of a Microsoft Word document, <code>Start-Process</code> would open Microsoft Word with the document name you passed in.</p>
<p>In this case, passing in a URL will attempt to open up your default web browser to the page you passed in.</p>
<p>If you called <code>Show-ISBNBookData</code> using the pipeline, the function will attempt to open up a new tab in your browser for each URL passed in via the pipeline.</p>
<p>Note I also used several <code>Write-Verbose</code> commands, you can learn more about it at <a href="https://arcanecode.com/2021/09/27/fun-with-powershell-write-verbose/">Fun With PowerShell &#8211; Write-Verbose</a>.</p>
<h1>An Example</h1>
<p>Calling the function is very simple.</p>
<pre><code class="language-powershell">$ISBN = '0-87259-481-5'
Show-ISBNBookData -ISBN $ISBN -Verbose
</code></pre>
<p>This should open up the following webpage in your default browser.</p>
<p><a href="https://openlibrary.org/books/OL894295M/Your_HF_digital_companion">https://openlibrary.org/books/OL894295M/Your_HF_digital_companion</a></p>
<p>This is a reference to the book <em>You HF Digital Companion</em>.</p>
<h2>See Also</h2>
<p>You may find more helpful information at the links below.</p>
<p><a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">ArcaneBooks Project</a></p>
<p><a href="https://arcanecode.com/2021/09/06/fun-with-powershell-advanced-functions/">Fun With PowerShell &#8211; Advanced Functions</a></p>
<p><a href="https://arcanecode.com/2021/07/12/fun-with-powershell-strings/">Fun With PowerShell &#8211; Strings</a></p>
<p><a href="https://arcanecode.com/2021/09/27/fun-with-powershell-write-verbose/">Fun With PowerShell &#8211; Write-Verbose</a></p>
<p><a href="https://arcanecode.com/2023/03/20/arcanebooks-isbn-overview-powershell-and-the-simple-openlibrary-isbn-api/">OpenLibrary Simple API</a></p>
<h2>Conclusion</h2>
<p>As you can see, <code>Start-Process</code> is extremely easy to use. Just pass in a URL or the name of a file, and PowerShell will attempt to open the item using the default application assigned in the operating system. In the ArcaneBooks project I&#8217;m using it to open a website, but you can use it for a variety of purposes.</p>
<p>If you like PowerShell, you might enjoy some of my Pluralsight courses. <a href="https://pluralsight.pxf.io/jWzbre">PowerShell 7 Quick Start for Developers on Linux, macOS and Windows</a> is one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my <a href="https://arcanecode.com/info/">About Me</a> page.</p>
<p>If you don&#8217;t have a Pluralsight subscription, just go to <a href="https://pluralsight.pxf.io/kjz6jn">my list of courses on Pluralsight</a> . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/05/22/fun-with-powershell-opening-websites-with-start-process/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.22.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.22.99_featured_image.png" medium="image">
			<media:title type="html">23.05.22.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>Fun With PowerShell &#8211; Elapsed Timers</title>
		<link>https://arcanecode.com/2023/05/15/fun-with-powershell-elapsed-timers/</link>
					<comments>https://arcanecode.com/2023/05/15/fun-with-powershell-elapsed-timers/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 15 May 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Timers]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5205</guid>

					<description><![CDATA[Fun With PowerShell - Elapsed Timers]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>I&#8217;m still working on my documentation for my ArcaneBooks project, but wanted to have something for you to read this week, so decided to show you how to create an elapsed timer in PowerShell.</p>
<p>It can be helpful to determine how long a process runs in PowerShell. You can use it to determine what parts of code may need to be optimized, or gather metrics around your functions.</p>
<h2>Creating and Using a Timer</h2>
<p>The .NET framework has a class named <code>System.Diagnostics.Stopwatch</code>. It has a static function named <code>StartNew</code> that you can call which will create a new instance from the Stopwatch class.</p>
<pre><code class="language-powershell">$processTimer = [System.Diagnostics.Stopwatch]::StartNew()
</code></pre>
<p>So now you go off and do your code, routine, whatever it is you want to measure. When you are done, you call the <code>Stop</code> method of your timer.</p>
<pre><code class="language-powershell">$processTimer.Stop()
</code></pre>
<p>Now what? How do we get the time from this? Well to do that you can grab the <code>Elapsed</code> property of your timer.</p>
<pre><code class="language-powershell">$processTimer.Elapsed
</code></pre>
<p>This produces the following output:</p>
<pre><code>Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 20
Milliseconds      : 698
Ticks             : 206988710
TotalDays         : 0.000239570266203704
TotalHours        : 0.00574968638888889
TotalMinutes      : 0.344981183333333
TotalSeconds      : 20.698871
TotalMilliseconds : 20698.871
</code></pre>
<p>It&#8217;d be nice to have it in something more readable. So in this example I&#8217;ll capture the elapsed time into a variable, then use PowerShell&#8217;s string formatting technique to produce something easily understandable.</p>
<pre><code class="language-powershell">$ts = $processTimer.Elapsed
$elapsedTime = &quot;{0:00}:{1:00}:{2:00}.{3:00}&quot; -f $ts.Hours, $ts.Minutes, $ts.Seconds, ($ts.Milliseconds / 10)
Write-Host &quot;All done - Elapsed Time $elapsedTime `r`n&quot;
</code></pre>
<p>This produces:</p>
<pre><code>All done - Elapsed Time 00:00:20.70
</code></pre>
<p>Alternatively you could use a string that expanded the time fields a bit. In this example I&#8217;ll also include the number of days. Since the timer shows days, milliseconds probably aren&#8217;t that important so I&#8217;ll omit them. If you needed it though it&#8217;d be easy enough to add.</p>
<pre><code class="language-powershell">$elapsedTime = &quot;The process took $($ts.Days) days, $($ts.Hours) hours, $($ts.Minutes) minutes, and $($ts.Seconds) seconds.&quot;
Write-Host &quot;All done - Elapsed Time $elapsedTime `r`n&quot;
</code></pre>
<p>This will produce:</p>
<pre><code>All done - Elapsed Time The process took 0 days, 0 hours, 0 minutes, and 20 seconds.
</code></pre>
<h2>Multiple Timers</h2>
<p>You may have a situation where you need multiple timers. For example, one for a full function, and a second to log the time of a loop in the function. Just create multiple process timer variables, for example <code>$processTimer1</code> and <code>$processTimer2</code>.</p>
<p>There&#8217;s nothing special about the variable name either, you could use names like <code>$myFunctionsTimer</code>, <code>$mainLoopTimer</code>, and <code>$loggingTimer</code>.</p>
<h2>See Also</h2>
<p>If you want to learn more about the string formatting technique used in this post, see my <a href="https://arcanecode.com/2021/07/19/fun-with-powershell-string-formatting/">Fun With PowerShell &#8211; String Formatting</a> post.</p>
<h2>Conclusion</h2>
<p>Optimizing your PowerShell code is made much easier when you can measure the runtime of sections of code. It lets you know what sections are running slow, and when you make changes did you actually improve things or make it worse.</p>
<p>As you saw in this post, creating one or more timers is very simple. You can insert them into your code temporarily, or leave them there as part of your metrics logging strategy.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/05/15/fun-with-powershell-elapsed-timers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.15.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.15.99_featured_image.png" medium="image">
			<media:title type="html">23.05.15.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>Fun With PowerShell &#8211; Authoring About Help</title>
		<link>https://arcanecode.com/2023/05/08/fun-with-powershell-authoring-about-help/</link>
					<comments>https://arcanecode.com/2023/05/08/fun-with-powershell-authoring-about-help/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 08 May 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Help]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5196</guid>

					<description><![CDATA[Fun With PowerShell - Authoring About Help]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In my previous post, <a href="https://arcanecode.com/2023/05/02/fun-with-powershell-authoring-help/">Fun With PowerShell &#8211; Authoring Help</a>, I covered how to author comment based help for your functions.</p>
<p>In addition to help for your functions, it&#8217;s also possible to write <code>about_</code> help. PowerShell itself contains many <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about?view=powershell-7.4">about topics</a> for PowerShell itself.</p>
<p>These <em>about</em> topics are designed to provide further information for your users, information that may not fit into the confines of a functions help. These texts can be as long as you need.</p>
<h2>The Contents of an About Topic File</h2>
<p>An about file can contain literally any text you want. Whatever is in there will be returned when you use <code>Get-Help</code> to retrieve its contents.</p>
<p>However, there is a suggested guideline for the formatting of an about file.</p>
<pre><code>
about_TopicName

SHORT DESCRIPTION
   Brief description, one to two sentences.

LONG DESCRIPTION
   Much longer text, could be several paragraphs.

BACKGROUND
   This isn't a standard option but one I like to include to provide context
   to the reader about why the module was created. What problem was it meant
   to solve.

NOTE
   Miscellaneous notes about the module, such as the copyright

TROUBLESHOOTING NOTE
   Warning notes of issues you may find, perhaps a to-do list

SEE ALSO
  links to relevant things, such as the project github site
  or the authors website

ABOUT TOPICS
   List other about topics

KEYWORDS
   Keywords here

</code></pre>
<p>I usually leave one blank line at the top, to separate the text from the <code>Get-Help</code> command, but this is just my personal preference.</p>
<p>It is then customary to put the name of the about topic, as shown.</p>
<p>The next two are self explanatory, a short and long description for the topic. While not required by PowerShell code, it is highly suggested as PowerShell can use the text in the SHORT DESCRIPTION with <code>Get-Help</code>, but we&#8217;ll talk about that later in the post.</p>
<p>Next up is a section I call BACKGROUND. I usually include this in the about topic for a module, to explain what problem this module was meant to solve, how it came to be, and so on. If I have any other about topics I generally omit this unless it is appropriate to the topic. To be clear, this is something I do, not a standard.</p>
<p>The note section is just what it says, it is for any notes that haven&#8217;t been covered in the other sections. I generally use this to place the copyright notice, the author name and contact info, and similar data.</p>
<p>The TROUBLESHOOTING NOTE area is used to let the user know of any issues they may encounter. One common one I find is that about topics don&#8217;t display correctly in some (but not all) version of Linux.</p>
<p>You might also include information about functions that will have further development done, or perhaps a note that documentation is still being worked on. This type of information can be especially useful for a module that is still in the alpha or beta stages, where further work will still be done.</p>
<p>Under the SEE ALSO section you can provide links to a projects github site, the PSGallery page, the author website, or other relevant links.</p>
<p>In the about topic page for the module, I like to provide a full list of all the about topics provided in the module, so the reader will know what else is available. Again, I usually only include this in the about page for the module itself and omit from other about topics unless it is relevant. We&#8217;ll touch on the about topic for a module momentarily.</p>
<p>The final section allows you to place keywords for a module or about topic. These can be useful when searching for a module that covers the included keywords.</p>
<h2>Placement of About Topics</h2>
<p>Under the modules main folder, you should create a folder with the standard language abbreviation for your target language. For example, for US English the folder would be named <code>en-us</code>. If I were to also write documentation for the French language (which would be a real feat as I don&#8217;t know any French) I would create a folder named <code>fr-FR</code>.</p>
<p>Here is the layout for my ArcaneBooks module.</p>
</div>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png"><img data-attachment-id="5197" data-permalink="https://arcanecode.com/2023/05/08/fun-with-powershell-authoring-about-help/23-05-08-02_file_layout/" data-orig-file="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png" data-orig-size="317,370" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="23.05.08.02_file_layout" data-image-description="" data-image-caption="" data-medium-file="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=257" data-large-file="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=317" loading="lazy" width="317" height="370" src="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=317" alt="" class="wp-image-5197" srcset="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png 317w, https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=129 129w, https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=257 257w" sizes="(max-width: 317px) 100vw, 317px" /></a></figure></div>


<div class="wp-block-jetpack-markdown"><p>At the top is the folder <code>ArcaneBooks</code>, which is the root folder for the module. Under it is a folder, <code>en-us</code> where English language help files are placed. Here I only have <code>about</code> topics, but if I were using XML based help those files would also be placed here.</p>
<p>Let&#8217;s talk now about how to name your about files.</p>
<h2>Naming Your About Topic Files</h2>
<p>The names of all about files should begin with <code>about_</code>. They should end with <code>.help.txt</code>. To create an about topic for the module itself (which you should at the very least include one about for the module) use the module name as I did here, with <code>about_ArcaneBooks.help.txt</code>.</p>
<p>If you then call help for the module, <code>Get-Help ArcaneBooks</code>, it will display the contents of the about file with the module name, <code>about_ArcaneBooks.help.txt</code>.</p>
<p>I&#8217;ve included two other about topics for the ArcaneBooks module. The first, <code>about_ABFunctions</code>, displays a list of functions in the module, with the synopsis of its purpose. I&#8217;ve found this to be of aid to the end user to help them see what functions are in the module. They can see this information using <code>Get-Help about_ABFunctions</code>.</p>
<p>The final about topic, <code>about_ABUsage</code>, has examples of how to use the module. I usually develop a PS1 script to test out a module as it is being developed. I find this makes for great examples of how to use the module overall, and include a copy inside an about topic so an end user can use it as well. As with the functions, a user can see this using <code>Get-Help about_ABUsage</code>.</p>
<h2>Getting Help</h2>
<p>This is an example of calling help for the module.</p>
<pre><code>PS D:\OneDrive\PSCore\ArcaneBooks\ArcaneBooks&gt; Get-Help about_ArcaneBooks

about_ArcaneBooks

SHORT DESCRIPTION
   Retrieves book metadata based on the ISBN or LCCN.

LONG DESCRIPTION
   This module is designed to retrieve metadata for books based on either the
   ISBN or the LCCN (Library of Congress Catalog Number). It will return data
   such as the book title, author, and more.

   To see a list of functions, please use &quot;Get-Help about_ABFunctions&quot;.

   In addition each cmdlet has help, you can use the Get-Help feature of
   PowerShell to learn more about each one.

BACKGROUND
   The author (Robert Cain aka ArcaneCode) is a member of the Alabama
   Historical Radio Society(https://alhrs.org/). They are beginning a project
   to create metadata for their library (title, author, publisher, etc.) and
   store it in cloud based software.

   Naturally we want to automate as much of this as possible, since the
   collection is rather extensive. Some of our books are so old they have
   neither an ISBN or a Library of Congress Catalog Number (LCCN for short).
   Those will require manual intervention to key in the data.

   Fortunately many of the books have the LCCN, the newer books have an ISBN,
   and a very few have both.

   The goal with this project was to allow a user to create a simple text file
   using notepad, Excel, or something similar. The user can enter an LCCN into
   one file or the ISBN in another.

   That data file will be piped through the appropriate cmdlets found in this
   module and produce a list of metadata for each book including things such
   as the book title, author, publication date, and the like.

   This output can then be piped into standard PowerShell cmdlets to output
   the data to formats such as CSV, XML, JSON, and the like.

   The sources used in this module are the Library of Congress or the
   Open Library site, which is part of the Internet Archive. Both provide
   web APIs that can use to retrieve data.

   For more information, please see the online documentation at the projects
   GitHub site, https://github.com/arcanecode/ArcaneBooks .

NOTE
   Author: Robert C Cain | @ArcaneCode | arcane@arcanetc.com

   This code is Copyright (c) 2023 Robert C Cain All rights reserved

   The code herein is for demonstration purposes. No warranty or guarantee
   is implied or expressly granted.

   This module may not be reproduced in whole or in part without the express
   written consent of the author.

TROUBLESHOOTING NOTE
   Help for the about_* topics doesn't work correctly on all versions of
   Linux due to issues with PowerShell's Help system.

SEE ALSO
     https://github.com/arcanecode/ArcaneBooks
     <blockquote class="wp-embedded-content" data-secret="pdDykV7AtC"><a href="https://arcanecode.com/info/">About Arcane Code</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  title="&#8220;About Arcane Code&#8221; &#8212; Arcane Code" src="https://arcanecode.com/info/embed/#?secret=z9068HXoKR#?secret=pdDykV7AtC" data-secret="pdDykV7AtC" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>

ABOUT TOPICS
   about_ArcaneBooks
   about_ABFunctions
   about_ABUsage

KEYWORDS
     ArcaneBooks, ISBN, LCCN

</code></pre>
<h2>Getting A List of About Topics</h2>
<p>Using <code>Get-Help</code>, you can get a list of all the about topics for modules loaded into memory.</p>
<pre><code class="language-powershell">Get-Help about_*
</code></pre>
<p>Here is a partial output of the result of the command.</p>
<pre><code>Name                              Category  Module                    Synopsis
----                              --------  ------                    --------
about_ABFunctions                 HelpFile                            This is a listing of the functions available in the ArcaneBooks module.
about_ABUsage                     HelpFile                            Provides examples on how to call the functions with example data.
about_ArcaneBooks                 HelpFile                            Retrieves book metadata based on the ISBN or LCCN.
about_Aliases                     HelpFile
about_Alias_Provider              HelpFile
</code></pre>
<p>In order to get the synopsis to show up in the output, you must include a <code>SHORT DESCRIPTION</code>. Then the synopsis must appear on the line immediately after it. There cannot be a blank line between, if there is <code>Get-Help</code> won&#8217;t display the synopsis.</p>
<h2>Conclusion</h2>
<p>As you can see, creating about topic help is very simple. Just create a folder to store it, then create the text file (or files) you need. Name them appropriately, and PowerShell then takes care of the rest!</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/05/08/fun-with-powershell-authoring-about-help/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.99_featured_image.png" medium="image">
			<media:title type="html">23.05.08.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>

		<media:content url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.08.02_file_layout.png?w=317" medium="image" />
	</item>
		<item>
		<title>Fun With PowerShell &#8211; Authoring Help</title>
		<link>https://arcanecode.com/2023/05/02/fun-with-powershell-authoring-help/</link>
					<comments>https://arcanecode.com/2023/05/02/fun-with-powershell-authoring-help/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Tue, 02 May 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[ArcaneBooks]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5187</guid>

					<description><![CDATA[Fun With PowerShell - Authoring Help]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>Having good help is vital to the construction of a module. It explains not only how to use a function, but the purpose of the module and even more.</p>
<p>Naturally I&#8217;ve included good help text in the ArcaneBooks module, but as I was going over the construction of the ArcaneBooks module I realized I&#8217;d not written about how to write help in PowerShell. So in this post and the next I&#8217;ll address this very topic.</p>
<h2>Two Types of Help</h2>
<p>There are two ways of creating help for functions in PowerShell modules. The newer method is to create XML files with the help text. I&#8217;ll be honest, I&#8217;m not a big fan of this method.</p>
<p>The XML is more difficult to author and read in plain text format as the help is surrounded by XML tags. To be able to effectively author it a third party tool is needed.</p>
<p>There is one advantage to the XML format, if you wish to internationalize your module you can write individual XML help files for each language you need. These can all be bundled with your module. In my case I&#8217;m only going to use English, so this isn&#8217;t of benefit to my ArcaneBooks module.</p>
<p>I&#8217;ll admit that I may be a bit old fashioned, but I still prefer the original <em>comment based help</em> when authoring help. It keeps the help text with the function, and is easier to read when looking at the raw code.</p>
<h2>Comment Blocks</h2>
<p>As its name implies, <em>comment based help</em> is created by placing specially crafted <em>comment blocks</em> beside the function declarations of the functions in your module.</p>
<p>As you may know, a normal comment in PowerShell begins with a <code>#</code>, commonly called a pound sign or hash tag. Some examples:</p>
<pre><code class="language-powershell"># This is a comment

$x = 1  # Set X equal to 1
</code></pre>
<p>A comment block allows you to create comments that are multiple lines. They begin with a <code>&lt;#</code> and end with <code>#&gt;</code>. An example would be:</p>
<pre><code class="language-powershell">&lt;#
Here is a comment block

More text here
#&gt;
</code></pre>
<p>You can add text after and before the <code>#</code> characters. I often use these to creeate dividers in my code.</p>
<pre><code class="language-powershell">&lt;#-----------------------------------------------
  Do some interesting stuff in this section
-----------------------------------------------#&gt;
</code></pre>
<p>I&#8217;ll dive a bit deeper into the structure of the comment help block, but first lets talk about placement.</p>
<h2>Placement of Comment Help</h2>
<p>To associate a help block with a function, it needs to be positioned right before or right after the function declaration.</p>
<pre><code class="language-powershell">&lt;#
Comment based help here
#&gt;
function DoSomething()
</code></pre>
<pre><code class="language-powershell">function DoSomething()
&lt;#
Comment based help here
#&gt;

$x = 1
</code></pre>
<p>Either of these are valid, but I much prefer the first version. It keeps the function declaration close to its code.</p>
<h2>Contents of Comment Based Help</h2>
<p>There is a defined template of what needs to be in comment based help.</p>
<pre><code class="language-powershell">&lt;#
.SYNOPSIS
A short one liner that describes the function

.DESCRIPTION
Detailed description of the function

.PARAMETER ParamName
Information about the parameter.

Add additional .PARAMETER tags for more parameters

.INPUTS
What inputs are allowed, useful for when a function allows input to be piped in.

.OUTPUTS
Explanation of what the function outputs.

Can also include sample data

.EXAMPLE
Code example

.EXAMPLE
Additional examples, just add more .EXAMPLE tags as needed

.NOTES
Notes here like author name

.LINK
Link to online help

.LINK
Additional link(s)
#&gt;
</code></pre>
<p>As you can see, it uses a series of tags to describe what is in the section. Each tag is preceded by a period.</p>
<p>The <code>SYNOPSIS</code> and <code>DESCRIPTION</code> are both required. In the synopsis you place a short description of the function. One, no more than two sentences go here.</p>
<p>In the description you can place an expanded explanation of the function. You can go into detail of its purpose. It doesn&#8217;t need to be a novel, but two to three paragraphs are not uncommon.</p>
<p>Next comes the parameters. Each parameter should be listed individually, getting a <code>PARAMETER</code> tag followed by the name of the parameter. In the accompanying text you can include details to the nature of the parameter, whether it is required, and if appropriate the data type.</p>
<p>Again, you should include one parameter tag for each of your functions parameters.</p>
<p>In the <code>INPUTS</code> area you can give an overall description of the data that will be input to the function. It is also a good place to describe data that can be input to the function through the pipeline.</p>
<p>The <code>OUTPUTS</code> is the place to describe what data is returned from the function. This may be a single value, or an object with multiple values. When returning an object I like to list each property along with a sample value for each.</p>
<p>You should include at least one <code>EXAMPLE</code> section in your help. Include a small code sample of calling your function.</p>
<p>It&#8217;s a good idea though to include multiple example sections. For instance, if your function allows for input through the pipeline, have one example for passing data in normally, than a second for using the pipeline. Include as many as you need to give the reader a good set of examples on how to use your function.</p>
<p><code>NOTES</code> is for just what it says, an area to include any additional notes about the function. In here I often include information such as the author name, copyright notices, and any other information I&#8217;d like to have included.</p>
<p>Finally is the <code>LINK</code> section. If you have online help, the first link tag should point to the online help web address that will be used with the <code>-Online</code> switch of the <code>Get-Help</code> cmdlet. You can include as many links as needed, I usually include at least one more pointing to the project website, such as a github site, or back to my own blog.</p>
<h2>A Real World Example</h2>
<p>Here is a real world example from the ArcaneBooks project I&#8217;ve been developing. This is the help for the <code>Get-ISBNBookData</code> function.</p>
<pre><code class="language-powershell">&lt;#
.SYNOPSIS
Gets book data from OpenLibrary.org based on the ISBN

.DESCRIPTION
Uses the more advanced API at OpenLibrary to retrieved detailed information
based on the 10 or 13 character ISBN passed in.

.PARAMETER ISBN
A 10 or 13 digit ISBN number. The passed in value can have spaces or dashes,
it will remove them before processing the request to get the book data.

.INPUTS
Via the pipeline this cmdlet can accept an array of ISBN values.

.OUTPUTS
The cmdlet returns one or more objects of type Class ISBNBook with the
following properties. Note that not all properties may be present, it
depends on what data the publisher provided.

ISBN | The ISBN number that was passed in, complete with an formatting
ISBN10 | ISBN as 10 digits
ISBN13 | ISBN in 13 digit format
Title | The title of the book
LCCN | Library of Congress Catalog Number
Author | The author(s) of the book
ByStatement | The written by statement provided by the publisher
NumberOfPages | Number of pages in the book
Publishers | The Publisher(s) of this book
PublishDate | The publication date for this edition of the book
PublisherLocation | The location of the publisher
Subject | Generic subject(s) for the work
LibraryOfCongressClassification | Specialized classification used by Library of Congress
DeweyDecimalClass | Dewey Decimal number
Notes | Any additional information provided by the publisher
CoverUrlSmall | URL link to an image of the book cover, in a small size
CoverUrlMedium | URL link to an image of the book cover, in a medium size
CoverUrlLarge | URL link to an image of the book cover, in a large size

.EXAMPLE
# Pass in a single ISBN as a parameter
$ISBN = '0-87259-481-5'
$bookData = Get-ISBNBookData -ISBN $ISBN
$bookData

.EXAMPLE
# Pipe in a single ISBN
$ISBN = '0-87259-481-5'
$bookData = $ISBN | Get-ISBNBookData
$bookData

.EXAMPLE
# Pipe in an array of ISBNs
$ISBNs = @( '0-87259-481-5'
          , '0-8306-7801-8'
          , '0-8306-6801-2'
          , '0-672-21874-7'
          , '0-07-830973-5'
          , '978-1418065805'
          , '1418065803'
          , '978-0-9890350-5-7'
          , '1-887736-06-9'
          , '0-914126-02-4'
          , '978-1-4842-5930-6'
          )
$bookData = $ISBNs | Get-ISBNBookData -Verbose
$bookData

$bookData | Select-Object -Property ISBN, Title

.NOTES
ArcaneBooks - Get-ISBNBookData.ps1

Author: Robert C Cain | @ArcaneCode | arcane@arcanetc.com

This code is Copyright (c) 2023 Robert C Cain All rights reserved

The code herein is for demonstration purposes.
No warranty or guarantee is implied or expressly granted.

This module may not be reproduced in whole or in part without
the express written consent of the author.

.LINK
https://github.com/arcanecode/ArcaneBooks/blob/1ebe781951f1a7fdf19bb6731487a74fa12ad08b/ArcaneBooks/Help/Get-ISBNBookData.md

.LINK
http://arcanecode.me
#&gt;
</code></pre>
<p>When I use the command <code>Get-Help Get-ISBNBookData -Full</code> this is the output.</p>
<pre><code class="language-powershell">SYNTAX
    Get-ISBNBookData [-ISBN] &lt;String&gt; [&lt;CommonParameters&gt;]


DESCRIPTION
    Uses the more advanced API at OpenLibrary to retrieved detailed information
    based on the 10 or 13 character ISBN passed in.


PARAMETERS
    -ISBN &lt;String&gt;
        A 10 or 13 digit ISBN number. The passed in value can have spaces or dashes,
        it will remove them before processing the request to get the book data.

        Required?                    true
        Position?                    1
        Default value
        Accept pipeline input?       true (ByValue)
        Accept wildcard characters?  false

    &lt;CommonParameters&gt;
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer, PipelineVariable, and OutVariable. For more information, see
        about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216).

INPUTS
    Via the pipeline this cmdlet can accept an array of ISBN values.


OUTPUTS
    The cmdlet returns one or more objects of type Class ISBNBook with the
    following properties. Note that not all properties may be present, it
    depends on what data the publisher provided.

    ISBN | The ISBN number that was passed in, complete with an formatting
    ISBN10 | ISBN as 10 digits
    ISBN13 | ISBN in 13 digit format
    Title | The title of the book
    LCCN | Library of Congress Catalog Number
    Author | The author(s) of the book
    ByStatement | The written by statement provided by the publisher
    NumberOfPages | Number of pages in the book
    Publishers | The Publisher(s) of this book
    PublishDate | The publication date for this edition of the book
    PublisherLocation | The location of the publisher
    Subject | Generic subject(s) for the work
    LibraryOfCongressClassification | Specialized classification used by Library of Congress
    DeweyDecimalClass | Dewey Decimal number
    Notes | Any additional information provided by the publisher
    CoverUrlSmall | URL link to an image of the book cover, in a small size
    CoverUrlMedium | URL link to an image of the book cover, in a medium size
    CoverUrlLarge | URL link to an image of the book cover, in a large size


NOTES


        ArcaneBooks - Get-ISBNBookData.ps1

        Author: Robert C Cain | @ArcaneCode | arcane@arcanetc.com

        This code is Copyright (c) 2023 Robert C Cain All rights reserved

        The code herein is for demonstration purposes.
        No warranty or guarantee is implied or expressly granted.

        This module may not be reproduced in whole or in part without
        the express written consent of the author.

    -------------------------- EXAMPLE 1 --------------------------

    PS &gt; # Pass in a single ISBN as a parameter
    $ISBN = '0-87259-481-5'
    $bookData = Get-ISBNBookData -ISBN $ISBN
    $bookData






    -------------------------- EXAMPLE 2 --------------------------

    PS &gt; # Pipe in a single ISBN
    $ISBN = '0-87259-481-5'
    $bookData = $ISBN | Get-ISBNBookData
    $bookData






    -------------------------- EXAMPLE 3 --------------------------

    PS &gt; # Pipe in an array of ISBNs
    $ISBNs = @( '0-87259-481-5'
              , '0-8306-7801-8'
              , '0-8306-6801-2'
              , '0-672-21874-7'
              , '0-07-830973-5'
              , '978-1418065805'
              , '1418065803'
              , '978-0-9890350-5-7'
              , '1-887736-06-9'
              , '0-914126-02-4'
              , '978-1-4842-5930-6'
              )
    $bookData = $ISBNs | Get-ISBNBookData -Verbose
    $bookData

    $bookData | Select-Object -Property ISBN, Title





RELATED LINKS
    https://github.com/arcanecode/ArcaneBooks/blob/1ebe781951f1a7fdf19bb6731487a74fa12ad08b/ArcaneBooks/Help/Get-ISBNBookData.md
    http://arcanecode.me
</code></pre>
<h2>See Also</h2>
<p><a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">The ArcaneBooks Project &#8211; An Introduction</a></p>
<h2>Conclusion</h2>
<p>As you can see, implementing comment based help is quite easy. It&#8217;s also important, as users rely on help to understand how to use the functions you author. You&#8217;ll also find it helpful as a reminder to yourself about the functionality of your own code down the road.</p>
<p>Another useful feature for help is to create <code>about_</code> help for your modules. You&#8217;ve likely seen these before, Microsoft provides <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about?view=powershell-7.4">a long list of about</a> topics for PowerShell itself.</p>
<p>You can create your own set of about help for your module, and in the next post I&#8217;ll show you how.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/05/02/fun-with-powershell-authoring-help/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.01.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/05/23.05.01.99_featured_image.png" medium="image">
			<media:title type="html">23.05.01.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>ArcaneBooks &#8211; Parsing Library of Congress Control Number (LCCN) Data With PowerShell</title>
		<link>https://arcanecode.com/2023/04/24/arcanebooks-parsing-library-of-congress-control-number-lccn-data-with-powershell/</link>
					<comments>https://arcanecode.com/2023/04/24/arcanebooks-parsing-library-of-congress-control-number-lccn-data-with-powershell/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 24 Apr 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[ArcaneBooks]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5176</guid>

					<description><![CDATA[ArcaneBooks - Parsing Library of Congress Control Number (LCCN) Data With PowerShell]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>In my previous post in this series, <a href="https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/">ArcaneBooks – Library of Congress Control Number (LCCN) – An Overview</a>, I provided an overview of the LCCN and the basics of calling its public web API to retrieve data based on the LCCN.</p>
<p>In this post I will demonstrate how to call the API and dissect the data using PowerShell. This will be a code intensive post.</p>
<p>You can find the full ArcaneBooks project on my <a href="https://github.com/arcanecode/ArcaneBooks">GitHub site</a>. Please note as of the writing of this post the project is still in development.</p>
<p>The code examples for this post can be located at <a href="https://github.com/arcanecode/ArcaneBooks/tree/main/Blog_Posts/005.00_LCCN_API">https://github.com/arcanecode/ArcaneBooks/tree/main/Blog_Posts/005.00_LCCN_API</a>. It contains the script that we&#8217;ll be dissecting here.</p>
<h2>XML from Library of Congress</h2>
<p>For this demo, we&#8217;ll be using an LCCN of <code>54-9698</code>, <em>Elements of radio servicing</em> by William Marcus. When we call the web API URL in our web browser, we get the following data.</p>
<pre><code class="language-xml">&lt;zs:searchRetrieveResponse xmlns:zs=&quot;http://docs.oasis-open.org/ns/search-ws/sruResponse&quot;&gt;
  &lt;zs:numberOfRecords&gt;2&lt;/zs:numberOfRecords&gt;
  &lt;zs:records&gt;
    &lt;zs:record&gt;
      &lt;zs:recordSchema&gt;mods&lt;/zs:recordSchema&gt;
      &lt;zs:recordXMLEscaping&gt;xml&lt;/zs:recordXMLEscaping&gt;
      &lt;zs:recordData&gt;
        &lt;mods xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
          xmlns=&quot;http://www.loc.gov/mods/v3&quot; version=&quot;3.8&quot; xsi:schemaLocation=&quot;http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-8.xsd&quot;&gt;
          &lt;titleInfo&gt;
            &lt;title&gt;Elements of radio servicing&lt;/title&gt;
          &lt;/titleInfo&gt;
          &lt;name type=&quot;personal&quot; usage=&quot;primary&quot;&gt;
            &lt;namePart&gt;Marcus, William. [from old catalog]&lt;/namePart&gt;
          &lt;/name&gt;
          &lt;name type=&quot;personal&quot;&gt;
            &lt;namePart&gt;Levy, Alex,&lt;/namePart&gt;
            &lt;role&gt;
              &lt;roleTerm type=&quot;text&quot;&gt;joint author&lt;/roleTerm&gt;
            &lt;/role&gt;
          &lt;/name&gt;
          &lt;typeOfResource&gt;text&lt;/typeOfResource&gt;
          &lt;originInfo&gt;
            &lt;place&gt;
              &lt;placeTerm type=&quot;code&quot; authority=&quot;marccountry&quot;&gt;nyu&lt;/placeTerm&gt;
            &lt;/place&gt;
            &lt;dateIssued encoding=&quot;marc&quot;&gt;1955&lt;/dateIssued&gt;
            &lt;issuance&gt;monographic&lt;/issuance&gt;
            &lt;place&gt;
              &lt;placeTerm type=&quot;text&quot;&gt;New York&lt;/placeTerm&gt;
            &lt;/place&gt;
            &lt;agent&gt;
              &lt;namePart&gt;McGraw Hill&lt;/namePart&gt;
            &lt;/agent&gt;
            &lt;dateIssued&gt;[1955]&lt;/dateIssued&gt;
            &lt;edition&gt;2d ed.&lt;/edition&gt;
          &lt;/originInfo&gt;
          &lt;language&gt;
            &lt;languageTerm authority=&quot;iso639-2b&quot; type=&quot;code&quot;&gt;eng&lt;/languageTerm&gt;
          &lt;/language&gt;
          &lt;physicalDescription&gt;
            &lt;form authority=&quot;marcform&quot;&gt;print&lt;/form&gt;
            &lt;extent&gt;566 p. illus. 24 cm.&lt;/extent&gt;
          &lt;/physicalDescription&gt;
          &lt;subject authority=&quot;lcsh&quot;&gt;
            &lt;topic&gt;Radio&lt;/topic&gt;
            &lt;topic&gt;Repairing. [from old catalog]&lt;/topic&gt;
          &lt;/subject&gt;
          &lt;classification authority=&quot;lcc&quot;&gt;TK6553 .M298 1955&lt;/classification&gt;
          &lt;identifier type=&quot;lccn&quot;&gt;54009698&lt;/identifier&gt;
          &lt;recordInfo&gt;
            &lt;recordContentSource authority=&quot;marcorg&quot;&gt;DLC&lt;/recordContentSource&gt;
            &lt;recordCreationDate encoding=&quot;marc&quot;&gt;820525&lt;/recordCreationDate&gt;
            &lt;recordChangeDate encoding=&quot;iso8601&quot;&gt;20040824072855.0&lt;/recordChangeDate&gt;
            &lt;recordIdentifier&gt;6046000&lt;/recordIdentifier&gt;
            &lt;recordOrigin&gt;Converted from MARCXML to MODS version 3.8 using MARC21slim2MODS3-8_XSLT1-0.xsl (Revision 1.172 20230208)&lt;/recordOrigin&gt;
          &lt;/recordInfo&gt;
        &lt;/mods&gt;
      &lt;/zs:recordData&gt;
      &lt;zs:recordPosition&gt;1&lt;/zs:recordPosition&gt;
    &lt;/zs:record&gt;
  &lt;/zs:records&gt;
  &lt;zs:nextRecordPosition&gt;2&lt;/zs:nextRecordPosition&gt;
  &lt;zs:echoedSearchRetrieveRequest&gt;
    &lt;zs:version&gt;2.0&lt;/zs:version&gt;
    &lt;zs:query&gt;bath.lccn=54009698&lt;/zs:query&gt;
    &lt;zs:maximumRecords&gt;1&lt;/zs:maximumRecords&gt;
    &lt;zs:recordXMLEscaping&gt;xml&lt;/zs:recordXMLEscaping&gt;
    &lt;zs:recordSchema&gt;mods&lt;/zs:recordSchema&gt;
  &lt;/zs:echoedSearchRetrieveRequest&gt;
  &lt;zs:diagnostics xmlns:diag=&quot;http://docs.oasis-open.org/ns/search-ws/diagnostic&quot;&gt;
    &lt;diag:diagnostic&gt;
      &lt;diag:uri&gt;info:srw/diagnostic/1/5&lt;/diag:uri&gt;
      &lt;diag:details&gt;2.0&lt;/diag:details&gt;
      &lt;diag:message&gt;Unsupported version&lt;/diag:message&gt;
    &lt;/diag:diagnostic&gt;
  &lt;/zs:diagnostics&gt;
&lt;/zs:searchRetrieveResponse&gt;
</code></pre>
<p>Let&#8217;s see how to retrieve this data then parse it using PowerShell.</p>
<h2>Parsing LCCN Data</h2>
<p>First, we&#8217;ll start by setting the LCCN in a variable. This is the LCCN for &quot;Elements of radio servicing&quot; by William Marcus</p>
<pre><code class="language-powershell">$LCCN = '54-9698'
</code></pre>
<p>To pass in the LCCN to the web API, we need to remove any dashes or spaces.</p>
<pre><code class="language-powershell">$lccnCleaned = $LCCN.Replace('-', '').Replace(' ', '')
</code></pre>
<p>After 2001 the LCCN started using a four digit year. By that time however, books were already printing the ISBN instead of the LCCN. For those books we&#8217;ll be using the ISBN, so for this module we can safely assume the LCCNs we are receiving only have a two digit year.</p>
<p>With that said, we&#8217;ll use the following code to extract the two digit year.</p>
<pre><code class="language-powershell">$lccnPrefix = $lccnCleaned.Substring(0,2)
</code></pre>
<p>Since digits 0 and 1 are the year, we&#8217;ll start getting the rest of the LCCN at the third digit, which is in position 2 and go to the end of the string, getting the characters.</p>
<p>Next, the API requires the remaining part of the LCCN must be six digits. So we&#8217;ll use the <code>PadLeft</code> method to put 0&#8217;s in front to make it six digits.</p>
<pre><code class="language-powershell">$lccnPadded = $lccnCleaned.Substring(2).PadLeft(6, '0')
</code></pre>
<p>Now combine the reformatted LCCN and save it to a variable.</p>
<pre><code class="language-powershell">$lccnFormatted =&quot;$($lccnPrefix)$($lccnPadded)&quot;
</code></pre>
<p>Now we&#8217;ll combine all the parts to create the URL needed to call the web API.</p>
<pre><code class="language-powershell">$baseURL = &quot;http://lx2.loc.gov:210/lcdb?version=3&amp;operation=searchRetrieve&amp;query=bath.lccn=&quot;
$urlParams = &quot;&amp;maximumRecords=1&amp;recordSchema=mods&quot;
$url = &quot;$($baseURL)$($lccnFormatted)$($urlParams)&quot;
</code></pre>
<p>It&#8217;s time now to get the LCCN data from the Library of Congress site. We&#8217;ll wrap it in a <code>try/catch</code> so in case the call fails, for example from the internet going down, it will provide a message and exit.</p>
<p>Note at the end of the <code>Write-Host</code> line we use the PowerShell line continuation character of ` (a single backtick) so we can put the foreground color on the next line, making the code a bit more readable.</p>
<pre><code class="language-powershell">try {
  $bookData = Invoke-RestMethod $url
}
catch {
  Write-Host &quot;Failed to retrieve LCCN $LCCN. Possible internet connection issue. Script exiting.&quot; `
    -ForegroundColor Red
  # If there's an error, quit running the script
  exit
}
</code></pre>
<p>Now we need to see if the book was found in the archive. If not the title will be null. We&#8217;ll use an <code>if</code> to check to see if the LCCN was found in their database. If not, the title property will be null. If so we display a message to that effect.</p>
<p>If it was found, we fall through into the <code>else</code> clause to process the data. The remaining code resides within the <code>else</code>.</p>
<pre><code class="language-powershell"># We let the user know, and skip the rest of the script
if ($null -eq $bookData.searchRetrieveResponse.records.record.recordData.mods.titleInfo.title)
{
  Write-Host = &quot;Retrieving LCCN $LCCN returned no data. The book was not found.&quot;
}
else # Great, the book was found, assign the data to variables
{
</code></pre>
<p>To get the data, we start at the root object, <code>$bookData</code>. The main node in the returned XML is <code>searchRetrieveResponse</code>. From here we can use standard dot notation to work our way down the XML tree to get the properties we want.</p>
<p>Our first entry gets the Library of Congress Number. The syntax is a little odd. If we walk XML tree, we find this stored in:</p>
<pre><code class="language-xml">&lt;identifier type=&quot;lccn&quot;&gt;54009698&lt;/identifier&gt;
</code></pre>
<p>If we display the identifier property using this code:</p>
<pre><code class="language-powershell">$bookData.searchRetrieveResponse.records.record.recordData.mods.identifier
</code></pre>
<p>We get this result.</p>
<pre><code>type #text
---- -----
lccn 54009698
</code></pre>
<p>The LCCN we want is stored in the property named <code>#text</code>. But <code>#text</code> isn&#8217;t a valid property name in PowerShell. We can still use it though if we wrap the name in quotes.</p>
<pre><code class="language-powershell">  $LibraryOfCongressNumber = $bookData.searchRetrieveResponse.records.record.recordData.mods.identifier.'#text'
</code></pre>
<p>From here we can process other properties that are easy to access.</p>
<pre><code class="language-powershell">  $Title = $bookData.searchRetrieveResponse.records.record.recordData.mods.titleInfo.title
  $PublishDate = $bookData.searchRetrieveResponse.records.record.recordData.mods.originInfo.dateIssued.'#text'
  $LibraryOfCongressClassification = $bookData.searchRetrieveResponse.records.record.recordData.mods.classification.'#text'
  $Description = $bookData.searchRetrieveResponse.records.record.recordData.mods.physicalDescription.extent
  $Edition = $bookData.searchRetrieveResponse.records.record.recordData.mods.originInfo.edition
</code></pre>
<p>Now we get to the section where an XML property can contain one or more values.</p>
<p>Books can have multiple authors, each is returned in its own item in an array. One example is the book subjects. Here is a sample of the XML:</p>
<pre><code class="language-xml">&lt;subject authority=&quot;lcsh&quot;&gt;
  &lt;topic&gt;Radio&lt;/topic&gt;
  &lt;topic&gt;Repairing. [from old catalog]&lt;/topic&gt;
&lt;/subject&gt;
</code></pre>
<p>As you can see, this has two topics. What we need to do is retrieve the root, in this case <code>subject</code>, then loop over each item.</p>
<p>For our purposes we don&#8217;t need them individually, a single string will do. So in the PowerShell we&#8217;ll create a new object of type <code>StringBuilder</code>. For more information on how to use StringBuilder, see my post <a href="https://arcanecode.com/2023/04/17/fun-with-powershell-stringbuilder/">Fun With PowerShell &#8211; StringBuilder</a>.</p>
<p>In the loop if the variable used to hold the string builder is empty, we&#8217;ll just add the first item. If it&#8217;s not empty, we&#8217;ll append a comma, then append the next value.</p>
<pre><code class="language-powershell">  $authors = [System.Text.StringBuilder]::new()
  foreach ($a in $bookData.searchRetrieveResponse.records.record.recordData.mods.name)
  {
    if ($a.Length -gt 1)
      { [void]$authors.Append(&quot;, $($a.namePart)&quot;) }
    else
      { [void]$authors.Append($a.namePart) }
  }
  $Author = $authors.ToString()
</code></pre>
<p>As a final step we used the <code>ToString</code> method to convert the data in the string builder back to a normal string and store it in the <code>$Author</code> variable.</p>
<p>From here, we&#8217;ll repeat this logic for several other items that can hold multiple values. The books subjects is one example.</p>
<pre><code class="language-powershell">  $subjects = [System.Text.StringBuilder]::new()
  $topics = $bookData.searchRetrieveResponse.records.record.recordData.mods.subject | Select topic
  foreach ($s in $topics.topic)
  {
    if ($subjects.Length -gt 1)
      { [void]$subjects.Append(&quot;, $($s)&quot;) }
    else
      { [void]$subjects.Append($s) }
  }
  $Subject = $subjects.ToString()
</code></pre>
<p>A book could have multiple publishers over time. The author could shift to a new publisher, or more likely a publishing house could be purchased and the new owners name used. The data is returned as an array, so combine them as we did with authors and subjects.</p>
<p>Note that in the returned data, the publisher is stored as an &quot;agent&quot;. We&#8217;ll use the name Publisher to keep it consistent with the ISBN data.</p>
<pre><code class="language-powershell">  $thePublishers = [System.Text.StringBuilder]::new()
  foreach ($p in $bookData.searchRetrieveResponse.records.record.recordData.mods.originInfo.agent)
  {
    if ($thePublishers.Length -gt 1)
      { [void]$thePublishers.Append(&quot;, $($p.namePart)&quot;) }
    else
      { [void]$thePublishers.Append($p.namePart) }
  }
  $Publishers = $thePublishers.ToString()
</code></pre>
<p>Since there could be multiple publishers, logically there could be multiple publishing locations. This section will combine them to a single location.</p>
<pre><code class="language-powershell">  $locations = [System.Text.StringBuilder]::new()
  foreach ($l in $bookData.searchRetrieveResponse.records.record.recordData.mods.originInfo.place.placeTerm)
  {
    if ($locations.Length -gt 1)
      { [void]$locations.Append(&quot;, $($l.'#text')&quot;) }
    else
      { [void]$locations.Append($l.'#text') }
  }
  $PublisherLocation = $locations.ToString()
</code></pre>
<p>All done! We&#8217;ll give a success message to let the user know.</p>
<pre><code class="language-powershell">  Write-Host &quot;Successfully retrieved data for LCCN $LCCN&quot; -ForegroundColor Green
</code></pre>
<p>Finally, we&#8217;ll display the results. Note some fields may not have data, that&#8217;s fairly normal. The Library of Congress only has the data provided by the publisher. In addition some of the LCCN data dates back many decades, so the data supplied in the 1940&#8217;s may be different than what is supplied today.</p>
<pre><code class="language-powershell">  &quot;LCCN: $LCCN&quot;
  &quot;Formatted LCCN: $lccnFormatted&quot;
  &quot;Library Of Congress Number: $LibraryOfCongressNumber&quot;
  &quot;Title: $Title&quot;
  &quot;Publish Date: $PublishDate&quot;
  &quot;Library Of Congress Classification: $LibraryOfCongressClassification&quot;
  &quot;Description: $Description&quot;
  &quot;Edition: $Edition&quot;
  &quot;Author: $Author&quot;
  &quot;Subject: $Subject&quot;
  &quot;Publishers: $Publishers&quot;
  &quot;Publisher Location: $PublisherLocation&quot;
}
</code></pre>
<h2>The Result</h2>
<p>Here is the result of the above code.</p>
<pre><code>LCCN: 54-9698
Formatted LCCN: 54009698
Library Of Congress Number: 54009698
Title: Elements of radio servicing
Publish Date: 1955
Library Of Congress Classification: TK6553 .M298 1955
Description: 566 p. illus. 24 cm.
Edition: 2d ed.
Author: Marcus, William. [from old catalog], Levy, Alex,
Subject: Radio, Repairing. [from old catalog]
Publishers: McGraw Hill
Publisher Location: nyu, New York
</code></pre>
<p>As you can see it returned a full dataset. Not all books my have data for all the fields, but this one had the full details on record with the Library of Congress.</p>
<h2>See Also</h2>
<p>This section has links to other blog posts or websites that you may find helpful.</p>
<p><a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">The ArcaneBooks Project &#8211; An Introduction</a></p>
<p><a href="https://arcanecode.com/2023/03/20/arcanebooks-isbn-overview-powershell-and-the-simple-openlibrary-isbn-api/">ArcaneBooks – ISBN Overview, PowerShell, and the Simple OpenLibrary ISBN API</a></p>
<p><a href="https://arcanecode.com/2023/04/03/arcanebooks-powershell-and-the-advanced-openlibrary-isbn-api/">ArcaneBooks – PowerShell and the Advanced OpenLibrary ISBN API</a></p>
<p><a href="https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/">ArcaneBooks – Library of Congress Control Number (LCCN) – An Overview</a></p>
<p><a href="https://arcanecode.com/2023/04/17/fun-with-powershell-stringbuilder/">Fun With PowerShell &#8211; StringBuilder</a></p>
<p><a href="https://github.com/arcanecode/ArcaneBooks">The GitHub Site for ArcaneBooks</a></p>
<h2>Conclusion</h2>
<p>In this document we covered the basics of the LCCN as well as the web API provided by the Library of Congress. Understanding this information is important when we integrate the call into our PowerShell code.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/04/24/arcanebooks-parsing-library-of-congress-control-number-lccn-data-with-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/03/001.90_featured_image.jpg" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/03/001.90_featured_image.jpg" medium="image">
			<media:title type="html">001.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>Fun With PowerShell &#8211; StringBuilder</title>
		<link>https://arcanecode.com/2023/04/17/fun-with-powershell-stringbuilder/</link>
					<comments>https://arcanecode.com/2023/04/17/fun-with-powershell-stringbuilder/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 17 Apr 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[StringBuilder]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5172</guid>

					<description><![CDATA[Fun With PowerShell - StringBuilder]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>As I was creating the next post in my ArcaneBooks series, I realized I had not written about the <code>StringBuilder</code> class. As the code in my ArcaneBooks module relies on it in several places, I thought it best to add a new post to my Fun With PowerShell series explaining how to use it before continuing.</p>
<p>It&#8217;s a common need in any language, and PowerShell is no exception, to need to add more text to an existing string.</p>
<p>What many people don&#8217;t realize though is that PowerShell strings are <em>immutable</em>. They cannot change. As an example, let&#8217;s talk about what happens behind the scenes when you execute this code sample.</p>
<pre><code class="language-powershell">$x = 'Arcane'
$x = $x + 'Code'
</code></pre>
<p>First, PowerShell creates a variable in memory. For an example, we&#8217;ll say the memory is located at position 0001.</p>
<p>In the second line of code, PowerShell creates a second variable in memory, let&#8217;s say it is position 0002. Into position 0002, it copies the data from position 0001 then adds the <code>Code</code> string.</p>
<p>Next, it changes <code>$x</code> to point to memory location 0002. Finally, it marks position 0001 as no longer in use. At some point in the future, the <strong>garbage collector</strong> will clean up the memory when there is some idle time. The <strong>garbage collector</strong> is a system function that removes chunks of memory that are no longer in use, freeing up memory for other code to use.</p>
<h2>Why This Is Bad</h2>
<p>In the example above, we only had one variable (the one at location 0001) that needed to be garbage collected. Imagine though you were looping over thousands of records of data, building a complex string that perhaps you&#8217;ll later save to a file. The amount of work the garbage collector would need to do is enormous. It would have a negative impact on system performance, and create a slow running script.</p>
<p>To solve this, the <strong>StringBuilder</strong> class was created. Behind the scenes it uses a <em>linked list</em>. Let me step through an example a step at a time.</p>
<p>Step 1 &#8211; Create an empty string builder object</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
</code></pre>
<p>Step 2 &#8211; Append text to the StringBuilder variable we created</p>
<p>To add a string value, we will use the <code>Append</code> method. Note when we use methods such as <code>Append</code> it returns data. Most of the time we don&#8217;t need to see this. By using <code>[void]</code> before the line, the output of the <code>Append</code> method is discarded.</p>
<pre><code class="language-powershell">[void]$output.Append('Arcane')
</code></pre>
<p>We now have an item in memory, we&#8217;ll call it position one. This holds two values, the string value and a pointer to the next item. If there is no next item, the pointer value is <code>null</code>.</p>
<table>
<thead>
<tr>
<th>Position</th>
<th>Text</th>
<th>Pointer to next item</th>
</tr>
</thead>
<tbody>
<tr>
<td>0001</td>
<td>Arcane</td>
<td>null</td>
</tr>
</tbody>
</table>
<p>Step 3 &#8211; Append a second string</p>
<pre><code class="language-powershell">[void]$output.Append('Code')
</code></pre>
<p>The string builder now updates the linked list.</p>
<table>
<thead>
<tr>
<th>Position</th>
<th>Text</th>
<th>Pointer to next item</th>
</tr>
</thead>
<tbody>
<tr>
<td>0001</td>
<td>Arcane</td>
<td>0002</td>
</tr>
<tr>
<td>0002</td>
<td>Code</td>
<td>null</td>
</tr>
</tbody>
</table>
<p>Step 4 &#8211; Retrieve the data</p>
<p>When we go to retrieve the data, the string builder will go through the chain, assemble the final data and return it. In order to copy it into a standard string variable, we&#8217;ll need to use the <code>ToString</code> method to convert the result from a string builder object to a standard string.</p>
<pre><code class="language-powershell">$result = $output.ToString()
</code></pre>
<h2>Why this is a good solution</h2>
<p>Here, PowerShell only created one variable, then kept appending to the linked list. When we are done with the variable <code>$output</code> the garbage collector only has to cleanup one variable, not hundreds or (potentially) thousands.</p>
<p>When you only have a few items, and are sure their sizes are small, then using a string builder may not provide much benefit in terms of performance. However, when you have an unknown number of items then string builder can be a friend.</p>
<p>In addition to <code>Append</code>, string builder has several more methods that are of use. Let&#8217;s look at them now.</p>
<h2>Append</h2>
<p>While we just looked at using <code>Append</code>, I want to use this section to remind you to include proper spacing when creating your strings.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'PowerShell is awesome!' )
[void]$output.Append( ' It makes my life much easier.' )
[void]$output.Append( ' I think I''ll go watch some of Robert''s videos on Pluralsight.' )
$output.ToString()
</code></pre>
<p>This results in:</p>
<pre><code>PowerShell is awesome! It makes my life much easier. I think I''ll go watch some of Robert''s videos on Pluralsight.
</code></pre>
<p>Note that on the second and third calls to the <code>Append</code> method I included a space at the beginning of the line. This was needed to make the output look like a true series of sentences, with spaces after the periods.</p>
<p>You could have also put spaces at the end of the lines, that is up to you and your needs when building your code.</p>
<h2>AppendLine</h2>
<p>When appending, you sometimes want a carriage return / line feed character added to the end of the text that was appended. To handle this, we have the <code>Appendline</code> method.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'PowerShell is awesome!' )
[void]$output.AppendLine( ' It makes my life much easier.' )
[void]$output.Append( 'I think I''ll go watch some of Robert''s videos on Pluralsight.' )
$output.ToString()
</code></pre>
<p>In the result, you can see the line wraps after the &quot;&#8230;much easier.&quot; line.</p>
<pre><code>PowerShell is awesome! It makes my life much easier.
I think I'll go watch some of Robert's videos on Pluralsight.
</code></pre>
<p>This can be handy when, for example, you are building a string that will be written out as a CSV (comma separated values) file. Each row of data will be saved as an individual line.</p>
<p>You may also have situations where you are building a big string that you want as something more readable. Perhaps you are building a string that will be emailed as a report. In it you&#8217;d want blank lines between each paragraph.</p>
<p>To accomplish this, you can just use <code>AppendLine</code> without passing a value into it.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'PowerShell is awesome!' )
[void]$output.AppendLine( ' It makes my life much easier.' )
[void]$output.AppendLine()
[void]$output.Append( 'I think I''ll go watch some of Robert''s videos on Pluralsight.' )
$output.ToString()
</code></pre>
<p>The output from this code is:</p>
<pre><code>PowerShell is awesome! It makes my life much easier.

I think I'll go watch some of Robert's videos on Pluralsight.
</code></pre>
<h2>AppendFormat</h2>
<p>The third version of append is <code>AppendFormat</code>. It allows you to append a numerical value, and specify a string format.</p>
<p>In the example below, the first parameter is <code>{0:C}</code>. Into the spot where the 0 is, the numeric value in the second parameter, <code>$value</code> is placed. The <code>:C</code> indicates a <em>currency</em> format should be used.</p>
<pre><code class="language-powershell">$value = 33
$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'The value is: ' )
[void]$output.AppendFormat( &quot;{0:C}&quot;, $value )
$output.ToString()
</code></pre>
<p>This results in:</p>
<pre><code>The value is: $33.00
</code></pre>
<p>The formats supported by string builder are identical to the ones that the string data type uses.</p>
<p>For more information on string formatting, please see my post <a href="https://arcanecode.com/2021/07/19/fun-with-powershell-string-formatting/">Fun With PowerShell String Formatting</a></p>
<h2>Insert</h2>
<p>You may have a situation where you need to insert text into the text already saved in your string builder variable. To accomplish this, we can use the <code>Insert</code> method.</p>
<p>As the first parameter we pass in the position we wish to start inserting at. The second parameter holds the text to be inserted.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'Arcane' )
[void]$output.Append( ' writes great blog posts.' )
[void]$output.Insert(6, 'Code')
$output.ToString()
</code></pre>
<p>The output of the above sample is:</p>
<pre><code>ArcaneCode writes great blog posts.
</code></pre>
<h2>Remove</h2>
<p>In addition to inserting text, we can also remove text using the <code>Remove</code> method. It requires two parameters, the first is the position to start removing at, the second is the number of characters to remove.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'ArcaneCode' )
[void]$output.Append( ' writes great blog posts.' )
[void]$output.Remove(6, 4)
$output.ToString()
</code></pre>
<p>In this example I&#8217;m removing the text <code>Code</code> from <code>ArcaneCode</code>.</p>
<pre><code>Arcane writes great blog posts.
</code></pre>
<h2>Replace</h2>
<p>You may recall that the string data type has a replace method. So too does the string builder, also named <code>Replace</code>. In the first parameter you pass in the character to be replaced. The second is what you want to replace it with.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( 'ArcaneCode' )
[void]$output.AppendLine( ' writes great blog posts.' )
[void]$output.Append( 'I think I''ll go watch some of Robert''s videos on Pluralsight.' )
[void]$output.Replace('.', '!')
$output.ToString()
</code></pre>
<p>In this simple example, I&#8217;m going to replace all periods in the text with exclamation marks.</p>
<pre><code>ArcaneCode writes great blog posts!
I think I'll go watch some of Robert's videos on Pluralsight!
</code></pre>
<p>Be aware <code>Replace</code> works on the entire text held in string builder, replacing every occurance found. If you want to limit the replacements, you&#8217;d have to do so prior to any appending you do.</p>
<p>The <code>Replace</code> method is most commonly used to remove special characters from your text, perhaps a result from reading in data from file that contains things like squiggly braces and brackets.</p>
<p>The replacement character can be an empty string, which results in simply removing the unwanted character.</p>
<p>Finally, you can stack multiple methods into one operation. For example, if the string builder holds the text:</p>
<pre><code>{ArcaneCode}, [arcanecode.com]
</code></pre>
<p>You can do:</p>
<pre><code class="language-powershell">$output.Replace('{', '').Replace('}', '').Replace('[', '').Replace(']', '')
</code></pre>
<p>Which results in the following text:</p>
<pre><code>ArcaneCode, arcanecode.com
</code></pre>
<p>And you aren&#8217;t limited to stacking replaces, you can mix and match methods.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new()
[void]$output.Append( '[ArcaneCode]' ).Replace('[', '').Replace(']', '').Insert(6, ' ')
$output.ToString()
</code></pre>
<p>Results in:</p>
<pre><code>Arcane Code
</code></pre>
<p>If you get carried away this can get ugly and hard to read. But it is possible so you should know about it. There are times when it can make the code more compact and a bit easier to read, such as:</p>
<pre><code class="language-powershell">[void]$output.Replace('[', '').Replace(']', '')
</code></pre>
<h2>Adding the first string when you create a StringBuilder object</h2>
<p>There is one last capability to look at. When you instantiate (fancy word for create) the new string builder object, you can pass in the first text value to be stored in the string builder.</p>
<p>Here I&#8217;m passing in the text <code>ArcaneCode</code> when we create the variable.</p>
<pre><code class="language-powershell">$output = [System.Text.StringBuilder]::new('ArcaneCode')
[void]$output.Append( ' writes great blog posts.' )
$output.ToString()
</code></pre>
<p>The output is like you&#8217;d expect.</p>
<pre><code>ArcaneCode writes great blog posts.
</code></pre>
<h2>See Also</h2>
<p>You may find more helpful information at the links below.</p>
<p><a href="https://arcanecode.com/2021/07/12/fun-with-powershell-strings/">Fun With PowerShell Strings</a></p>
<p><a href="https://arcanecode.com/2021/07/19/fun-with-powershell-string-formatting/">Fun With PowerShell String Formatting</a></p>
<p>If you want to go deeper on the internals of the <code>StringBuilder</code> class, Andrew Lock has a great series of articles <a href="https://andrewlock.net/a-deep-dive-on-stringbuilder-part-1-the-overall-design-and-first-look-at-the-internals/">at his blog</a>.</p>
<h2>Conclusion</h2>
<p>The string builder class can be a great tool for optimizing your scripts that do a lot of text manipulation.</p>
<p>Now that you have an understanding of the string builder class, we&#8217;re free to proceed with the next post in the ArcaneBooks project.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/04/17/fun-with-powershell-stringbuilder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/04/23.04.17.99_featured_image.png" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/04/23.04.17.99_featured_image.png" medium="image">
			<media:title type="html">23.04.17.99_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
		<item>
		<title>ArcaneBooks &#8211; Library of Congress Control Number (LCCN) &#8211; An Overview</title>
		<link>https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/</link>
					<comments>https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/#respond</comments>
		
		<dc:creator><![CDATA[arcanecode]]></dc:creator>
		<pubDate>Mon, 10 Apr 2023 15:00:00 +0000</pubDate>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[ArcaneBooks]]></category>
		<category><![CDATA[LCCN]]></category>
		<category><![CDATA[Library of Congress]]></category>
		<guid isPermaLink="false">http://arcanecode.com/?p=5165</guid>

					<description><![CDATA[ArcaneBooks - Library of Congress Control Number (LCCN) - An Overview]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-jetpack-markdown"><h2>Introduction</h2>
<p>This is part of my ongoing series on my ArcaneBooks project. The goal is to provide a module to retrieve book data via provided web APIs. In the <strong>SEE ALSO</strong> section later in this post I&#8217;ll provide links to previous posts which cover the background of the project, as well as how to use the OpenLibrary APIs to get data based on the ISBN.</p>
<p>In this post I will provide an overview of using the Library of Congress API to get data based on the LCCN, short for Library of Congress Control Number.</p>
<p>The next post in this series will provide code examples and an explanation of how to use PowerShell to get data using the Library of Congress API.</p>
<h1>LCCN Overview</h1>
<p>The abbreviation <strong>LCCN</strong>, according to the Library of Congress&#8217;s own website, stands for <em>Library of Congress Control Number</em>. When the system was first created in 1898, however, LCCN stood for <em>Library of Congress Card Number</em>, and I&#8217;ve seen it both ways in publications.</p>
<p>I&#8217;ve also seen a few places define it as <em>Library of Congress Catalog Number</em>, although this was never an official designation.</p>
<p>The LCCN was created in 1898 to provide a unique value to every item in the Library of Congress. This not only includes books, but works of art, manuscripts (not in book form), maps, and more.</p>
<h2>LCCN Format</h2>
<p>The LCCN has two parts, a prefix followed by a serial number. From 1898 to 2000 the prefix was two digits, representing the year. Beginning in 2001 the prefix became four digits, representing the year.</p>
<p>The serial number is simple a sequential number. 45-1 was the first number assigned in 1945. 45-1234 was the 1,234th item assigned in that year.</p>
<p>Be aware from 1969 to 1972 there was an experiment where the single digit of 7 was used for the prefix. They decided this scheme wasn&#8217;t going to work out, and reverted to the standard format of year followed by serial number.</p>
<p>Here are a few examples of real LCCNs from books in my personal collection. You can use these in your own testing.</p>
<table>
<thead>
<tr>
<th>LCCN</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>54-9698</td>
<td>Elements of Radio Servicing</td>
</tr>
<tr>
<td>40-33904</td>
<td>Radio Handbook Twenty-Second Edition</td>
</tr>
<tr>
<td>41-3345</td>
<td>The Radio Amateur&#8217;s Handbook 42nd Edition 1965</td>
</tr>
<tr>
<td>64-20875</td>
<td>Early Electrical Communication</td>
</tr>
<tr>
<td>74-75450</td>
<td>VHF Handbook for Radio Amateurs</td>
</tr>
<tr>
<td>76-190590</td>
<td>Wire Antennas for Radio Amateurs</td>
</tr>
<tr>
<td>71-120473</td>
<td>73 Vertical, Beam, and Triangle Antennas</td>
</tr>
</tbody>
</table>
<h2>Accessing Book Data from the Library of Congress</h2>
<p>The Library of Congress actually provides two web APIs for getting book data. The first API is for accessing assets, such as digital assets. It doesn&#8217;t return much data for books.</p>
<p>The second is the LC Z39.50 system, accessible through lx2.loc.gov. Here is an example of calling it to retrieve a record for the book <strong>Elements of Radio Servicing</strong>, which has the LCCN of 54-9698. (It should, of course, all be used as a single line just in case your web browser wraps it.)</p>
<pre><code>http://lx2.loc.gov:210/lcdb?version=3&amp;amp;operation=searchRetrieve&amp;amp;query=bath.lccn=54009698&amp;amp;maximumRecords=1&amp;amp;recordSchema=mods
</code></pre>
<p>Breaking it down, the root call is to <code>http://lx2.loc.gov:210/lcdb</code>. After this is a question mark <code>?</code>, followed by the parameters.</p>
<p>The first parameter is <code>version=3</code>. This indicates which format to use for the return data. It supports two versions, 1.1 and 3. For our purposes we&#8217;ll use the most current version, 3.</p>
<p>Following the ampersand <code>&amp;amp;</code> is <code>operation=searchRetrieve</code>. This instructs the Library of Congress&#8217;s API that we want to do a search to retrieve data.</p>
<p>Next is the core piece, we need to tell it what LCCN number to look up, <code>query=bath.lccn=54009698</code>. The root object is <code>bath</code>, then it uses the property <code>lccn</code>.</p>
<p>The LCCN has to be formatted in a specific way. We start with the two or four digit year. In the above example, 54-9698, this would be the two digit year of <code>54</code>.</p>
<p>Next is the serial number. If the number is less than six digits, it must be left zero padded to become six. Thus 9698 becomes <code>009698</code>. The year and serial number are combined, removing any dashes, spaces, or other characters and becomes <code>54009698</code>.</p>
<p>Following is <code>maximumRecords=1</code>, indicating we only expect one record back. That&#8217;s all we&#8217;ll get back with a single LCCN anyway, so this will work fine for our needs.</p>
<p>The final parameter is <code>recordSchema=mods</code>. The API supports several formats.</p>
<table>
<thead>
<tr>
<th>Record Schema</th>
<th>Description</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>dc</td>
<td>Dublin Core (bibliographic records)</td>
<td>Brings back just the basics (Name, author, etc)</td>
</tr>
<tr>
<td>mads</td>
<td>MADS (authority records)</td>
<td>Brief, not a lot of info</td>
</tr>
<tr>
<td>mods</td>
<td>MODS (bibliographic records)</td>
<td>Very readable XML schema, most info</td>
</tr>
<tr>
<td>marcxml</td>
<td>MARCXML &#8211; the default schema</td>
<td>Abbreviated schema, not readable</td>
</tr>
<tr>
<td>opacxml</td>
<td>MARCXML (wth holdings attached)</td>
<td>As above with a bit more info</td>
</tr>
</tbody>
</table>
<p>You are welcome to experiment with different formats, but for this module we&#8217;ll be using <code>mods</code>. It provides the most information, and is in XML. XML is very easy to read, and it works great with PowerShell.</p>
<h2>ISBN and Library of Congress</h2>
<p>It is possible to use the Library of Congress to look up the ISBN. In my testing though, the interface provided by OpenLibrary provided more data. Thus we&#8217;ll be using it for looking up ISBNs in this module.</p>
<p>We&#8217;ll use the LCCN API for books where we only have the LCCN.</p>
<h2>See Also</h2>
<p><a href="https://arcanecode.com/2023/03/13/the-arcanebooks-project-an-introduction/">The ArcaneBooks Project &#8211; An Introduction</a></p>
<p><a href="https://arcanecode.com/2023/03/20/arcanebooks-isbn-overview-powershell-and-the-simple-openlibrary-isbn-api/">ArcaneBooks – ISBN Overview, PowerShell, and the Simple OpenLibrary ISBN API</a></p>
<p><a href="https://arcanecode.com/2023/04/03/arcanebooks-powershell-and-the-advanced-openlibrary-isbn-api/">ArcaneBooks – PowerShell and the Advanced OpenLibrary ISBN API</a></p>
<h2>Conclusion</h2>
<p>In this document we covered the basics of the LCCN as well as the web API provided by the Library of Congress. Understanding this information is important when we integrate the call into our PowerShell code.</p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://arcanecode.com/2023/04/10/arcanebooks-library-of-congress-control-number-lccn-an-overview/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		
		<media:thumbnail url="https://arcanecode.com/wp-content/uploads/2023/03/001.90_featured_image.jpg" />
		<media:content url="https://arcanecode.com/wp-content/uploads/2023/03/001.90_featured_image.jpg" medium="image">
			<media:title type="html">001.90_featured_image</media:title>
		</media:content>

		<media:content url="https://1.gravatar.com/avatar/461a2d99b1a8f2425c5ea54c260326893456aafc7b54df0c1563e4d308dd2817?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">arcanecode</media:title>
		</media:content>
	</item>
	</channel>
</rss>
