{"id":4493,"date":"2026-11-13T00:35:00","date_gmt":"2026-11-13T00:35:00","guid":{"rendered":"https:\/\/dataopsschool.com\/blog\/?p=4493"},"modified":"2026-11-13T00:35:00","modified_gmt":"2026-11-13T00:35:00","slug":"script-repeated-data-check-after-manual-runs","status":"publish","type":"post","link":"https:\/\/dataopsschool.com\/blog\/script-repeated-data-check-after-manual-runs\/","title":{"rendered":"How to Script a Repeated Data Check After Doing It Manually"},"content":{"rendered":"<p>Every data team has a check that someone runs by hand each Monday. Row counts compared against last week, a null scan on the customer table, a glance at the newest partition to see whether it landed. It feels responsible, and for a while it is. Then the person who does it goes on leave, or the table list triples, and the check quietly stops happening. The fix is not a heroic framework. It is a repeatable method for choosing what to script and in what order, and this guide lays it out as numbered steps so you can follow it with your own pipeline.<\/p>\n<p>The principle underneath is simple and evidence-friendly: automate only what your own records show to be identical across runs, and keep a human on whatever required interpretation.<\/p>\n<h2>Step 1: pick one check and run it manually, on purpose<\/h2>\n<p>Choose a check that happens at least weekly and whose purpose you can state in one sentence, for example &#8220;confirm yesterday&#8217;s orders arrived and look plausible&#8221;. Resist picking the most impressive one. The best first candidate is dull.<\/p>\n<p>Run it by hand at least three times. Do it the way you normally would, with the same queries and the same dashboards. The goal of these runs is observation, not efficiency.<\/p>\n<h2>Step 2: record every action and every decision<\/h2>\n<p>Open a plain text file and log each step as you take it. Capture:<\/p>\n<ul>\n<li>The exact query or command, copied rather than paraphrased.<\/li>\n<li>The input it needs, such as a date or a table name.<\/li>\n<li>What you looked at in the result.<\/li>\n<li>What you concluded, and why.<\/li>\n<li>How long each part took.<\/li>\n<\/ul>\n<p>Timing is the evidence that will later justify the work. A step that takes forty seconds is not worth much effort. One that takes twenty minutes and is repeated daily is.<\/p>\n<h2>Step 3: compare the logs and mark what never changes<\/h2>\n<p>Lay the three logs next to each other. Mark anything identical in all of them: same query shape, same thresholds, same output layout. Mark separately anything where your conclusion depended on context, for instance &#8220;volume is low, but it is a holiday&#8221;.<\/p>\n<p>You now have two columns. The first is mechanical. The second is interpretive. Only the first column is eligible for automation.<\/p>\n<h2>Step 4: write the mechanical part as a small script<\/h2>\n<p>Take the identical steps and put them into a script or a scheduled query. Keep it modest. A good early version does three things: runs the query, compares the result to an expected range, and writes a one-line outcome with a timestamp. It does not attempt to explain the result.<\/p>\n<p>For teams that want a formal framework, the ideas in a <a href=\"https:\/\/dataopsschool.com\/blog\/a-practical-guide-to-automated-data-validation-in-dataops\/\">hands-on introduction to automated validation in DataOps<\/a> map neatly onto this step, and so does the broader <a href=\"https:\/\/dataopsschool.com\/blog\/a-practical-introduction-to-dataops-testing-automation\/\">overview of testing automation for data pipelines<\/a> published here earlier. Use either as a menu, not a mandate.<\/p>\n<h2>Step 5: decide what the script does when it fails<\/h2>\n<p>This is where many first automations go wrong. A failing check can notify someone, block a downstream job, or simply log the failure. For a first version, notify and log. Blocking downstream jobs should come only after the check has run quietly for a few weeks and you have measured how often it raises false alarms.<\/p>\n<p>Write the failure message for the reader who will see it cold. It should name the table, the expected range, the observed value and the link to the query. If the message cannot be acted on without opening three other tabs, rewrite it.<\/p>\n<h2>Step 6: run both versions in parallel<\/h2>\n<p>For two or three cycles, let the script run while a person repeats the manual check. Compare outcomes. If they agree, good. If they disagree, you have found either a bug or an interpretive step you had mislabelled as mechanical. Both are valuable discoveries, and both are far cheaper to find now than in a production incident.<\/p>\n<h2>Step 7: assign the interpretation to a named person<\/h2>\n<p>Automation tells you that something moved. It rarely tells you why. Decide who reads the outcome, within what time, and what they are permitted to do about it: investigate, pause a job, escalate. The answer should be written next to the script, not remembered.<\/p>\n<h2>Step 8: measure and prune<\/h2>\n<p>After a month, count three things: how many times the script ran, how many alerts it raised, and how many of those alerts needed action. A check with many alerts and no actions is noise, so loosen the threshold. A check that never alerts may be fine, or may be testing the wrong thing, so deliberately break a copy of the data once to confirm it would notice.<\/p>\n<h2>A short worked pattern<\/h2>\n<p>Picture a team that compares daily row counts for a handful of source tables. By hand, each comparison takes a few minutes and involves the same query with a different table name. After three manual rounds, the log shows the query never changes and the threshold has always been &#8220;within a band of the same weekday last week&#8221;. The interpretation, such as &#8220;that source had a planned outage&#8221;, changes every time.<\/p>\n<p>So they script the query and the band comparison across all tables, send a short summary each morning, and keep a field where the analyst types a reason for any miss. The mechanical work falls away. The analyst&#8217;s notes, kept in one place, start to show which sources cause trouble most often, which is a finding nobody had time to see before.<\/p>\n<h2>The same logic outside data engineering<\/h2>\n<p>Intake of any repeated request benefits from this pattern. As an illustration, <a href=\"https:\/\/www.hiphospitals.com\/\">HipHospitals<\/a> is a medical tourism site whose country pages list hospitals and doctors, with forms for requesting a quote or booking an appointment from abroad. The forms standardise the repeated first contact, while everything that needs a person happens later, which mirrors the split between a script and an analyst. The example concerns administration only, not clinical judgment.<\/p>\n<h2>Common mistakes to avoid<\/h2>\n<ol>\n<li>Scripting after one run. You will encode a one-off quirk as a rule.<\/li>\n<li>Automating the interpretive column and then trusting it blindly.<\/li>\n<li>Building without a failure message anyone can act on.<\/li>\n<li>Never revisiting thresholds as the data grows.<\/li>\n<li>Forgetting to record who owns the script when people change teams.<\/li>\n<\/ol>\n<h2>What to do this week<\/h2>\n<p>Choose your dullest recurring check. Log three manual runs. Mark the unchanging steps. Script only those, run both versions side by side, and write down who reads the result. The evidence you gather along the way, timings and false alarms included, will tell you whether the next check deserves the same treatment.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A step-by-step method for data teams: run a recurring check by hand, log what stays constant, then turn that part into a small script while analysts keep the interpretation.<\/p>\n","protected":false},"author":6,"featured_media":4494,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[814],"tags":[],"class_list":["post-4493","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dataops"],"_links":{"self":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/4493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=4493"}],"version-history":[{"count":1,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/4493\/revisions"}],"predecessor-version":[{"id":4590,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/4493\/revisions\/4590"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/media\/4494"}],"wp:attachment":[{"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=4493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=4493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dataopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=4493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}