<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Matthew J. Clemente</title>
    <description>The latest articles on Forem by Matthew J. Clemente (@mjclemente).</description>
    <link>https://forem.com/mjclemente</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F174250%2F9837e43d-fdbb-41e4-91e4-d47173be1889.jpeg</url>
      <title>Forem: Matthew J. Clemente</title>
      <link>https://forem.com/mjclemente</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mjclemente"/>
    <language>en</language>
    <item>
      <title>Notes on Migrating from MS SQL Server to PostgreSQL</title>
      <dc:creator>Matthew J. Clemente</dc:creator>
      <pubDate>Tue, 04 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/mjclemente/notes-on-migrating-from-ms-sql-server-to-postgresql-m77</link>
      <guid>https://forem.com/mjclemente/notes-on-migrating-from-ms-sql-server-to-postgresql-m77</guid>
      <description>&lt;p&gt;I'm not a database guru or SQL sherpa, but from time to time I do fill the role of de facto DBA. The following are some notes and observations from a recent, successful, migration from Microsoft SQL Server to PostgreSQL. Is it everything you need to know? Absolutely not. But there are some points and resources that will hopefully be helpful.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Note on Versions&lt;/li&gt;
&lt;li&gt;Moving the Database&lt;/li&gt;
&lt;li&gt;
Updating Application Code for PostgreSQL

&lt;ul&gt;
&lt;li&gt;Lowercase table and column names&lt;/li&gt;
&lt;li&gt;Switch from TOP to LIMIT&lt;/li&gt;
&lt;li&gt;Use RETURNING with INSERT to retrieve identity&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;CONCAT&lt;/code&gt; instead of &lt;code&gt;+&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Accounting for the Boolean data type&lt;/li&gt;
&lt;li&gt;Different reserved keywords&lt;/li&gt;
&lt;li&gt;Formatting dates and times:&lt;/li&gt;
&lt;li&gt;Switch from &lt;code&gt;STUFF... FOR XML PATH('')&lt;/code&gt; to &lt;code&gt;string_agg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Final Notes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Note on Versions
&lt;/h2&gt;

&lt;p&gt;Many of the articles that I came across comparing SQL Server and Postgres, aside from those that were useless from a practical standpoint, were outdated. That is, comparing PG 9.3 with SQL Server 2014 just isn't going to paint an accurate picture of where they stand today (February 2020). So, for context, this was a migration from a dedicated instance of MS SQL Server 2016, as well as cloud-based &lt;a href="https://azure.microsoft.com/en-us/services/sql-database/"&gt;Azure SQL Databases&lt;/a&gt; to &lt;a href="https://www.digitalocean.com/products/managed-databases-postgresql/"&gt;DigitalOcean's managed PostgreSQL hosting&lt;/a&gt;, running PostgreSQL v11. &lt;/p&gt;

&lt;h2&gt;
  
  
  Moving the Database
&lt;/h2&gt;

&lt;p&gt;I thought this would be the hard part, but the actual migration of the data from one database engine to the other turned out to be rather straightforward, thanks to the aptly named tool: &lt;a href="https://www.convert-in.com/mss2pgs.htm"&gt;MS SQL to PostgreSQL&lt;/a&gt;. The data transfers was fast, it retained foreign keys and indexes, and allowed a high degree of control over the operation and handling of tables and columns. A few dry runs to testing servers were necessary to work out the exact settings and process, but we were very happy with the results.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; The more labor intensive part of changing database engines was updating our application code to be PostgreSQL compatible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating Application Code for PostgreSQL
&lt;/h2&gt;

&lt;p&gt;While not comprehensive, here are some of the differences between SQL Server and Postgres that we needed to account for in our applications.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; In no particular order:&lt;/p&gt;

&lt;h3&gt;
  
  
  Lowercase table and column names
&lt;/h3&gt;

&lt;p&gt;PostgreSQL handles the casing of identifiers differently than SQL Server, which is to say, &lt;em&gt;case matters&lt;/em&gt;. There are &lt;a href="https://github.com/ontop/ontop/wiki/Case-sensitivity-for-SQL-identifiers"&gt;numerous&lt;/a&gt; &lt;a href="https://dev.to/lefebvre/dont-get-bit-by-postgresql-case-sensitivity--457i"&gt;discussions&lt;/a&gt; about this online, so I won't repeat them. The approach we took was to lowercase all identifers. At the database level, this was done by the data transfer tool mentioned earlier, but within the application, we had to do it manually. No magic tool here. We worked our way through the code base, lowercasing as we went. Visual Studio Code's shortcut &lt;strong&gt;Command-K-L&lt;/strong&gt; (⌘+K+L) came in very handy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switch from TOP to LIMIT
&lt;/h3&gt;

&lt;p&gt;Postgres, like MySQL, applies limits to the result set at the end of the SQL statement using &lt;code&gt;LIMIT&lt;/code&gt;, while SQL Server does this at the outset, using &lt;code&gt;TOP&lt;/code&gt;. So we had to go through updating queries from &lt;code&gt;SELECT TOP 1&lt;/code&gt; to &lt;code&gt;SELECT ... LIMIT 1&lt;/code&gt;. It wasn't hard; it just takes a while.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use RETURNING with INSERT to retrieve identity
&lt;/h3&gt;

