<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://rohankthakur.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://rohankthakur.github.io//" rel="alternate" type="text/html" /><updated>2025-11-19T22:56:53+05:30</updated><id>https://rohankthakur.github.io//feed.xml</id><title type="html">Rohan Kumar Thakur</title><subtitle>My portfolio website showcasing photography, art,  technical projects, and miscellaneous content.</subtitle><entry><title type="html">The Intersection of Technical and Creative Work</title><link href="https://rohankthakur.github.io//misc/2024/09/15/creative-technical-intersection/" rel="alternate" type="text/html" title="The Intersection of Technical and Creative Work" /><published>2024-09-15T00:00:00+05:30</published><updated>2024-09-15T00:00:00+05:30</updated><id>https://rohankthakur.github.io//misc/2024/09/15/creative-technical-intersection</id><content type="html" xml:base="https://rohankthakur.github.io//misc/2024/09/15/creative-technical-intersection/"><![CDATA[<p>Over years of working across both technical and creative domains, I’ve noticed fascinating parallels in problem-solving approaches, attention to detail, and the iterative nature of both code and art. This post explores some of those connections and how skills from one area often enhance the other.</p>

<h2 id="common-problem-solving-patterns">Common Problem-Solving Patterns</h2>

<h3 id="breaking-down-complex-problems">Breaking Down Complex Problems</h3>
<p><strong>In Programming</strong>: Large applications are broken into modules, functions, and components that can be developed and tested independently.</p>

<p><strong>In Art</strong>: Complex drawings start with basic shapes and proportions before adding details. Paintings are built up in layers, each serving a specific purpose.</p>

<p><strong>In Photography</strong>: A successful image considers composition, lighting, exposure, and post-processing as separate but interconnected elements.</p>

<p>The pattern is consistent: start with the big picture, identify the main components, then refine iteratively.</p>

<h3 id="debugging-and-problem-solving">Debugging and Problem-Solving</h3>
<p><strong>In Code</strong>: When a program doesn’t work, you isolate variables, test assumptions, and work systematically through possibilities.</p>

<p><strong>In Drawing</strong>: When a portrait looks “off,” you check proportions, value relationships, and edge quality systematically.</p>

<p><strong>In Photography</strong>: When an image isn’t working, you analyze exposure, composition, focus, and timing methodically.</p>

<p>Both disciplines require:</p>
<ul>
  <li>Systematic analysis</li>
  <li>Testing hypotheses</li>
  <li>Patience with iterative improvement</li>
  <li>Comfort with failure as a learning tool</li>
</ul>

<h2 id="technical-skills-enhancing-creative-work">Technical Skills Enhancing Creative Work</h2>

<h3 id="automation-and-batch-processing">Automation and Batch Processing</h3>
<p>Programming concepts translate directly to creative workflows:</p>
<ul>
  <li><strong>Photoshop Actions</strong>: Essentially visual programming for repetitive image processing</li>
  <li><strong>Lightroom Presets</strong>: Reusable “functions” for consistent photo processing</li>
  <li><strong>File Organization</strong>: Database principles applied to managing thousands of images</li>
</ul>

<h3 id="version-control-thinking">Version Control Thinking</h3>
<p>Git workflow concepts apply to creative projects:</p>
<ul>
  <li><strong>Branching</strong>: Saving multiple versions before major changes</li>
  <li><strong>Commits</strong>: Documenting stages of development with notes</li>
  <li><strong>Rollback</strong>: Returning to earlier versions when experiments fail</li>
  <li><strong>Merging</strong>: Combining successful elements from different attempts</li>
</ul>

<h3 id="documentation-habits">Documentation Habits</h3>
<p>Technical writing skills improve creative process documentation:</p>
<ul>
  <li>Clear project notes for future reference</li>
  <li>Step-by-step technique documentation</li>
  <li>Equipment and settings recording</li>
  <li>Process photography for complex projects</li>
</ul>

<h2 id="creative-skills-enhancing-technical-work">Creative Skills Enhancing Technical Work</h2>

<h3 id="visual-design-principles">Visual Design Principles</h3>
<p>Art training improves technical communication:</p>
<ul>
  <li><strong>Typography</strong>: Understanding hierarchy and readability</li>
  <li><strong>Layout</strong>: Applying composition principles to user interfaces</li>
  <li><strong>Color Theory</strong>: Using color meaningfully in data visualization</li>
  <li><strong>Visual Hierarchy</strong>: Directing attention in technical documentation</li>
</ul>

<h3 id="iterative-refinement">Iterative Refinement</h3>
<p>Artistic process thinking improves code quality:</p>
<ul>
  <li><strong>Multiple drafts</strong>: Not settling for the first working solution</li>
  <li><strong>Critique process</strong>: Regularly reviewing and improving work</li>
  <li><strong>Aesthetic judgment</strong>: Recognizing when something “feels right”</li>
  <li><strong>Patience with process</strong>: Understanding that good work takes time</li>
</ul>

<h3 id="attention-to-detail">Attention to Detail</h3>
<p>Fine art training develops observational skills valuable in debugging:</p>
<ul>
  <li><strong>Seeing subtle differences</strong>: Noticing small variations that indicate problems</li>
  <li><strong>Pattern recognition</strong>: Identifying recurring issues quickly</li>
  <li><strong>Systematic observation</strong>: Looking at problems from multiple angles</li>
</ul>

<h2 id="the-creative-technical-portfolio-website">The Creative-Technical Portfolio Website</h2>

<p>This very website exemplifies the intersection of technical and creative skills:</p>

<p><strong>Technical Requirements</strong>:</p>
<ul>
  <li>Clean, semantic HTML structure</li>
  <li>Responsive CSS design system</li>
  <li>Performance optimization</li>
  <li>SEO and accessibility compliance</li>
  <li>Version control and deployment</li>
</ul>

<p><strong>Creative Considerations</strong>:</p>
<ul>
  <li>Visual hierarchy and typography</li>
  <li>Color palette and brand consistency</li>
  <li>User experience and navigation flow</li>
  <li>Image presentation and gallery design</li>
  <li>Content organization and storytelling</li>
</ul>

<p>The project required both technical problem-solving (Ruby dependencies, build processes) and creative decision-making (visual design, content structure).</p>

<h2 id="lessons-for-integrated-practice">Lessons for Integrated Practice</h2>

<h3 id="embrace-both-sides">Embrace Both Sides</h3>
<p>Rather than keeping technical and creative work separate, actively look for connections:</p>
<ul>
  <li>Use technical tools to enhance creative work</li>
  <li>Apply creative thinking to technical challenges</li>
  <li>Document processes from both perspectives</li>
  <li>Share knowledge across domains</li>
</ul>

<h3 id="process-over-tools">Process Over Tools</h3>
<p>Both technical and creative work benefit from:</p>
<ul>
  <li>Clear processes that can be repeated and refined</li>
  <li>Regular practice and skill development</li>
  <li>Learning from failure and iteration</li>
  <li>Building on fundamentals before advanced techniques</li>
</ul>

<h3 id="community-and-learning">Community and Learning</h3>
<p>Both communities value:</p>
<ul>
  <li>Sharing knowledge and techniques</li>
  <li>Constructive critique and feedback</li>
  <li>Continuous learning and adaptation</li>
  <li>Recognition that mastery takes time</li>
</ul>

<h2 id="future-directions">Future Directions</h2>

<p>As technology and creativity continue to converge, new opportunities emerge:</p>
<ul>
  <li><strong>AI-assisted creative tools</strong> requiring both technical understanding and artistic judgment</li>
  <li><strong>Interactive installations</strong> combining programming with visual art</li>
  <li><strong>Data visualization</strong> as a fusion of analysis and aesthetic presentation</li>
  <li><strong>Generative art</strong> using code as a creative medium</li>
</ul>

<p>The boundary between technical and creative work continues to blur, making skills in both areas increasingly valuable and complementary.</p>

<p><em>What connections have you found between your technical and creative work? I’d love to hear about your experiences at the intersection of these disciplines.</em></p>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="misc" /><category term="creativity" /><category term="technology" /><category term="process" /><category term="reflection" /><summary type="html"><![CDATA[Reflections on how technical problem-solving skills enhance creative work, and vice versa, based on experiences across photography, art, and software development.]]></summary></entry><entry><title type="html">More the merrier! When you get the family together!</title><link href="https://rohankthakur.github.io//photography/2024/04/20/more-merrier/" rel="alternate" type="text/html" title="More the merrier! When you get the family together!" /><published>2024-04-20T00:00:00+05:30</published><updated>2024-04-20T00:00:00+05:30</updated><id>https://rohankthakur.github.io//photography/2024/04/20/more-merrier</id><content type="html" xml:base="https://rohankthakur.github.io//photography/2024/04/20/more-merrier/"><![CDATA[<h2 id="the-scene">The Scene</h2>

<p>This is a small compilation of images where it’s not a single bird alone, but the family together - either a couple going about their day, and at times even a full family, simply relaxing together or foraging for a meal.</p>

<h2 id="the-equipment">The Equipment</h2>

<p>Assorted - as all of them were not captured together. A combination of zooms and an 800mm prime. Images have seen slight adjustment mostly for exposure and a bit of a tone curve … I try to keep it simple and light handed in this department.</p>

<h2 id="the-waiting-game">The Waiting Game</h2>

<p>Not much of a single waiting game here … but the process of building a collection of images following a theme over a period of time. This page will see updates as the collection grows larger.</p>

<h2 id="the-reward">The Reward</h2>