&lt;p&gt;When an INSERT statement generates an identity value, applications frequently have need to retrieve and use that generated identifier. For example, if you insert a new client, you probably want to know the client's ID. MS SQL Server provides &lt;code&gt;SCOPE_IDENTITY()&lt;/code&gt; for this purpose, and some programming languages will return the generated identifier value automatically following an INSERT query. With PostgreSQL, you need to modify your INSERT statement, adding a line that specifies the column value you need returned. Here's how that looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Testy'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'McTester'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RETURNING&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- returns the value generated for this record in the id column&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The reason for this has to do with Postgres apparently not having a concept of a table's "identity". You can read more about it &lt;a href="https://stackoverflow.com/questions/2944297/postgresql-function-for-last-inserted-id"&gt;here on Stack Overflow&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;CONCAT&lt;/code&gt; instead of &lt;code&gt;+&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Postgres does not allow the use of the &lt;code&gt;+&lt;/code&gt; operator for string concatenation, so queries composed like the example here will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;firstname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;fullname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This syntax will need to be rewritten, using &lt;code&gt;CONCAT&lt;/code&gt;, as shown here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;CONCAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;fullname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While putting this together, I learned that &lt;code&gt;CONCAT&lt;/code&gt; is &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/concat-transact-sql?view=sql-server-ver15"&gt;supported in SQL Server&lt;/a&gt; - I just hadn't ever used it. While a bit strange at first, I prefer the &lt;code&gt;CONCAT&lt;/code&gt; syntax now; I find the resulting code to be cleaner - easier to read, write, and modify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accounting for the Boolean data type
&lt;/h3&gt;

&lt;p&gt;In SQL Server, the &lt;em&gt;bit&lt;/em&gt; data type is typically used as a stand in for boolean values. Postgres provides a true boolean data type, unsurprisingly named &lt;em&gt;boolean&lt;/em&gt;. However, because they are fundementally different data types (though meant to convey the same thing), they behave in subtly different ways.  &lt;/p&gt;

&lt;p&gt;For example, the bit data type can be compared to integers, as well as boolean string values, as seen in these SQL Server examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- SQL Server&lt;/span&gt;
&lt;span class="c1"&gt;-- bit to integer comparison (valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="c1"&gt;-- bit to boolean string comparison (valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, SQL Server does not allow columns of the bit data type to be actually used as booleans:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- SQL Server&lt;/span&gt;
&lt;span class="c1"&gt;-- bit to boolean comparison (not valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;

&lt;span class="c1"&gt;-- bit as boolean implying truth (not valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On the other hand, the PostgreSQL boolean data type &lt;em&gt;cannot be compared with integers&lt;/em&gt;; it results in the following error: &lt;code&gt;ERROR: operator does not exist: boolean = integer&lt;/code&gt; (which we saw a lot of) - that is, the following is invalid in Postgres:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Postgres&lt;/span&gt;
&lt;span class="c1"&gt;-- boolean to integer comparison (not valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, as you would expect, the boolean data type in Postgres does function as a true boolean, so the following examples are valid in Postgres:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Postgres&lt;/span&gt;
&lt;span class="c1"&gt;-- boolean to boolean comparison (valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;

&lt;span class="c1"&gt;-- boolean auto cast to boolean string (valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'TRUE'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'T'&lt;/span&gt;

&lt;span class="c1"&gt;-- boolean implying true/false (valid)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All of which is a long-winded way to say that there were instances in our codebase where we were comparing boolean columns to 1 or 0, and we needed to update them to use the actual booleans TRUE or FALSE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different reserved keywords
&lt;/h3&gt;

&lt;p&gt;I don't have a comprehensive list of the different reserved keywords - just a note that this difference can cause issues. In our case, we had a column named &lt;code&gt;offset&lt;/code&gt;, which was acceptable in SQL Server, but which we needed to quote in order to use in Postgres, as the keyword is reserved. For reference, here's the list of &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/reserved-keywords-transact-sql?view=sql-server-ver15"&gt;SQL Server reserved keywords&lt;/a&gt;, and here are the &lt;a href="https://www.postgresql.org/docs/current/sql-keywords-appendix.html"&gt;Postgres SQL keywords&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatting dates and times:
&lt;/h3&gt;

&lt;p&gt;This is a minor difference, but even minor differences need to be changed. When formatting dates, as in a SELECT statement, the function and syntax used are different. While SQL Server used &lt;code&gt;FORMAT&lt;/code&gt;, Postgres uses  &lt;code&gt;to_char&lt;/code&gt;, as in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- SQL Server &lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
&lt;span class="n"&gt;FORMAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastmodified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'M/d/yy h:mm tt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;readabledatetime&lt;/span&gt;

&lt;span class="c1"&gt;-- Postgres&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
&lt;span class="n"&gt;to_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastmodified&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'FMMM/FMDD/YY HH12:MI AM'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;readabledatetime&lt;/span&gt;

&lt;span class="c1"&gt;-- Example Output: 8/1/19 8:21 PM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here are the &lt;a href="https://www.postgresql.org/docs/11/functions-formatting.html"&gt;Postgres docs on formatting&lt;/a&gt;, which you'll need to review if this type of change impacts you. I was impressed with how configurable the formatting options were - for instance, note that in the example above, the &lt;code&gt;FM&lt;/code&gt; prefix is used to supress leading 0s.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switch from &lt;code&gt;STUFF... FOR XML PATH('')&lt;/code&gt; to &lt;code&gt;string_agg&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you've never needed to use SQL Server's &lt;code&gt;STUFF&lt;/code&gt; with &lt;code&gt;FOR XML PATH('')&lt;/code&gt; to concatenate the results of a subquery as a list... then count yourself lucky and just skip this section. If you have, then you know that the syntax is not straightforward and can be difficult to parse.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; Here's an example of what I'm talking about (along with a &lt;a href="http://sqlfiddle.com/#!18/c0020d/4/0"&gt;SQL fiddle&lt;/a&gt; if you want to follow along):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;STUFF&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;author_title&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;authorid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorid&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="n"&gt;PATH&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Thankfully, PostgreSQL uses a more intuitive function, &lt;code&gt;string_agg&lt;/code&gt; to provide this functionality, so here's how you would &lt;a href="http://sqlfiddle.com/#!15/c065b/2/0"&gt;rewrite&lt;/a&gt; the above example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;string_agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;author_title&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;authorid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Additionally, the &lt;code&gt;string_agg&lt;/code&gt; function actually allows you to dispense with the subquery and use a JOIN/GROUP BY instead, so you could also &lt;a href="http://sqlfiddle.com/#!15/c065b/3/0"&gt;rewrite&lt;/a&gt; the example as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;string_agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;OUTER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;author_title&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorid&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;While database incompatibilities are always work to resolve, cases like this are nice, in that the changes at least feel like improvements. That said, I also found out that &lt;code&gt;string_agg&lt;/code&gt; is now &lt;a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15"&gt;available in SQL Server&lt;/a&gt;, as of SQL Server 2017. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;Obviously, I haven't covered all of the differences between Microsoft SQL Server and PostreSQL. The process and issues you encounter will depend highly on your application architecture. For example, we don't use common table expressions (CTEs), which apparently &lt;a href="https://www.brentozar.com/archive/2018/08/two-important-differences-between-sql-server-and-postgresql/"&gt;can cause performance issues&lt;/a&gt; in all but the latest (v12) versions of Postgres. Bottom line - you can do all the reading you want about incompatibilities, but there's no substitute for testing, testing, testing your application code.&lt;/p&gt;

&lt;p&gt;For a further discussion of this topic, I'd recommend this Reddit thread: &lt;a href="https://www.reddit.com/r/PostgreSQL/comments/ay7tw5/coming_from_sql_server/"&gt;Coming from SQL Server&lt;/a&gt;; it touches on some of the benefits of moving to Postgres as well, which I really don't have the space to explore here. If you've made a similar migration, or just have more familiarity with database engines, please share you insights in the comments!&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;The biggest issue that we encountered was actually resolved with the latest update to the app (&lt;a href="https://www.convert-in.com/mss2pgs_changes.htm"&gt;v4.5&lt;/a&gt;) - in earlier versions, when transferring tables with a primary key comprised of multiple columns, the order of the columns within the key/index was sometimes changed. I should also note that it's not a free tool. But, at $49 (with a limited, free trial), we found it well worth the time it saved. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;And yes, I know that a query-builder library or ORM would mitigate much of this, but it's still good to know. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;And if you're looking for a little more clarity, here's a fairly detailed Stack Overflow explanation: &lt;a href="https://stackoverflow.com/questions/31211506/how-stuff-and-for-xml-path-work-in-sql-server"&gt;How Stuff and 'For Xml Path' work in Sql Server&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>sql</category>
      <category>postgres</category>
      <category>database</category>
      <category>webdev</category>
    </item>
    <item>
      <title>TIL: Generating .xlsx Files with CFML - An Easy Way to Reduce File Size</title>
      <dc:creator>Matthew J. Clemente</dc:creator>
      <pubDate>Fri, 11 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/mjclemente/til-generating-xlsx-files-with-cfml-an-easy-way-to-reduce-file-size-joi</link>
      <guid>https://forem.com/mjclemente/til-generating-xlsx-files-with-cfml-an-easy-way-to-reduce-file-size-joi</guid>
      <description>&lt;p&gt;Just a quick note about generating XLSX (Excel) files with ColdFusion, which basically amounts to me regurgitating the documentation. It’s a small change in code, but the reduction in spreadsheet file size can be considerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Background
&lt;/h2&gt;

&lt;p&gt;I’ve been under the (mistaken) impression that when generating spreadsheet files with ColdFusion, my options were limited to XLS or CSV. I would generate the former using the built-in spreadsheet functions (&lt;code&gt;spreadsheetNew()&lt;/code&gt;) and the latter by manually assembling strings into a comma-delimited format.&lt;/p&gt;

&lt;p&gt;While I’m a big fan of the plaintext, interoperable nature of the CSV, some clients explicitly request Excel sheets - so they get their XLS files. These were always “good enough” for the basic reports they were requesting.&lt;/p&gt;

&lt;p&gt;Nevertheless, it bothered me that I was using an outdated format for Excel files. My core frustration was practical - XLS files are so much larger than their XLSX counterparts - but this was never enough of a bother to warrant further investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Consequently, I was happily surprised to discover that &lt;code&gt;spreadsheetNew()&lt;/code&gt; provides a second boolean argument, &lt;code&gt;xmlFormat&lt;/code&gt;, which indicates if the spreadsheet should be created in the XLSX format - it’s right there in the &lt;a href="https://cfdocs.org/spreadsheetnew"&gt;docs&lt;/a&gt; - somehow I’ve just always missed it. Here’s the complete method signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;spreadsheetNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sheetname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;xmlFormat&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;xmlFormat&lt;/code&gt; option defaults to &lt;code&gt;false&lt;/code&gt;, generating an XLS file - and that’s how I’d been using it for all these years. Sigh.&lt;/p&gt;

&lt;p&gt;Here’s an example generating a spreadsheet, first using the default XLS approach, and then setting &lt;code&gt;xmlFormat&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, in order to generate an XLSX file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// legacy approach&lt;/span&gt;
&lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expandPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test.xls&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spreadsheetNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;XLS Test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;spreadsheetAddRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;spreadsheetWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// XLSX approach&lt;/span&gt;
&lt;span class="nx"&gt;xlsxFilePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expandPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test.xlsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;xlsxSheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spreadsheetNew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;XLSX Test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;spreadsheetAddRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;xlsxSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;spreadsheetWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;xlsxSheet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xlsxFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to save it as an XLSX file, the only difference was setting the &lt;code&gt;xmlFormat&lt;/code&gt; to true (and updating the file extension).&lt;/p&gt;

&lt;p&gt;To take a look at the benefit of this change, let’s compare file sizes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sheetSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFileInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;xlsxSheetSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getFileInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;xlsxFilePath&lt;/span&gt; &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;bytesSaved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sheetSize&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;xlsxSheetSize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;change&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;bytesSaved&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;sheetSize&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File size reduced by #round( change )#% &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// File size reduced by 54%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sure enough, &lt;strong&gt;the resulting XLSX file is less than half the size of the identical XLS one&lt;/strong&gt;. That’s a pretty big win for one very small change in code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Note for Lucee CFML Users
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-by-category/spreadsheet-functions.html"&gt;Spreadsheet Functions&lt;/a&gt; provided by Adobe ColdFusion are not natively supported in Lucee. Fortunately, it’s not too much work to add them, as I’ve previously blogged: &lt;a href="///2018/11/05/using-excel-spreadsheet-functions-with-lucee-5-on-docker.html"&gt;How Not To Use Spreadsheet Functions in Lucee&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Read that post for a more detailed exploration of using spreadsheet functions in Lucee, but the TLDR; is that there are two basic approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the &lt;a href="https://forgebox.io/view/037A27FF-0B80-4CBA-B954BEBD790B460E"&gt;&lt;em&gt;cfspreadsheet&lt;/em&gt;&lt;/a&gt; extension. This can be done programmatically or via the Lucee admin.&lt;/li&gt;
&lt;li&gt;Take an altogether different approach and use Julian Halliwell’s &lt;a href="https://github.com/cfsimplicity/lucee-spreadsheet"&gt;cfsimplicity/lucee-spreadsheet&lt;/a&gt; standalone library for spreadsheet manipulation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy spreadsheeting!&lt;/p&gt;

</description>
      <category>cfml</category>
      <category>coldfusion</category>
      <category>excel</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is the Modulus Operator? A Short Guide with Practical Use Cases</title>
      <dc:creator>Matthew J. Clemente</dc:creator>
      <pubDate>Fri, 12 Jul 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/mjclemente/what-is-the-modulus-operator-a-short-guide-with-practical-use-cases-5elj</link>
      <guid>https://forem.com/mjclemente/what-is-the-modulus-operator-a-short-guide-with-practical-use-cases-5elj</guid>
      <description>&lt;p&gt;Addition, subtraction, multiplication, and division. These are the four mathematical operations I was taught during my childhood education, and their operators, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, are very familiar. I was not taught &lt;code&gt;%&lt;/code&gt;, the &lt;strong&gt;&lt;em&gt;modulus operator&lt;/em&gt;&lt;/strong&gt; , which I recently discovered can be quite useful and interesting in its own right.&lt;/p&gt;

&lt;p&gt;The modulus operator, written in most programming languages as &lt;code&gt;%&lt;/code&gt; or &lt;code&gt;mod&lt;/code&gt;, performs what is known as the &lt;a href="https://en.wikipedia.org/wiki/Modulo_operation"&gt;modulo operation&lt;/a&gt;. You next response, understandably, might be, “That doesn’t clarify anything,” so let’s take a closer look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
How It Works

&lt;ul&gt;
&lt;li&gt;The Modulo Operation Expressed As a Formula&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Use Cases for the Modulo Operation

&lt;ul&gt;
&lt;li&gt;Even / Odd and Alternating&lt;/li&gt;
&lt;li&gt;Restrict Number to Range&lt;/li&gt;
&lt;li&gt;Rotating Through Limited Options (Circular Array)&lt;/li&gt;
&lt;li&gt;Every Nth Operations in a Loop&lt;/li&gt;
&lt;li&gt;Converting Units of Measure&lt;/li&gt;
&lt;li&gt;Miscellany&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Some Helpful Reading&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The modulus operator - or more precisely, the modulo operation - is a way to determine the &lt;em&gt;remainder&lt;/em&gt; of a division operation. Instead of returning the result of the division, the modulo operation returns the whole number remainder.&lt;/p&gt;

&lt;p&gt;Some examples may help illustrate this, as it’s not necessarily intuitive the first time you encounter it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="c1"&gt;// 5 divided by 1 equals 5, with a remainder of 0&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// 5 divided by 2 equals 2, with a remainder of 1&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="c1"&gt;// 5 divided by 3 equals 1, with a remainder of 2&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// 5 divided by 4 equals 1, with a remainder of 1&lt;/span&gt;

&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="c1"&gt;// 5 divided by 5 equals 1, with a remainder of 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It may be helpful to think back to your early math lessons, before you learned fractions and decimals. Mathematics with whole numbers behaves differently - when dividing numbers that aren’t even multiples, there’s always some amount left over. That remainder is what the modulo operation returns.&lt;/p&gt;

&lt;p&gt;If this seems strange, boring, or not particularly useful, bear with me a bit longer - or just skip ahead to the use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Modulo Operation Expressed As a Formula
&lt;/h3&gt;

&lt;p&gt;As one final means of explication, for those more mathematically inclined, here’s a formula that describes the modulo operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By substituting values, we can see how the modulo operation works in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="c1"&gt;// a = 100, n = 7&lt;/span&gt;
&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you don’t find the formula helpful, don’t worry - I didn’t either at first. Some people find this abstract representation helps deepen or clarify their understanding of the operation, but you don’t need to know it.&lt;/p&gt;

&lt;p&gt;A final note here - if you’re wondering how the modulo operation functions with negative numbers or decimals, that’s a bit outside the scope of this article. For our purposes here, we’ll only be dealing with positive integers.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Okay, enough with the math for now. While returning the remainder is what the modulo operation does, that’s not its only use; indeed we’ll see that it’s handy for a good deal more - but that was a necessary starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases for the Modulo Operation
&lt;/h2&gt;

&lt;p&gt;When I first encountered the it, the modulus operator seemed little more than a bit of mathematical trivia. I found it far more interesting as I started to learn its practical utility. I’ll discuss a few applications here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Even / Odd and Alternating
&lt;/h3&gt;

&lt;p&gt;One of the most basic use cases for the modulus operator is to determine if a number is even or odd.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; This is possible because &lt;code&gt;x % 2&lt;/code&gt; always returns either 0 or 1. Even numbers, because they are evenly divisible by 2, always return 0, while odd numbers always return the remainder of 1. Here’s what I mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// 01010101010&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, what’s the use case? This technique is often used to alternate values within a loop. The first time I used the modulus operator, it was to manually zebra-stripe table rows, with the row’s background color based on whether it was even or odd. In a similar vein, I’ve used &lt;code&gt;%&lt;/code&gt; to distribute the results of a web-form to two recipients, on an every-other basis; in pseudocode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;incrementalId&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// send to one&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="c1"&gt;// send to the other&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It’s a convenient hack any time you have a group or stream of records, widgets, leads, etc., that you want to handle on an alternating basis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restrict Number to Range
&lt;/h3&gt;

&lt;p&gt;When you’re using the modulus operator for even/odd alternation, you’re actually taking advantage of one of its more helpful properties, though you might not realize it. Here’s the property: &lt;strong&gt;the range of &lt;code&gt;x % n&lt;/code&gt; is between 0 and &lt;code&gt;n - 1&lt;/code&gt;&lt;/strong&gt; , which is to say that &lt;em&gt;the modulo operation will not return more than the divisor&lt;/em&gt;.&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Again, examples might help clarify this idea; in each instance here, the divisor is 5, so results will range from 0 - 4.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="c1"&gt;// 1 cannot be divided by 5, so the remainder is 1&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="c1"&gt;// 4 cannot be divided by 5, so the remainder is 4&lt;/span&gt;

&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="c1"&gt;// 7 divided by 5 equals 1, with a remainder of 2&lt;/span&gt;

&lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="c1"&gt;// 25 divided by 5 equals 5, with a remainder of 0&lt;/span&gt;

&lt;span class="mi"&gt;218&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;// 218 divided by 5 equals 43, with a remainder of 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, regardless of the initial number, the modulus (divisor) limits the range of the result.&lt;/p&gt;

&lt;p&gt;On its own, this property doesn’t seem useful, but when applied within a larger set, it can be used to create a pattern of circular repetition. Here’s an example of incrementing numbers with a modulus of 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// cycle back to 0&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;// cycle back to 0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice how the result of the modulo operation keeps repeating 0-1-2; the values wrap around. One way to describe these results is as a &lt;a href="https://www.quora.com/What-is-a-circular-array-and-how-does-it-work"&gt;circular array&lt;/a&gt;, like numbers on the face of a clock. Let’s take a closer look at a practical application of this property.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rotating Through Limited Options (Circular Array)
&lt;/h4&gt;

&lt;p&gt;In a situation with a limited number of options - weekdays, primary colors, company projects, clients, etc. - we can use the modulo operation to walk through them in a repeating loop. That is, we can treat the array of options as a circle that we just keep cycling through.&lt;/p&gt;

&lt;p&gt;Here’s a somewhat contrived example to illustrate this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// array of options that we want to cycle through&lt;/span&gt;
&lt;span class="nx"&gt;weekdays&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Mon'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Tue'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Wed'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Thu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Fri'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// option count provides modulus (divisor)&lt;/span&gt;
&lt;span class="nx"&gt;dayCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;weekdays.len&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;employeeCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// loop over employees while rotating through days&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;employeeCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// employee number mod option count&lt;/span&gt;
  &lt;span class="nx"&gt;dayIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;dayCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// adjust because CFML array indexed from 1&lt;/span&gt;
  &lt;span class="nx"&gt;dayIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// use result to cycle through weekday array positions&lt;/span&gt;
  &lt;span class="nx"&gt;weekday&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;weekdays&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dayIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="nf"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s2"&gt;"Scheduling employee on #weekday#. "&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we step through a list of employees, we assign each to a weekday. Once we’ve scheduled five employees, we reach Friday. With no more options, assignment then loops back to Monday and continues the cycle until all employees are scheduled. This is possible because, as shown in the previous section, the modulus of 5 (the number of weekdays) returns a circular array of 0-4, that we can map to options in our weekday array. Seeing and understanding this was a major revelation for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Every Nth Operations in a Loop
&lt;/h3&gt;

&lt;p&gt;Another application of the modulo operation is determining an interval within a loop; that is, calculating occurrences such as “every fourth time,” “once every ten,” etc.&lt;/p&gt;

&lt;p&gt;The principle, in this case, is that if &lt;code&gt;n&lt;/code&gt; is an even multiple of &lt;code&gt;x&lt;/code&gt;, then &lt;code&gt;x % n = 0&lt;/code&gt;. Consequently, &lt;code&gt;x % 4&lt;/code&gt; will return 0 every fourth time; &lt;code&gt;x % 10&lt;/code&gt; will return 0 every tenth time, and so on. One practical use of this is providing feedback within long or long running loops:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// given a list of widgets, files, people, etc.&lt;/span&gt;
&lt;span class="nx"&gt;longList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="nx"&gt;feedbackInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// to be used as the modulus&lt;/span&gt;

&lt;span class="c1"&gt;// loop over the list to process each item&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;longList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// perform some operation&lt;/span&gt;

  &lt;span class="c1"&gt;// mod operation gives feedback once every hundred loops&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;feedbackInterval&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;percentCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;longList&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s2"&gt;"#percentCompleted# percent complete. "&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You could use a similar principle to trigger client/user interaction based on time or engagement. For example, send a promo every 90 days, or offer a feedback survey every 50 logins.&lt;/p&gt;

&lt;p&gt;Keep in mind that time is also, in effect, a long running loop. Every hour has 60 minutes, repeating on a cycle. If you wanted to schedule a task to run four times an hour, you could achieve this using the modulo operation - just run it when &lt;code&gt;minutes % 4 == 0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Converting Units of Measure
&lt;/h3&gt;

&lt;p&gt;Converting units of measure is common example of the modulo operation’s practical utility. The general use case is when you want to convert a smaller unit, such as minutes or inches/centimeters, to a larger unit, like hours or miles/kilometers; in these situations, decimals or fractions aren’t always helpful.&lt;/p&gt;

&lt;p&gt;For example, if we wanted to know the number of hours in 349 minutes, having the result expressed as &lt;em&gt;5 hours 49 minutes&lt;/em&gt; may be more helpful than &lt;em&gt;5.8167 hours&lt;/em&gt;. Here’s a quick-and-dirty take at what that type of conversion function might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cfscript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;minutesToHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"#hours# hours #minutes# minutes"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;writeOutput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;minutesToHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;349&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Standard division (rounded down to the nearest integer) determines the number of hours, while the modulo operation is used to keep track of the remaining minutes. Whether you’re dealing with time, distance, pressure, energy, or data storage, you can use this general approach for unit conversion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Miscellany
&lt;/h3&gt;

&lt;p&gt;You might think that I’ve exhausted all the situations in which you might use the modulus operator, but you’d be wrong. Here are a handful more that I found on Stack Overflow, Quora, and the internet at large:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/42234911/5361034"&gt;Reversing a number&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/37449343/5361034"&gt;Converting linear data to a matrix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/51461187/5361034"&gt;Determining if arrays are rotated versions of each other&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quora.com/What-would-be-a-practical-use-of-modulus-operator/answer/Graham-Cox-18"&gt;Pagination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quora.com/In-which-cases-is-the-Modulo-operation-used-in-programming/answer/Mesam-Zahid"&gt;Leap year calculation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, once you’re comfortable with the modulo operation, you shouldn’t have any trouble solving the &lt;a href="https://blog.codinghorror.com/why-cant-programmers-program/"&gt;FizzBuzz Question&lt;/a&gt; discussed here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Helpful Reading
&lt;/h2&gt;

&lt;p&gt;Credit where it’s due - I learned a lot from these posts while I was researching and writing this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/modulo-java"&gt;The Modulo Operator in Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.tutsplus.com/tutorials/how-to-use-the-modulo-operator-in-php--cms-32393"&gt;How to Use the Modulo Operator in PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://betterexplained.com/articles/fun-with-modular-arithmetic/"&gt;Fun With Modular Arithmetic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/2609315/recognizing-when-to-use-the-modulus-operator"&gt;Recognizing when to use the modulus operator&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.quora.com/In-which-cases-is-the-Modulo-operation-used-in-programming"&gt;In which cases is the Modulo (%) operation used in programming?&lt;/a&gt; (Quora)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you know it; go use it! If you’ve got other uses or examples that you’d like to share, I’d love to hear them.&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Programming languages vary in their approach to supporting and handing &lt;em&gt;floating point&lt;/em&gt; (decimal) modulo operations, as well as negative numbers. Working with these is outside the scope of this article, my concern, and most practical use cases that I’ve read about or encountered. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Lest I get called out in the comments, I should note that &lt;em&gt;bitwise operators&lt;/em&gt; offer another, even more efficient approach to determining if a number is even or odd, but that’s another topic for another day. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;I should note that the divisor in a modulo operation is also called the modulus. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>math</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Install and Manage Multiple Versions of Java (hint: jabba and jEnv)</title>
      <dc:creator>Matthew J. Clemente</dc:creator>
      <pubDate>Fri, 31 May 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/mjclemente/how-to-install-and-manage-multiple-versions-of-java-hint-jabba-and-jenv-2ho0</link>
      <guid>https://forem.com/mjclemente/how-to-install-and-manage-multiple-versions-of-java-hint-jabba-and-jenv-2ho0</guid>
      <description>&lt;p&gt;One of my goals for the coming months is to improve my proficiency with Java; that is, to put some real knowledge behind my current patchwork understanding, pieced together over the years via trial-and-error.&lt;/p&gt;

&lt;p&gt;Before diving into Java training courses on Udemy, Youtube, etc, I wanted to make sure that I had a way to use different versions of the JDK on my machine. This was due, at least in part, to the &lt;a href="https://blog.jetbrains.com/idea/2018/09/using-java-11-in-production-important-things-to-know/"&gt;changes Oracle made to their Java licensing&lt;/a&gt; and release cycle. There are now a variety of Java versions and vendor distributions available, and I wanted to find a way to easily switch between different versions of the JDK without needing to actually update my system’s version of Java or manually set &lt;code&gt;JAVA_HOME&lt;/code&gt; each time.&lt;/p&gt;

&lt;p&gt;Basically, the same way I can use different versions of Ruby, Node, and CFML, thanks to &lt;a href="https://github.com/rbenv/rbenv"&gt;rbenv&lt;/a&gt;, &lt;a href="http://nvm.sh"&gt;nvm&lt;/a&gt;, and &lt;a href="https://commandbox.ortusbooks.com/"&gt;CommandBox&lt;/a&gt;, respectively, it seemed I should be able to easily use different versions of Java, and not be tied to my system’s default version. So, like a good developer I did some Googling and stumbled across &lt;a href="https://stackoverflow.com/questions/52524112/how-do-i-install-java-on-mac-osx-allowing-version-switching"&gt;this helpful StackOverflow post&lt;/a&gt;, and ultimately settled on using both &lt;strong&gt;&lt;a href="https://github.com/shyiko/jabba"&gt;jabba&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="http://www.jenv.be/"&gt;jEnv&lt;/a&gt;&lt;/strong&gt; - the former to install versions and the latter to configure them on a per-directory basis. Here’s how it works:&lt;/p&gt;

&lt;h2&gt;
  
  
  jabba to install different JDK versions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;jabba&lt;/strong&gt; is a cross-platform Java Version Manager. I found that it really excels at streamlining the process of installing different versions of Java. You can find the installation instructions along with some very helpful documenation on the &lt;a href="https://github.com/shyiko/jabba#installation"&gt;jabba Github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once installed, you can list available versions of the JDK via &lt;code&gt;jabba ls-remote&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jabba ls-remote
1.12.0
1.12.0-1
1.6.65
adopt@1.12.33-0
...
zulu@1.7.95
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Right now, there are over 100 results, literally from A-to-Z (that is, Adopt OpenJDK to Zulu OpenJDK).&lt;/p&gt;

&lt;p&gt;To install a particular version, such as Corretto, you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jabba &lt;span class="nb"&gt;install &lt;/span&gt;amazon-corretto@1.11.0-3.7.1
&lt;span class="c"&gt;#installed to ~/.jabba/jdk/amazon-corretto@1.11.0-3.7.1/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On Linux/Mac, the JDK version is downloaded/installed to &lt;code&gt;~/.jabba&lt;/code&gt;. Remember this, because you’ll need to know where these are when using jEnv.&lt;/p&gt;

&lt;p&gt;Versions of the JDK not readily available, such as Oracle’s 11.0.3, which now requires an account to download, can be manually installed via a URL or file location. Here’s how I installed Oracle’s, after downloading it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jabba &lt;span class="nb"&gt;install &lt;/span&gt;oracle@1.11.0-3&lt;span class="o"&gt;=&lt;/span&gt;tgz+file:///Users/MYUSER/Downloads/jdk-11.0.3_osx-x64_bin.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Using jabba with Intellij on Mac
&lt;/h3&gt;

&lt;p&gt;When I tried to add the jabba-installed JDKs to Intellij as SDKs, I ran into a small issue - because they’re located in a hidden folder, they’re not readily selectable via the file browser. Unsurprisingly, I wasn’t the first person to have this issue, &lt;a href="https://www.reddit.com/r/java/comments/a1rfvx/jabba_intellij_on_mac/"&gt;a Reddit post in r/java&lt;/a&gt; pointed me to two answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Within Intellij, when browsing for the JDKs in &lt;code&gt;~/.jabba&lt;/code&gt;, you can type &lt;strong&gt;Command-Shift-Period&lt;/strong&gt; (⌘+⇧+.), which should reveal the hidden files/folders, making them possible to select. Apparently this doesn’t work in all Intellij versions, so there’s another option.&lt;/li&gt;
&lt;li&gt;In regular Finder, navigate to the folder &lt;code&gt;~/.jabba/jdk/JDK@VERSION/Contents/Home&lt;/code&gt; - you should then be able to drag this into the Intellij Finder window, in order to use/select it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  jEnv for per-directory JDK assignment
&lt;/h2&gt;

&lt;p&gt;With installing JDK versions sorted out, my next goal was to make managing and using them straightforward. A primary concern was the ability to assign a JDK version to a project/directory and then not have to think about it again. For me, &lt;strong&gt;jEnv&lt;/strong&gt; nailed it.&lt;/p&gt;

&lt;p&gt;So, what is &lt;a href="http://www.jenv.be/"&gt;jEnv&lt;/a&gt;? To pull a quote from its website:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;jEnv is a command line tool to help you forget how to set the JAVA_HOME environment variable&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, while it doesn’t install different versions of Java, jEnv makes it much easier to manage the versions already on your machine (like those installed by jabba). Just a note that, unfortunately for Windows users, it is not currently cross-platform.&lt;/p&gt;

&lt;p&gt;After installing jEnv, I needed to add the JDKs from jabba (and from my machine). This is done using the &lt;code&gt;jenv add&lt;/code&gt; command and providing path to the JDK version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add a jabba JDK&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;jenv add /Users/MYUSER/.jabba/jdk/oracle@1.11.0-3/Contents/Home/
oracle64-11.0.3 added
11.0.3 added
11.0 added

&lt;span class="c"&gt;# Add the system JDK&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/
oracle64-1.8.0.181 added
1.8.0.181 added
1.8 added

&lt;span class="c"&gt;# List JDK versions&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;jenv versions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now - and this is what I was most excited about - I can set a Java version for a directory and then I don’t need to think about it again. Here’s how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;java &lt;span class="nt"&gt;-version&lt;/span&gt;
java version &lt;span class="s2"&gt;"1.8.0_181"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;jenv &lt;span class="nb"&gt;local &lt;/span&gt;oracle64-11.0.3

&lt;span class="nv"&gt;$ &lt;/span&gt;java &lt;span class="nt"&gt;-version&lt;/span&gt;
java version &lt;span class="s2"&gt;"11.0.3"&lt;/span&gt; 2019-04-16 LTS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This works by adding a &lt;code&gt;.java-version&lt;/code&gt; file to the directory, which contains the specified version. jEnv automatically ensures that this version is used within the folder (and subfolders). Set-it-and-forget-it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it up
&lt;/h2&gt;

&lt;p&gt;I was ultimately very happy with this solution - it enables me to do some initial Java configuration for a project and then just forget about it and get back to the code. That said, I’m no Java guru. If you’ve got a better approach or see problems with this one, please let me know.&lt;/p&gt;

</description>
      <category>java</category>
      <category>jabba</category>
      <category>jenv</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