<div class="image-gallery">
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-1.jpg" alt="Red-whiskered Bulbul (Pycnonotus jocosus)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-1.jpg', 'Red-whiskered Bulbul (Pycnonotus jocosus)')" loading="lazy" />
        
          <div class="gallery-caption">Red-whiskered Bulbul (Pycnonotus jocosus)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-2.jpg" alt="Common Rosefinch (Carpodacus erythrinus)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-2.jpg', 'Common Rosefinch (Carpodacus erythrinus)')" loading="lazy" />
        
          <div class="gallery-caption">Common Rosefinch (Carpodacus erythrinus)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-3.jpg" alt="Indian Peafowl (Pavo cristatus)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-3.jpg', 'Indian Peafowl (Pavo cristatus)')" loading="lazy" />
        
          <div class="gallery-caption">Indian Peafowl (Pavo cristatus)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-4.jpg" alt="Red-vented Bulbul (Pycnonotus cafer)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-4.jpg', 'Red-vented Bulbul (Pycnonotus cafer)')" loading="lazy" />
        
          <div class="gallery-caption">Red-vented Bulbul (Pycnonotus cafer)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-5.jpg" alt="Black Kite (Milvus migrans)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-5.jpg', 'Black Kite (Milvus migrans)')" loading="lazy" />
        
          <div class="gallery-caption">Black Kite (Milvus migrans)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-6.jpg" alt="Plum-headed Parakeet (Psittacula cyanocephala)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-6.jpg', 'Plum-headed Parakeet (Psittacula cyanocephala)')" loading="lazy" />
        
          <div class="gallery-caption">Plum-headed Parakeet (Psittacula cyanocephala)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-7.jpg" alt="House Crow (Corvus splendens)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-7.jpg', 'House Crow (Corvus splendens)')" loading="lazy" />
        
          <div class="gallery-caption">House Crow (Corvus splendens)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-8.jpg" alt="Red-vented Bulbul (Pycnonotus cafer)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-8.jpg', 'Red-vented Bulbul (Pycnonotus cafer)')" loading="lazy" />
        
          <div class="gallery-caption">Red-vented Bulbul (Pycnonotus cafer)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-9.jpg" alt="Common Myna (Acridotheres tristis)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-9.jpg', 'Common Myna (Acridotheres tristis)')" loading="lazy" />
        
          <div class="gallery-caption">Common Myna (Acridotheres tristis)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-10.jpg" alt="Red-naped Ibis (Pseudibis papillosa)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-10.jpg', 'Red-naped Ibis (Pseudibis papillosa)')" loading="lazy" />
        
          <div class="gallery-caption">Red-naped Ibis (Pseudibis papillosa)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-11.jpg" alt="Spotted Dove (Stigmatopelia chinensis)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-11.jpg', 'Spotted Dove (Stigmatopelia chinensis)')" loading="lazy" />
        
          <div class="gallery-caption">Spotted Dove (Stigmatopelia chinensis)</div>
        
      
    </div>
  
    <div class="gallery-item">
      
        <!-- Object format with url and caption -->
        <img src="/assets/images/photography/birds/in-pairs/in-pairs-12.jpg" alt="Rose-ringed Parakeet (Psittacula krameri)" onclick="openLightbox('/assets/images/photography/birds/in-pairs/in-pairs-12.jpg', 'Rose-ringed Parakeet (Psittacula krameri)')" loading="lazy" />
        
          <div class="gallery-caption">Rose-ringed Parakeet (Psittacula krameri)</div>
        
      
    </div>
  
</div>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="photography" /><category term="birds" /><category term="wildlife" /><category term="photography-tips" /><summary type="html"><![CDATA[Many times you find couples and families chilling out together.]]></summary></entry><entry><title type="html">A hoopoe on a roll! Breakfast time!</title><link href="https://rohankthakur.github.io//photography/2024/04/16/hoopoe-on-a-roll/" rel="alternate" type="text/html" title="A hoopoe on a roll! Breakfast time!" /><published>2024-04-16T00:00:00+05:30</published><updated>2024-04-16T00:00:00+05:30</updated><id>https://rohankthakur.github.io//photography/2024/04/16/hoopoe-on-a-roll</id><content type="html" xml:base="https://rohankthakur.github.io//photography/2024/04/16/hoopoe-on-a-roll/"><![CDATA[<h2 id="the-scene">The Scene</h2>

<p>This is from an early morning walk, looking for birds and some birdy action.</p>

<p>At a local park, I spot this Common Hoopoe (<em>Upupa epops</em>) which seemed pretty hungry and was moving around rapidly, checking the grassy lawn for something to eat.</p>

<h2 id="the-equipment">The Equipment</h2>

<p>A Nikon Z-mount mirrorless body with an 800mm lens, on a shoulder strap - handheld.</p>

<h2 id="the-waiting-game">The Waiting Game</h2>

<p>As this fellow went about, I could anticipate that there were some interesting images to make.</p>

<p>I got down low, and started shooting a few bursts to try and capture some nice context-filled action images.</p>

<p>See a section of the series shot below …</p>

<div class="post-image 2">
  <img src="/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-series.jpg" alt="" onclick="openLightbox('/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-series.jpg', 'A sample from the series')" loading="lazy" />
  
  <div class="image-caption">A sample from the series</div>
  
</div>

<h2 id="the-reward">The Reward</h2>

<p>Eventually, I did get a bunch of interesting images, as the hoope successfully pulled out a juicy worm and happily swallowed it up!</p>

<p>Here are the three I have chosen to depict the action - predator over prey … hunger satiated … nature! These have undergone just some basic adjustments, like exposure and a bit of a tone curve. Further processing should help obtain even better results … but I get lazy with this part of the work flow 😁</p>

<div class="post-image 2">
  <img src="/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-1.jpg" alt="" onclick="openLightbox('/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-1.jpg', 'Where's my food?')" loading="lazy" />
  
  <div class="image-caption">Where's my food?</div>
  
</div>

<div class="post-image 2">
  <img src="/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-2.jpg" alt="" onclick="openLightbox('/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-2.jpg', 'Hmm, found some!')" loading="lazy" />
  
  <div class="image-caption">Hmm, found some!</div>
  
</div>

<div class="post-image 2">
  <img src="/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-3.jpg" alt="" onclick="openLightbox('/assets/images/photography/birds/hoopoe-on-a-roll/hoopoe-3.jpg', 'aaaand ... swallowed!')" loading="lazy" />
  
  <div class="image-caption">aaaand ... swallowed!</div>
  
</div>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="photography" /><category term="birds" /><category term="hoopoe" /><category term="wildlife" /><category term="photography-tips" /><summary type="html"><![CDATA[A hoopoe looking for and successfully finding some juicy breakfast.]]></summary></entry><entry><title type="html">The sustainable builder</title><link href="https://rohankthakur.github.io//photography/2024/04/14/bulbul-builder/" rel="alternate" type="text/html" title="The sustainable builder" /><published>2024-04-14T00:00:00+05:30</published><updated>2024-04-14T00:00:00+05:30</updated><id>https://rohankthakur.github.io//photography/2024/04/14/bulbul-builder</id><content type="html" xml:base="https://rohankthakur.github.io//photography/2024/04/14/bulbul-builder/"><![CDATA[<h2 id="the-scene">The Scene</h2>

<p>This is another capture from an early morning bird walk. Getting up early, getting out with the right gear and an open mind.</p>

<h2 id="the-equipment">The Equipment</h2>

<p>A Nikon Z-mount mirrorless body with an 800mm lens, on a shoulder strap - handheld.</p>

<h2 id="the-waiting-game">The Waiting Game</h2>

<p>After spying this little thing - Himalayan Bulbul (<em>Pycnonotus leucogenys</em>) - rummaging around between these bamboo sticks, I wondered what it was up to. Bulbuls aren’t exactly the types to be getting into such piles of wood, at least not in my experience. So I continued to watch it, ready with the camera up to my eyes, getting down to it’s level. Waiting to see what’s up…</p>

<h2 id="the-reward">The Reward</h2>

<p>It was collecting nesting material! Here is the evidence … it delicately pulls out a fine strand of spider web, which it shall use to build it’s nest.</p>

<div class="post-image 2">
  <img src="/assets/images/photography/birds/bulbul-builder/bulbul-builder-1.jpg" alt="" onclick="openLightbox('/assets/images/photography/birds/bulbul-builder/bulbul-builder-1.jpg', 'Himalayan Bulbul (Pycnonotus leucogenys) - pulling on a strand of spider web for nesting.')" loading="lazy" />
  
  <div class="image-caption">Himalayan Bulbul (Pycnonotus leucogenys) - pulling on a strand of spider web for nesting.</div>
  
</div>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="photography" /><category term="birds" /><category term="bulbul" /><category term="wildlife" /><category term="photography-tips" /><summary type="html"><![CDATA[A bulbul delicately pulling out some cobwebs to build it's nest.]]></summary></entry><entry><title type="html">Pen and Ink: Amsterdam!</title><link href="https://rohankthakur.github.io//art/2019/12/25/amsterdam-sketch-pen-ink/" rel="alternate" type="text/html" title="Pen and Ink: Amsterdam!" /><published>2019-12-25T00:00:00+05:30</published><updated>2019-12-25T00:00:00+05:30</updated><id>https://rohankthakur.github.io//art/2019/12/25/amsterdam-sketch-pen-ink</id><content type="html" xml:base="https://rohankthakur.github.io//art/2019/12/25/amsterdam-sketch-pen-ink/"><![CDATA[<p>A pen and ink rendering of a scene from one of my favourite cities - Amsterdam!</p>

<p>And who knew COVID was just round the corner, about to throw the world into chaos 😐…</p>

<h2 id="the-setup">The Setup</h2>

<p>A good setup is important for nice results - you need to be comfortable, you need to feel inspired.</p>

<div class="post-image 2">
  <img src="/assets/images/art/sketches/ams-1/setup.jpg" alt="" onclick="openLightbox('/assets/images/art/sketches/ams-1/setup.jpg', 'The Setup')" loading="lazy" />
  
  <div class="image-caption">The Setup</div>
  
</div>

<p>For this study, I worked with an image captured by me in May 2018.</p>

<p>It started with a light pencil sketch to get everything in place,</p>

<div class="post-image 2">
  <img src="/assets/images/art/sketches/ams-1/ams-1-1.jpg" alt="" onclick="openLightbox('/assets/images/art/sketches/ams-1/ams-1-1.jpg', 'Initial sketch')" loading="lazy" />
  
  <div class="image-caption">Initial sketch</div>
  
</div>

<p>And then, the first solid lines with a pen … time to commit to the ‘bigger picture’ …</p>

<div class="post-image 2">
  <img src="/assets/images/art/sketches/ams-1/ams-1-2.jpg" alt="" onclick="openLightbox('/assets/images/art/sketches/ams-1/ams-1-2.jpg', 'First commit')" loading="lazy" />
  
  <div class="image-caption">First commit</div>
  
</div>

<p>Once you have the main layout, getting into the details … some parts are precise, some are loose … trying to balance the two to keep true to the rendering in mind,</p>

<div class="post-image 2">
  <img src="/assets/images/art/sketches/ams-1/ams-1-3.jpg" alt="" onclick="openLightbox('/assets/images/art/sketches/ams-1/ams-1-3.jpg', 'Details follow')" loading="lazy" />
  
  <div class="image-caption">Details follow</div>
  
</div>

<p>Until it’s done, and you have something that you are satisfied with,</p>

<div class="post-image 2">
  <img src="/assets/images/art/sketches/ams-1/ams-1-4.jpg" alt="" onclick="openLightbox('/assets/images/art/sketches/ams-1/ams-1-4.jpg', 'The finish line!')" loading="lazy" />
  
  <div class="image-caption">The finish line!</div>
  
</div>

<p>Hope you like it!</p>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="art" /><category term="pen" /><category term="ink" /><category term="drawing" /><category term="city" /><summary type="html"><![CDATA[Exploring one of my favourite cities with pen and ink, a classic subject - canals and bridges.]]></summary></entry><entry><title type="html">Enhancing PROC COMPARE to do more</title><link href="https://rohankthakur.github.io//projects/2017/10/09/sas-proc-compare/" rel="alternate" type="text/html" title="Enhancing PROC COMPARE to do more" /><published>2017-10-09T00:00:00+05:30</published><updated>2017-10-09T00:00:00+05:30</updated><id>https://rohankthakur.github.io//projects/2017/10/09/sas-proc-compare</id><content type="html" xml:base="https://rohankthakur.github.io//projects/2017/10/09/sas-proc-compare/"><![CDATA[<p>This project involved taking the standard PROC COMPARE and building a utility on top of it, using SAS macros.</p>

<p>PROC COMPARE by default gives you a very detailed result which can be tedious to go thorugh, especially if you are comparing large datasets with lots of rows and columns.</p>

<p>It builds on PROC COMPARE to reduce columns, rows etc and summarizes changes per key item, making the output easier to analyse and work with.</p>

<p>In fact, I have used the reduced output to programmatically prepare proper reports for before/after changes, that can be automatically delivered at the end of specific ETL builds to stakeholders.</p>

<h2 id="the-code">The code</h2>

<p><em>(Scroll right for longer lines of code)</em></p>

<div class="language-sas highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
</pre></td><td class="rouge-code"><pre><span class="cm">/* builds on PROC COMPARE to reduce columns, rows etc and summarise changes per key item */</span>
<span class="k">%macro</span> <span class="nf">SmartCompare</span><span class="p">(</span><span class="n">libref1</span><span class="o">=</span><span class="p">,</span><span class="n">dsn1</span><span class="o">=</span><span class="p">,</span><span class="n">libref2</span><span class="o">=</span><span class="p">,</span><span class="n">dsn2</span><span class="o">=</span><span class="p">,</span><span class="n">keyname</span><span class="o">=</span><span class="p">,</span><span class="n">excl_cols</span><span class="o">=</span><span class="p">);</span>
       <span class="cm">/*%SmartCompare(
              libref1=work, 
              dsn1=temp_test_1_old, 
              libref2=work, 
              dsn2=temp_test_1_lat, 
              keyname = COMP_TIMESTAMP, 
              excl_cols=('_OBS_' '_TYPE_' 'COMP_TIMESTAMP' 'OLD_LATEST_NEW_TERMIN')
       );
       */</span>
       <span class="cm">/* Rohan Kumar Thakur, https://github.com/rohankthakur */</span>
       <span class="o">*</span><span class="p">;</span><span class="k">%macro</span> <span class="nf">a</span><span class="p">;</span><span class="k">%mend</span> <span class="nf">a</span><span class="p">;</span>
       <span class="k">%let</span> <span class="n">rc1</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">open</span><span class="p">(</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">,</span><span class="n">i</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">nobs1</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">attrn</span><span class="p">(</span><span class="nv">&amp;rc1</span><span class="p">,</span><span class="n">NOBS</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">close1</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">CLOSE</span><span class="p">(</span><span class="nv">&amp;rc1</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">is_there1</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">));</span>
 
       <span class="k">%let</span> <span class="n">rc2</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">open</span><span class="p">(</span><span class="nv">&amp;libref2..&amp;dsn2</span><span class="p">,</span><span class="n">i</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">nobs2</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">attrn</span><span class="p">(</span><span class="nv">&amp;rc2</span><span class="p">,</span><span class="n">NOBS</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">close2</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">CLOSE</span><span class="p">(</span><span class="nv">&amp;rc2</span><span class="p">));</span>
       <span class="k">%let</span> <span class="n">is_there2</span><span class="o">=</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref2..&amp;dsn2</span><span class="p">));</span>
 
       <span class="k">%if</span> <span class="p">(</span><span class="nv">&amp;nobs1</span> <span class="ow">ne</span> <span class="mi">0</span> <span class="ow">and</span> <span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">)))</span> <span class="ow">and</span>  <span class="p">(</span><span class="nv">&amp;nobs2</span> <span class="ow">ne</span> <span class="mi">0</span> <span class="ow">and</span> <span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref2..&amp;dsn2</span><span class="p">)))</span> <span class="k">%then</span> <span class="k">%do</span><span class="p">;</span>
       <span class="k">%let</span> <span class="n">syscc</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
       <span class="cm">/* print when exists with non-zero row count */</span>
              <span class="k">proc</span> <span class="k">sort</span> <span class="k">data</span><span class="o">=</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">;</span> <span class="k">by</span> <span class="nv">&amp;keyname</span><span class="p">;</span> <span class="k">run</span><span class="p">;</span>
              <span class="k">proc</span> <span class="k">sort</span> <span class="k">data</span><span class="o">=</span><span class="nv">&amp;libref2..&amp;dsn2</span><span class="p">;</span> <span class="k">by</span> <span class="nv">&amp;keyname</span><span class="p">;</span> <span class="k">run</span><span class="p">;</span>
              <span class="k">proc</span> <span class="k">compare</span> <span class="n">base</span><span class="o">=</span><span class="nv">&amp;libref1..&amp;dsn1</span> <span class="k">compare</span><span class="o">=</span><span class="nv">&amp;libref2..&amp;dsn2</span> <span class="n">OUT</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">diff_b</span> <span class="n">OUTNOEQUAL</span> <span class="cm">/*OUTBASE OUTCOMP*/</span> <span class="n">OUTDIF</span> <span class="n">NOPRINT</span><span class="p">;</span> <span class="n">id</span> <span class="nv">&amp;keyname</span><span class="p">;</span> <span class="k">run</span><span class="p">;</span>
              <span class="cm">/* select CHAR columns */</span>
                     <span class="k">proc</span> <span class="k">sql</span><span class="p">;</span>
                     <span class="k">create</span> <span class="k">table</span> <span class="n">work</span><span class="p">.</span><span class="n">contents</span> <span class="k">as</span>
                     <span class="k">select</span> <span class="n">monotonic</span><span class="p">()</span> <span class="k">as</span> <span class="n">start</span><span class="p">,</span> <span class="n">NAME</span> <span class="k">from</span> <span class="n">dictionary</span><span class="p">.</span><span class="n">columns</span> <span class="k">where</span> <span class="k">libname</span><span class="o">=</span><span class="k">%upcase</span><span class="p">(</span><span class="s2">"work"</span><span class="p">)</span> <span class="ow">and</span> <span class="n">memname</span><span class="o">=</span><span class="k">%upcase</span><span class="p">(</span><span class="s2">"DIFF_B"</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="k">format</span> <span class="ow">like</span> <span class="s1">'$%'</span> <span class="ow">or</span> <span class="n">type</span> <span class="o">=</span> <span class="s1">'char'</span><span class="p">);</span>
                     <span class="k">quit</span><span class="p">;</span>
              <span class="cm">/* make macro var with a list of columns */</span>
                     <span class="k">proc</span> <span class="k">sql</span> <span class="n">noprint</span><span class="p">;</span>
                     <span class="k">select</span> <span class="n">name</span> <span class="k">into</span> <span class="p">:</span><span class="n">varlist</span> <span class="n">separated</span> <span class="k">by</span> <span class="s1">' '</span> <span class="k">from</span> <span class="n">work</span><span class="p">.</span><span class="n">contents</span> <span class="k">where</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nv">&amp;excl_cols</span> <span class="k">order</span> <span class="k">by</span> <span class="n">start</span><span class="p">;</span>
                     <span class="k">quit</span><span class="p">;</span>
              <span class="cm">/* make macro var with a list of corresponding counter columns */</span>
                     <span class="k">proc</span> <span class="k">sql</span> <span class="n">noprint</span><span class="p">;</span>
                     <span class="k">select</span> <span class="k">trim</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="o">||</span> <span class="s1">'_2'</span> <span class="k">into</span> <span class="p">:</span><span class="n">varlist2</span> <span class="n">separated</span> <span class="k">by</span> <span class="s1">' '</span> <span class="k">from</span> <span class="n">work</span><span class="p">.</span><span class="n">contents</span> <span class="k">where</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nv">&amp;excl_cols</span> <span class="k">order</span> <span class="k">by</span> <span class="n">start</span><span class="p">;</span>
                     <span class="k">quit</span><span class="p">;</span>
              <span class="cm">/* create a format for column names */</span>
                     <span class="k">proc</span> <span class="k">sql</span><span class="p">;</span>
                     <span class="k">create</span> <span class="k">table</span> <span class="n">work</span><span class="p">.</span><span class="n">contents_format</span> <span class="k">as</span>
                     <span class="k">select</span> <span class="n">monotonic</span><span class="p">()</span> <span class="k">as</span> <span class="n">start</span><span class="p">,</span> <span class="s1">'get_col_name'</span> <span class="k">as</span> <span class="n">fmtname</span><span class="p">,</span> <span class="n">NAME</span> <span class="k">as</span> <span class="k">label</span><span class="p">,</span> <span class="s1">'n'</span> <span class="k">as</span> <span class="n">type</span> <span class="k">from</span> <span class="n">work</span><span class="p">.</span><span class="n">contents</span> <span class="k">where</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="nv">&amp;excl_cols</span> <span class="k">order</span> <span class="k">by</span> <span class="n">start</span><span class="p">;</span>
                     <span class="k">quit</span><span class="p">;</span>
                     <span class="k">proc</span> <span class="k">format</span> <span class="n">library</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">formats</span> <span class="n">cntlin</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">contents_format</span><span class="p">;</span> <span class="k">run</span><span class="p">;</span>
                     <span class="k">proc</span> <span class="k">format</span> <span class="n">library</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">formats</span> <span class="n">fmtlib</span><span class="p">;</span> <span class="k">select</span> <span class="n">get_col_name</span><span class="p">;</span> <span class="k">run</span><span class="p">;</span>
                     <span class="cm">/* Get number of changes per keyname and all changed columns per keyname */</span>
                           <span class="k">data</span> <span class="nv">work.count_changes_pre</span> <span class="p">;</span>
                             <span class="k">set</span> <span class="n">work</span><span class="p">.</span><span class="n">diff_b</span><span class="p">;</span>
                             <span class="k">length</span> <span class="n">changes</span> <span class="kt">$</span> <span class="m">8000</span><span class="p">;</span>
                             <span class="k">array</span> <span class="n">vi</span><span class="p">{</span><span class="o">*</span><span class="p">}</span> <span class="nv">&amp;varlist</span> <span class="p">;</span>
                             <span class="n">changes</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
                             <span class="n">num_changes</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
                                    <span class="k">do</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">to</span> <span class="k">dim</span><span class="p">(</span><span class="n">vi</span><span class="p">)</span> <span class="p">;</span>
                                      <span class="k">if</span> <span class="k">index</span><span class="p">(</span><span class="n">vi</span><span class="p">{</span><span class="n">i</span><span class="p">},</span> <span class="s1">'X'</span><span class="p">)</span> <span class="ow">ge</span> <span class="mi">1</span> <span class="k">then</span> 
                                                <span class="k">do</span><span class="p">;</span>
                                                       <span class="k">if</span> <span class="n">changes</span> <span class="o">=</span> <span class="s1">''</span> <span class="k">then</span> <span class="k">do</span><span class="p">;</span> <span class="n">changes</span> <span class="o">=</span> <span class="k">put</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="kt">$</span><span class="n">get_col_name</span><span class="p">.);</span> <span class="n">num_changes</span> <span class="o">=</span> <span class="n">num_changes</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="k">end</span><span class="p">;</span>
                                                       <span class="k">else</span> <span class="k">do</span><span class="p">;</span> <span class="n">changes</span> <span class="o">=</span> <span class="k">catx</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span><span class="n">changes</span><span class="p">,</span><span class="k">put</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="kt">$</span><span class="n">get_col_name</span><span class="p">.));</span> <span class="n">num_changes</span> <span class="o">=</span> <span class="n">num_changes</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="k">end</span><span class="p">;</span>
                                                <span class="k">end</span><span class="p">;</span>
                                    <span class="k">end</span> <span class="p">;</span>
                             <span class="k">output</span> <span class="n">work</span><span class="p">.</span><span class="n">count_changes_pre</span><span class="p">;</span>
                             <span class="k">drop</span> <span class="n">i</span><span class="p">;</span>
                           <span class="k">run</span><span class="p">;</span>
                           <span class="cm">/**/</span>
                           <span class="k">%let</span> <span class="n">counts</span> <span class="o">=</span> <span class="k">%eval</span><span class="p">(</span><span class="k">%sysfunc</span><span class="p">(</span><span class="k">count</span><span class="p">(</span><span class="n">%cmpres</span><span class="p">(</span><span class="nv">&amp;keyname</span><span class="p">),</span><span class="k">%str</span><span class="p">(</span> <span class="p">)))</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
                           <span class="k">%global</span> <span class="n">new_keyname</span><span class="p">;</span>
                           <span class="k">data</span> <span class="nv">_null_</span><span class="p">;</span>
                                  <span class="k">length</span> <span class="n">full_piece</span> <span class="kt">$</span> <span class="m">200</span><span class="p">;</span>
                                  <span class="n">full_piece</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>     
                                  <span class="k">do</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">to</span> <span class="nv">&amp;counts</span><span class="p">;</span>
                                         <span class="n">full_piece</span> <span class="o">=</span> <span class="k">catx</span><span class="p">(</span><span class="s1">', '</span><span class="p">,</span><span class="n">full_piece</span><span class="p">,</span> <span class="k">scan</span><span class="p">(</span><span class="s2">"</span><span class="si">&amp;keyname</span><span class="s2">"</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="s1">' '</span><span class="p">));</span> 
                                  <span class="k">end</span><span class="p">;</span>
                                  <span class="k">drop</span> <span class="n">i</span><span class="p">;</span>
                                  <span class="k">call</span> <span class="n">symput</span><span class="p">(</span><span class="s1">'new_keyname'</span><span class="p">,</span><span class="n">full_piece</span><span class="p">);</span>
                           <span class="k">run</span><span class="p">;</span>
                           <span class="cm">/**/</span>
                           <span class="k">proc</span> <span class="k">sql</span><span class="p">;</span>
                           <span class="k">create</span> <span class="k">table</span> <span class="n">work</span><span class="p">.</span><span class="n">sc_count_changes</span> <span class="k">as</span>
                           <span class="k">select</span> <span class="nv">&amp;new_keyname</span><span class="p">,</span> <span class="k">trim</span><span class="p">(</span><span class="k">put</span><span class="p">(</span><span class="n">num_changes</span><span class="p">,</span><span class="m">4.</span><span class="p">)</span> <span class="o">||</span> <span class="s1">' changes, '</span> <span class="o">||</span> <span class="n">changes</span><span class="p">)</span> <span class="k">as</span> <span class="n">Description</span>
                           <span class="k">from</span> <span class="n">work</span><span class="p">.</span><span class="n">count_changes_pre</span><span class="p">;</span>
                           <span class="k">quit</span><span class="p">;</span>
                     <span class="cm">/* Check columns that have changes and keep only those columns in result view */</span>
                           <span class="k">data</span> <span class="nv">work.limited_output_pre_a</span><span class="p">;</span>
                             <span class="k">set</span> <span class="n">work</span><span class="p">.</span><span class="n">diff_b</span> <span class="k">end</span><span class="o">=</span><span class="n">eof</span> <span class="p">;</span>
                             <span class="k">array</span> <span class="n">vi</span><span class="p">{</span><span class="o">*</span><span class="p">}</span> <span class="nv">&amp;varlist</span> <span class="p">;</span> <span class="cm">/* incoming values */</span>
                             <span class="k">array</span> <span class="n">vc</span><span class="p">{</span><span class="o">*</span><span class="p">}</span> <span class="nv">&amp;varlist2</span> <span class="p">;</span> <span class="cm">/* counters */</span>
                             <span class="k">retain</span> <span class="n">vc</span> <span class="p">.</span> <span class="p">;</span>
                                    <span class="k">do</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">to</span> <span class="k">dim</span><span class="p">(</span><span class="n">vi</span><span class="p">)</span> <span class="p">;</span>
                                      <span class="k">if</span> <span class="k">index</span><span class="p">(</span><span class="n">vi</span><span class="p">{</span><span class="n">i</span><span class="p">},</span> <span class="s1">'X'</span><span class="p">)</span> <span class="ow">ge</span> <span class="mi">1</span> <span class="k">then</span> <span class="n">vc</span><span class="p">{</span><span class="n">i</span><span class="p">}</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">;</span>
                                    <span class="k">end</span> <span class="p">;</span>
                             <span class="k">if</span> <span class="n">eof</span> <span class="k">then</span> <span class="k">output</span> <span class="p">;</span>
                             <span class="k">keep</span> <span class="nv">&amp;varlist2</span> <span class="p">;</span>
                           <span class="k">run</span><span class="p">;</span>
                            <span class="k">proc</span> <span class="k">transpose</span> <span class="k">data</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">limited_output_pre_a</span> <span class="k">out</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">limited_output_pre_b</span> <span class="p">(</span><span class="k">Rename</span><span class="o">=</span> <span class="p">(</span><span class="n">_NAME_</span> <span class="o">=</span> <span class="k">NAME</span> <span class="n">COL1</span><span class="o">=</span><span class="k">COUNT</span><span class="p">));</span> <span class="k">run</span><span class="p">;</span>
                           <span class="k">proc</span> <span class="k">sql</span> <span class="n">noprint</span><span class="p">;</span>
                           <span class="k">select</span> <span class="k">substr</span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="k">length</span><span class="p">(</span><span class="n">name</span><span class="p">)</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="k">into</span> <span class="p">:</span><span class="n">shortlist</span> <span class="n">separated</span> <span class="k">by</span> <span class="s1">' '</span>
                           <span class="k">from</span> <span class="n">work</span><span class="p">.</span><span class="n">limited_output_pre_b</span> <span class="k">where</span> <span class="k">count</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span>
                           <span class="k">quit</span><span class="p">;</span>
                           <span class="k">data</span> <span class="nv">work.sc_limited_output</span> <span class="p">(</span><span class="k">keep</span><span class="o">=</span> <span class="nv">&amp;keyname</span> <span class="nv">&amp;shortlist</span><span class="p">);</span>
                           <span class="k">informat</span> <span class="nv">&amp;keyname</span> <span class="nv">&amp;shortlist</span><span class="p">;</span>
                           <span class="k">set</span> <span class="n">work</span><span class="p">.</span><span class="n">diff_b</span> <span class="p">;</span>
                           <span class="k">run</span><span class="p">;</span>
                           <span class="cm">/* check for errors and delete temp datasets etc */</span>
                           <span class="k">%if</span> <span class="nv">&amp;syscc</span> <span class="o">&lt;</span> <span class="m">10</span> <span class="k">%then</span> <span class="k">%do</span><span class="p">;</span>
                                  <span class="k">proc</span> <span class="k">datasets</span> <span class="n">library</span><span class="o">=</span><span class="n">work</span> <span class="n">memtype</span><span class="o">=</span><span class="k">data</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="n">diff_b</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="k">contents</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="n">contents_format</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="n">count_changes_pre</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="n">limited_output_pre_a</span><span class="p">;</span>
                                         <span class="k">delete</span> <span class="n">limited_output_pre_b</span><span class="p">;</span>
                                  <span class="k">run</span><span class="p">;</span>
                                  <span class="k">proc</span> <span class="k">catalog</span> <span class="n">catalog</span><span class="o">=</span><span class="n">work</span><span class="p">.</span><span class="n">formats</span><span class="p">;</span>
                                  <span class="k">delete</span> <span class="n">get_col_name</span><span class="p">.</span><span class="k">format</span><span class="p">;</span>
                                  <span class="k">quit</span><span class="p">;</span>
                           <span class="k">%end</span><span class="p">;</span>
                           <span class="k">%else</span> <span class="k">%if</span>  <span class="nv">&amp;syscc</span> <span class="o">&gt;</span> <span class="m">10</span> <span class="k">%then</span> <span class="k">%do</span><span class="p">;</span>
                                  <span class="k">%put</span> <span class="n">Warning</span><span class="o">!</span> <span class="n">Temp</span> <span class="n">files</span> <span class="ow">not</span> <span class="n">deleted</span> <span class="n">as</span> <span class="n">there</span> <span class="n">were</span> <span class="n">errors</span> <span class="n">detected</span><span class="p">.;</span>
                           <span class="k">%end</span><span class="p">;</span>
       <span class="k">%end</span><span class="p">;</span>
       <span class="k">%else</span> <span class="k">%if</span> <span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">))</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">%then</span> <span class="k">%do</span><span class="p">;</span>
              <span class="cm">/* print when dataset does not exist */</span>
       <span class="k">%end</span><span class="p">;</span>
       <span class="k">%else</span> <span class="k">%if</span> <span class="nv">&amp;nobs1</span> <span class="o">=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="k">%sysfunc</span><span class="p">(</span><span class="k">Exist</span><span class="p">(</span><span class="nv">&amp;libref1..&amp;dsn1</span><span class="p">))</span> <span class="k">%then</span> <span class="k">%do</span><span class="p">;</span>
              <span class="cm">/* print when dataset exists with zero row count */</span>
       <span class="k">%end</span><span class="p">;</span>
<span class="k">%mend</span> <span class="nf">SmartCompare</span><span class="p">;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><em>Project repository and documentation available on GitHub.</em></p>]]></content><author><name>Rohan Kumar Thakur</name></author><category term="projects" /><category term="sas" /><category term="portfolio" /><summary type="html"><![CDATA[This SAS macro builds on PROC COMPARE to reduce columns, rows etc and summarise changes per key item.]]></summary></entry></feed>