ข้ามไปยังเนื้อหา

การย้ายข้อมูลเป็นโครงการด้านคุณภาพก่อนอื่นใด

มีให้อ่านอีก 19 ภาษา

English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · 简体中文 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · Українська · Español (México) · Français (Canada) · Deutsch (Schweiz)

In a fruit packing shed, crates of sound apples move along the line, and one crate of bruised and split apples is set apart on the floor.
ภาพสร้างด้วย AI

โมดูลที่ 1 จาก 5 ในบท การย้ายข้อมูลและการซิงก์ บทที่ 10 ของหลักสูตร Data Architect แต่ละโมดูลอ่านแยกกันได้ ก่อนหน้า: บทก่อนหน้า การผสานรวมและการเคลื่อนย้ายข้อมูล · ถัดไป: การโหลดในปริมาณมาก

คำถามที่โมดูลนี้ตอบ: อะไรควรเกิดขึ้นกับข้อมูลก่อนที่คุณจะเริ่มโหลดมันเข้า Salesforce?

โครงการย้ายข้อมูลหลอกคุณได้ คุณมีข้อมูลอยู่ตรงนี้ ต้องการมันอยู่ตรงนั้น จึงมีคนเริ่มพูดถึง Data Loader, Bulk API ไฟล์ CSV ขนาด batch และลำดับการโหลด สิ่งเหล่านั้นสำคัญ แต่ไม่ใช่จุดที่ผมเริ่ม คำถามแรกของผมคือ เรากำลังจะย้ายอะไรกันแน่? ถ้าต้นทางมีลูกค้าซ้ำ ที่อยู่ที่ไม่ถูกต้อง ค่าที่เลิกใช้แล้ว ความสัมพันธ์ที่ขาด และข้อมูลสิบห้าปีที่ไม่มีใครต้องการ Salesforce ก็ยินดีจะเป็นบ้านใหม่ของทั้งหมดนั้น การโหลดให้เร็วขึ้นไม่ได้แก้สิ่งนั้น การย้ายข้อมูลเป็นโครงการด้านคุณภาพก่อนอื่นใด

Here’s Steve Trucking’s landscape from Checkpoint 1, the weekend RouteDesk retires. RouteDesk is the desktop dispatch tool the coordinators used inside each distribution center (DC) to turn manifests into routes. It holds eight years of delivery history, about 5 million deliveries, and the quality varies by DC. At Checkpoint 1 we decided it retires, and we left one question open: what, if anything, comes into the org? That’s a migration decision, and this is the chapter for it. ⟲

The arrow that runs once Steve Trucking's landscape from Checkpoint 1, in the same places, the weekend RouteDesk retires: people on the left, Salesforce with Field Service in the middle with the Retail Partner portal and the tracking page, the integration layer from chapter 9 to its right, and the systems around it: Snowflake, FleetLink, the finance ERP, photo storage, and RouteDesk, retiring, with 8 years and about 5 million deliveries. One new arrow, in amber, the migration this module zooms in on, carries what's still open from RouteDesk into Salesforce, migrated once. Underneath: one arrow runs once and then disappears; a migration is an integration with an end. {"author": "Steve Simpson", "blueprint": "1.0.1", "builder": "standard 1.54.0", "built": "2026-10-30", "id": "DGM-DA-MG-10", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "system-landscape 0.13.0", "theme": "stevetecharc 1.4.0"} ABOVE: IDENTITY, APPEXCHANGE, WEB PEOPLE RIGHT: INTERNAL SYSTEMS BELOW: CUSTOMER CHANNELS BOTTOM RIGHT: PARTNERS AND PROVIDERS Dispatch coordinators 45, inside 9 partner DCs Delivery crews ~700 on 330 trucks Care and office staff 100: service, ops, finance Retail Partner users ~300 at 3 partners Recipients ~1 million a year Corporate IdP SSO for office staff only Retail Partner portal Tracking page INTEGRATION Snowflake status history, analytics FleetLink raw GPS stays here Finance ERP invoices partners, pays crews Photo storage 4–5 million a year, off core RouteDesk retiring: 8 years, ~5 million deliveries Phone care agents Email email-to-case SMS and email provider day-before message, with a link Redrock REST API, webhooks Keystone CSV over SFTP Brightwave EDI through a third-party network Salesforce Field Service, one US org a link, no login office staff only calls cases in manifests in status out manifests in status out manifests in status out upserts, partner key status events status events latest position only delivery counts delivery counts photos, from the crews' app day-before, with a link what's still open: migrated once Salesforce a community people identity, apps, web an internal system a customer channel the integration layer starts at the system that opens the connection; the label says what moves a shared certificate: trust, no direct call the migration we zoom in on Checkpoint 1's landscape, the weekend RouteDesk retires. One arrow runs once and then disappears: a migration is an integration with an end. © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

One new arrow. It runs once, and then it disappears. ⟲

A migration is an arrow on the landscape like any other. Everything chapter 9 asked of an arrow applies: what moves, how much, by which key, who proves it arrived. The difference is that this arrow has an end. When it’s done, RouteDesk is switched off and the arrow comes off the drawing. That makes it easy to rush, because “we only do it once.” But the data it carries stays in Salesforce for years. ⟲

การย้ายข้อมูลที่แย่ให้เร็วขึ้นไม่ใช่ความสำเร็จ

หัวข้อที่มีชื่อว่า “การย้ายข้อมูลที่แย่ให้เร็วขึ้นไม่ใช่ความสำเร็จ ”

ระบบเดิมมีเรกคอร์ดลูกค้า 500,000 รายการ และเราย้ายเรกคอร์ดลูกค้า 500,000 รายการ เราสำเร็จไหม? อาจใช่ แล้วถ้า 40,000 รายการเป็นข้อมูลซ้ำ 75,000 รายการไม่มีความเคลื่อนไหวมาสิบปี หลายพันรายการมีรหัสรัฐที่ไม่ถูกต้อง บางรายการไม่มีตัวระบุที่ใช้ได้ เรกคอร์ดลูกบางรายการชี้ไปยังเรกคอร์ดแม่ที่ไม่มีอยู่แล้ว และบางฟิลด์มีความหมายต่างกันขึ้นอยู่กับว่าเรกคอร์ดถูกสร้างเมื่อไหร่ล่ะ? รายงานยังบอกได้ว่าต้นทาง 500,000 ปลายทาง 500,000 โหลดได้ 100 เปอร์เซ็นต์ และโครงการก็ยังล้มเหลวได้ ความครบถ้วนสำคัญ แต่ความครบถ้วนอย่างเดียวพิสูจน์คุณภาพไม่ได้

ดังนั้นก่อนออกแบบการโหลด ผมต้องการเข้าใจต้นทาง มีข้อมูลอะไร และมันหมายถึงอะไร? เก่าแค่ไหน น่าเชื่อถือแค่ไหน ฟิลด์ไหนถูกใช้จริง ค่าไหนถูกต้อง มีความสัมพันธ์อะไร ตัวระบุไหนเชื่อถือได้? อะไรควรรอดผ่านการย้ายข้อมูล และอะไรไม่ควร? นี่คือที่ที่บทก่อนๆ ถึงเวลาใช้งาน: บทที่ 4 สอนเราเรื่องภาพรวมระบบขององค์กร บทที่ 5 ว่าคุณภาพต้องถูกออกแบบ บทที่ 6 เรื่องตัวตนและอำนาจชี้ขาด การย้ายข้อมูลนำทั้งหมดนั้นไปใช้กับก้อนข้อมูลที่มีอยู่ มันไม่ใช่แค่การย้ายแถว มันคือการตัดสินว่าอดีตส่วนไหนสมควรเป็นส่วนหนึ่งของสถาปัตยกรรมในอนาคต

รายการสำหรับการย้ายข้อมูลต้องมีอย่างน้อยสามคำตอบ: ย้าย จัดเก็บถาวร หรือทิ้งตามนโยบาย รายละเอียดธุรกรรมอายุห้าปีอาจต้องเก็บไว้เพื่อการปฏิบัติตามกฎ โดยไม่ต้องอยู่ในโมเดลข้อมูลที่ใช้งานอยู่ ข้อมูลชั่วคราวที่เลิกใช้อาจไม่มีทั้งข้อกำหนดการเก็บรักษาและคุณค่า ประวัติอาจควรอยู่ในที่จัดเก็บถาวรที่ค้นหาได้ หลักการวงจรชีวิตของบทที่ 7 คือ “ออกแบบทางออก” และการย้ายข้อมูลคือเวลาที่สมบูรณ์แบบที่จะใช้มัน อย่าแบกทุกเรกคอร์ดไปข้างหน้าเพียงเพราะมันมีอยู่

So zoom in on RouteDesk and take it apart, one class of data at a time. ⟲

Migrate, archive or discard A table of what's in RouteDesk, with a decision for each class of data. Deliveries not yet made, about 6,400 two days ahead: migrate, to Salesforce Work Orders, because the crews need them on Monday morning. Delivered inside the 60-day claim window, about 190,000: migrate, to Salesforce, so a claim's Case links to its Work Order. Delivered and older, about 4.8 million: archive, to Snowflake by the partner key, for claims and five-year reporting. Route plans and coordinators' drafts, eight years of them: discard by policy, once the business confirms nobody must keep them. The decision column is highlighted. Underneath: retiring a system isn't moving every record; know why every class of data moves, or doesn't. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-11", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "system-landscape/inventory 0.12.0", "theme": "stevetecharc 1.4.0"} WHAT'S IN ROUTEDESK HOW MUCH DECISION WHERE IT GOES, AND WHY Deliveries not yet made about 6,400 (two days ahead) Migrate Salesforce Work Orders: the crews need them on Monday morning Delivered, inside the 60-day claim window about 190,000 (60 days) Migrate Salesforce, so a claim's Case links to its Work Order Delivered, older about 4.8 million Archive Snowflake, by the partner key: claims and five-year reporting Route plans and coordinators' drafts eight years of them Discard, by policy Nowhere, once the business confirms nobody must keep them Retiring a system isn't moving every record. Know why every class of data moves, or doesn't. © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Every class of data gets a decision, a place and a reason. ⟲

The deliveries not yet made have to come in: manifests arrive one to two days ahead, so on cutover weekend RouteDesk holds about two days of work, roughly 6,400 deliveries, and the crews need them on Monday morning. The recent history comes in because of claims. A damage claim is a Case in Salesforce, and the agent working it needs the delivery behind it. So deliveries still inside the claim window come in too. Steve Trucking accepts claims for 60 days after a delivery, so that’s about 190,000 more Work Orders. Had the business said 30 days, it would be half that. The window is the business’s number, not ours. ⟲

The other 4.8 million deliveries go to Snowflake, where Checkpoint 1 already sends status history, kept by the partner key so a claim on an old delivery can still find it, and so leadership’s five-year reports still work. They don’t belong in the operational core: that would make Salesforce RouteDesk’s retirement home, and chapter 7 showed what Work Orders at volume cost. And the route plans and the coordinators’ drafts? Eight years of yesterday’s plans have no value once the deliveries are done. But I don’t decide that alone. ⟲

The opposite mistake is “we don’t need the old stuff.” Who decided? Legal, finance, operations, service, compliance? The data architect shouldn’t invent retention policy during a migration; we translate the business and regulatory requirement into architecture. Before excluding data, establish whether it must be kept, for how long, where, who needs access, and whether its relationships and source identifiers must survive. Eight years of Recipients’ names, addresses and phone numbers is exactly that kind of question: archiving them isn’t the same as keeping them forever. The goal isn’t to migrate less. It’s to know why every class of data is moving, or isn’t. ⟲

Test knowledge. Migrate what the new system needs to operate, not everything the old one held. Expect a scenario with years of legacy history: the answer is usually to migrate active and recent records and archive the rest outside Salesforce where it stays reachable, with the retention decision made by the business, not by the migration team. ⟲

Before the steps, the place. All of this preparation happens outside Salesforce, in a working database of its own: Postgres, SQL Server, Oracle, MySQL, even SQLite for a small job, whatever the team knows. Not in Salesforce, and not in a spreadsheet that gets emailed around. I call it the preparation data store, or the preparation store for short. It sits in between: the source feeds it, and it feeds Salesforce. ⟲

The preparation data store sits in between Three cards in a row. On the left, the source: RouteDesk, 8 years and about 5 million deliveries. In between, highlighted: the preparation data store, a database such as Postgres, SQL Server, Oracle or MySQL, where the data is standardized, cleaned, enriched, deduplicated and validated. On the right, the target: Salesforce, one US org. RouteDesk's extract goes into the preparation data store, kept raw; the preparation data store loads the result into Salesforce; and Salesforce sends back what's already there, and the IDs of what was loaded. Underneath: prepare outside, then load the result; the data store holds the source, the steps, and a copy of what Salesforce already has. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-16", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.3.0", "theme": "stevetecharc 1.4.0"} THE SOURCE IN BETWEEN THE TARGET RouteDesk 8 years, ~5 million deliveries Preparation data store Postgres, SQL Server, Oracle, MySQL: standardize, clean, enrich, dedupe, validate Salesforce one US org extract, kept raw load the result what's already there, and IDs back Prepare outside, then load the result. The data store holds the source, the steps, and a copy of what Salesforce already has. HOW TO READ IT where the preparation happens © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

The preparation data store sits in between. Every step in this module happens inside it. ⟲

The extract lands there raw. The standardizing, cleaning, enriching, deduping and validating all run there, as code. The quarantine is a table, the counts are queries, and the whole thing can be run again from the top. Some tools connect a database like this straight to Salesforce, copying data down and sending changes back; others export files for a data loader. There are many ways to load data. The principle doesn’t change: prepare it outside, then load the result. ⟲

And it holds more than the source. Pull down the relevant parts of the target org too. Why? Because dedupe has to compare against what’s already in Salesforce, and when the survivor of a merge is a record that’s already there, the new children need its key to link to it. You can’t decide the merge without both sides in front of you. For RouteDesk, the preparation store holds the RouteDesk extract and a copy of what Salesforce already has: the Retail Partner Accounts, the Products and Service Territories, the claim Cases with their delivery references, and the Work Orders the new integration has already created, because the partners don’t stop sending manifests for our cutover weekend. ⟲

Then you practice. Run the preparation, load a sandbox, reconcile, find the rule that was wrong, fix it, run it all again. By the time we reach production, the preparation has run many times, and it’s boring. That’s the goal. ⟲

ลำดับของผม: ทำให้เป็นมาตรฐาน ทำความสะอาด เพิ่มคุณค่า กำจัดข้อมูลซ้ำ ตรวจสอบความถูกต้อง

หัวข้อที่มีชื่อว่า “ลำดับของผม: ทำให้เป็นมาตรฐาน ทำความสะอาด เพิ่มคุณค่า กำจัดข้อมูลซ้ำ ตรวจสอบความถูกต้อง ”

When I’m preparing data for migration, I work in this order, and the order matters. All five steps happen in the preparation data store. ⟲

Standardize. Get equivalent values into one form. One source has CA, California and Calif.; another has US, USA and United States. A company comes in as Steve Plumbing, Steve's Plumbing and Steve's Plumbing LLC. Phone numbers arrive as 5555550142, (555) 555-0142 and +1 555 555 0142. Before we compare records or apply matching rules, we need to know which differences are formatting and which are meaningful. ⟲

Names are the classic trap. I had a system with first and last name in one field, and the Salesforce contact needs them apart. “Daniel Reyes” splits easily. Then you get “Mr. Daniel Reyes,” “Daniel Reyes PhD,” “Daniel Reyes III,” and names with two family names, such as Roberto González Suárez, where González isn’t a middle name: split that wrong and you’re in trouble. Build the patterns (two words, three words, a title, a suffix), run the splits, and have the customer validate the results. ⟲

ทำความสะอาด จัดการกับสิ่งที่ผิด ใช้ไม่ได้ หรือเลิกใช้แล้ว: รหัสที่ไม่ถูกต้อง วันที่ที่เป็นไปไม่ได้ คำสะกดผิด ค่าที่ใส่ไว้แทน ฟิลด์ที่เก็บข้อมูลไม่ตรงกับความหมายของมัน จับคู่ค่า picklist อย่างตั้งใจ: สถานะลูกค้าเป้าหมายเดิม Cold อาจกลายเป็น Closed ในปลายทาง เมื่อรายการยาว (ผมเคยเห็น 200 ค่า) ให้สร้างตารางการแปลง และให้ธุรกิจกรอกค่าปลายทางสำหรับแต่ละค่าต้นทาง Salesforce ตรวจสอบ picklist อย่างเข้มงวด จับให้ได้ก่อนมันมาถึง และอย่ารอให้กฎการตรวจสอบความถูกต้องบอกคุณว่าต้นทางมีอะไร

RouteDesk’s “quality varies by DC” shows up right here. Each DC set up its own status codes over eight years, so the same outcome arrives in nine spellings. The transformation table maps every one of them to the Work Order’s status values in Salesforce: ⟲

DCRouteDesk saysWork Order status
DC 1DLVCompleted
DC 4Delivered - OKCompleted
DC 7DONE/INSTCompleted (the install is on its line item)
DC 1NHCannot Complete (nobody home)
DC 4RefusedCannot Complete
DC 7CXLCanceled

The left two columns come from profiling the extract; the right column comes from the business, not from us. Completed, Cannot Complete and Canceled are three of the standard Work Order status values (WorkOrder (เปิดในแท็บใหม่), Object Reference, Winter ‘27, checked 2026-10-27). Notice the third row: one RouteDesk code carried two facts, the delivery and the install, and the target model keeps them apart. ⟲

Enrich. Sometimes missing information can be reliably added: a normalized address, a postal code from city and state, a county, a geolocation, a mapping from a legacy code to the new enterprise taxonomy, an enterprise identifier. Enrichment needs provenance. If we add or change information, I want to know where it came from and why I trust it. Some of RouteDesk’s older deliveries don’t name the Retail Partner at all, because each DC served one partner and everybody knew. The DC and the order number’s format tell us which partner it was. That’s enrichment from a rule we can show, not a guess. ⟲

กำจัดข้อมูลซ้ำ แล้วจึงหาเรกคอร์ดที่แทนสิ่งเดียวกันในโลกจริง ทำไมไม่เริ่มตรงนี้? เพราะการจับคู่ข้อมูลสกปรกยากกว่า: Steve's Plumbing กับ STEVES PLUMBING LLC เปรียบเทียบได้ง่ายกว่ามากหลังทำให้เป็นมาตรฐาน กำจัดข้อมูลซ้ำภายในข้อมูลที่เข้ามา แล้วกับสิ่งที่อยู่ใน Salesforce แล้ว กฎของบทที่ 6 ยังใช้ได้: การผสานเป็นการทำลาย การเชื่อมโยงไม่ใช่ อย่ายุบเรกคอร์ดรวมกันเพียงเพราะคะแนน fuzzy ดูน่าเชื่อ

Validate. Finally, test the transformed data against the target: required information present, reference values valid, relationships resolvable, keys unique where they should be, values fitting the model, authority rules preserved. Only then do I want to talk seriously about loading. And don’t expect the import tool to catch everything. Salesforce’s own Trailhead project on the NPSP importer makes the point: it catches invalid picklist values and missing required fields, but if a spreadsheet turned a postal code like 02134 into the number 2134, the importer loads the four digits (Perform an Import Dry Run (เปิดในแท็บใหม่), Trailhead, checked 2026-10-27). That’s one more reason the preparation lives in a database with typed columns, not in a spreadsheet. ⟲

Standardize, clean, enrich, dedupe, validate A funnel, top to bottom. RouteDesk's extract, from nine DCs, kept as it came out: the evidence. Standardize: nine DCs' status codes into one list, and one form for phones and addresses. Clean: impossible dates, placeholder phones, products typed by hand. Set aside to quarantine: a delivery with no partner order number, with no key to load it by. Enrich: the Retail Partner, from the DC and the order number. Dedupe: a revised manifest keyed in twice is one delivery, not two. Set aside, merged: the duplicate, with a plan for its stops and notes. Validate against Salesforce: keys unique, products and territories resolve. Set aside to quarantine: a line item whose product doesn't exist in Salesforce. At the bottom, highlighted: load-ready, and a count that reconciles to the extract. Underneath: bad records need somewhere to go, a quarantine with the reason, an owner and a deadline; not silently dropped, not forced in. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-12", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "funnel 0.2.0", "theme": "stevetecharc 1.4.0"} RouteDesk's extract, from nine DCs kept as it came out: the evidence Standardize nine DCs' status codes into one list; one form for phones and addresses Clean impossible dates, placeholder phones, products typed by hand Set aside: to quarantine a delivery with no partner order number: no key to load it by Enrich the Retail Partner, from the DC and the order number Dedupe a revised manifest keyed in twice is one delivery, not two Set aside: merged the duplicate, with a plan for its stops and notes Validate against Salesforce: keys unique, products and territories resolve Set aside: to quarantine a line item whose product doesn't exist in Salesforce Load-ready and a count that reconciles to the extract Bad records need somewhere to go: a quarantine with the reason, an owner and a deadline. Not silently dropped, not forced in. © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Five steps, in order. A record that fails one goes somewhere visible, with its reason. ⟲

Test knowledge. Data quality is fixed before the load, not after. Know the preparation steps (standardize, clean, enrich, deduplicate, validate) and why the order matters: you can’t match records reliably until their values are in one form. Picklist values are mapped with a transformation table the business signs off, because Salesforce rejects values a restricted picklist doesn’t have. ⟲

ความยั่วยวนคือ “เอาทุกอย่างเข้า Salesforce ก่อน แล้วค่อยทำความสะอาดทีหลัง” ผมไม่ชอบให้นั่นเป็นค่าเริ่มต้น เมื่อข้อมูลแย่ๆ อยู่ใน production แล้ว มันก็มีส่วนร่วมใน production: ผู้ใช้เห็น ระบบอัตโนมัติ รายงาน การผสานรวม และเอเจนต์เห็น ข้อมูลซ้ำเริ่มสะสมเรกคอร์ดที่เกี่ยวข้อง และการทำความสะอาดก็ยากขึ้น ในที่ที่ทำได้ ให้ปรับปรุงข้อมูลก่อนมันเข้าสู่ปลายทาง ไม่ใช่ทุกความไม่สมบูรณ์ในอดีตต้องแก้ นั่นคือการตัดสินใจด้านต้นทุนกับประโยชน์ แต่ “เราจะทำความสะอาดทีหลัง” ไม่ใช่กลยุทธ์การย้ายข้อมูล มันคือหนี้ทางเทคนิคที่มีวันเปิดตัว

And not every record deserves the same effort. An active customer with open orders, open cases, current contracts and billing relationships is different from one who bought something once nine years ago. Both may need to be kept. For the critical, active data I may require stricter validation, more enrichment, closer duplicate review and detailed reconciliation; for low-value history, preserving traceability may matter more than making every record perfect. Architecture is partly deciding where quality effort creates value. For RouteDesk, the 6,400 deliveries the crews will drive to on Monday get the strictest checks. The 4.8 million going to the archive need their keys and their dates right; nobody will fix eight years of typos in delivery notes. ⟲

หนึ่งในความผิดพลาดที่ง่ายที่สุดคือการสูญเสียความสามารถในการสืบย้อนเรกคอร์ด Salesforce กลับไปยังที่มาของมัน ถ้าลูกค้าเดิม CUST-847291 กลายเป็น Account 001… ผมก็ยังอยากรู้ว่ามันมาจาก CUST-847291 เพื่อการกระทบยอด การแก้ปัญหา การโหลดใหม่ การตรวจสอบ การจับคู่เรกคอร์ดลูก การวิเคราะห์การย้อนกลับ และคำถามที่มาถึงหลังเปิดใช้งาน Salesforce ID ใหม่สำคัญภายใน Salesforce แต่มันไม่ได้ลบตัวตนจากต้นทาง นี่คือหลักการ External ID จากบทที่ 9 การย้ายข้อมูลกับการผสานรวมพบกันที่ตัวตน

At Steve Trucking they meet in one field. Every Work Order already carries the partner’s key, Partner_Delivery_Key__c, an External ID marked unique, holding values like REDROCK-8472914-1 (chapter 9, module 2). RouteDesk kept the partner’s order number on each delivery, so the migration builds the same key and upserts on it, exactly as the integration does. That matters on cutover weekend: if Redrock resends a manifest for Tuesday after we’ve loaded Tuesday from RouteDesk, the integration finds the migrated Work Order and updates it instead of creating a second one. RouteDesk’s own delivery number comes along too, in a plain field, so anyone can trace a Work Order back to the record it came from. ⟲

So don’t rebuild relationships by name (“find the Account whose Name is Acme Distribution”). If the legacy contact carries Legacy_Account_ID = CUST-847291 and the Salesforce Account carries that identifier as an External ID, the relationship is rebuilt deterministically. The Bulk API does this in the load file itself: a column header such as WorkOrder.Partner_Delivery_Key__c says “find my parent by this indexed field,” and Salesforce looks up the parent’s ID for you (Relationship Fields in a Header Row (เปิดในแท็บใหม่), Bulk API 2.0 and Bulk API Developer Guide, checked 2026-10-27). Keys turn “I think this child belongs here” into “I know which parent this came from,” and that matters more as the Number of Zeros grows. ⟲

Relationships also create sequence. If contacts reference accounts, the accounts must exist first; if line items reference orders and products, those come first. So migration isn’t one giant load. It’s reference data, parents, children, junctions, then dependent history, in an order the target data model dictates. That’s one more reason the data architect belongs in migration planning: the model tells us how the migration has to be assembled. Here’s RouteDesk’s open work, on Checkpoint 1’s model. ⟲

The model sets the load order Four waves from left to right. Wave 1, already there or reference: Retail Partner Accounts, already in Salesforce; Service Territories, the nine DCs; Work Types: delivery, install, haul-away; and Products, the SKUs and services. Wave 2, the parent, highlighted: Work Orders, upserted by Partner_Delivery_Key__c, each pointing to its Retail Partner by the partner's key, its territory by DC code and its work type. Wave 3, its children: Service Appointments, the scheduled visit and window, pointing to their Work Order by the partner key; and Work Order Line Items, the items on each delivery, pointing to their Work Order by the partner key and to their Product by SKU. Wave 4, what points at it: claim Cases already in Salesforce, updated to point to their Work Order by the partner key. Underneath: parents before children, and every child finds its parent by a key, never by a name; the model sets the order. WAVE 1: ALREADY THERE, OR REFERENCE WAVE 2: THE PARENT WAVE 3: ITS CHILDREN WAVE 4: WHAT POINTS AT IT Products SKUs and services Retail Partner Accounts already in Salesforce Service Territories the nine DCs Work Types delivery, install, haul-away Parents before children, and every child finds its parent by a key, never by a name. The model sets the order. HOW TO READ IT the parent the migration builds around © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Wave 1: what the Work Orders will point to has to exist first. Most of it already does. ⟲

The model sets the load order Four waves from left to right. Wave 1, already there or reference: Retail Partner Accounts, already in Salesforce; Service Territories, the nine DCs; Work Types: delivery, install, haul-away; and Products, the SKUs and services. Wave 2, the parent, highlighted: Work Orders, upserted by Partner_Delivery_Key__c, each pointing to its Retail Partner by the partner's key, its territory by DC code and its work type. Wave 3, its children: Service Appointments, the scheduled visit and window, pointing to their Work Order by the partner key; and Work Order Line Items, the items on each delivery, pointing to their Work Order by the partner key and to their Product by SKU. Wave 4, what points at it: claim Cases already in Salesforce, updated to point to their Work Order by the partner key. Underneath: parents before children, and every child finds its parent by a key, never by a name; the model sets the order. WAVE 1: ALREADY THERE, OR REFERENCE WAVE 2: THE PARENT WAVE 3: ITS CHILDREN WAVE 4: WHAT POINTS AT IT Products SKUs and services Retail Partner Accounts already in Salesforce Service Territories the nine DCs Work Types delivery, install, haul-away Work Orders upsert by Partner_Delivery_Key__c by the partner's key by name of type by DC code Parents before children, and every child finds its parent by a key, never by a name. The model sets the order. HOW TO READ IT the parent the migration builds around © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Wave 2: the Work Orders, upserted by the partner key. ⟲

The model sets the load order Four waves from left to right. Wave 1, already there or reference: Retail Partner Accounts, already in Salesforce; Service Territories, the nine DCs; Work Types: delivery, install, haul-away; and Products, the SKUs and services. Wave 2, the parent, highlighted: Work Orders, upserted by Partner_Delivery_Key__c, each pointing to its Retail Partner by the partner's key, its territory by DC code and its work type. Wave 3, its children: Service Appointments, the scheduled visit and window, pointing to their Work Order by the partner key; and Work Order Line Items, the items on each delivery, pointing to their Work Order by the partner key and to their Product by SKU. Wave 4, what points at it: claim Cases already in Salesforce, updated to point to their Work Order by the partner key. Underneath: parents before children, and every child finds its parent by a key, never by a name; the model sets the order. WAVE 1: ALREADY THERE, OR REFERENCE WAVE 2: THE PARENT WAVE 3: ITS CHILDREN WAVE 4: WHAT POINTS AT IT Products SKUs and services Retail Partner Accounts already in Salesforce Service Territories the nine DCs Work Types delivery, install, haul-away Work Orders upsert by Partner_Delivery_Key__c Work Order Line Items the items on each delivery Service Appointments the scheduled visit and window by the partner's key by name of type by DC code by the partner key by SKU by the partner key Parents before children, and every child finds its parent by a key, never by a name. The model sets the order. HOW TO READ IT the parent the migration builds around © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Wave 3: the children, each finding its Work Order by the same key. ⟲

The model sets the load order Four waves from left to right. Wave 1, already there or reference: Retail Partner Accounts, already in Salesforce; Service Territories, the nine DCs; Work Types: delivery, install, haul-away; and Products, the SKUs and services. Wave 2, the parent, highlighted: Work Orders, upserted by Partner_Delivery_Key__c, each pointing to its Retail Partner by the partner's key, its territory by DC code and its work type. Wave 3, its children: Service Appointments, the scheduled visit and window, pointing to their Work Order by the partner key; and Work Order Line Items, the items on each delivery, pointing to their Work Order by the partner key and to their Product by SKU. Wave 4, what points at it: claim Cases already in Salesforce, updated to point to their Work Order by the partner key. Underneath: parents before children, and every child finds its parent by a key, never by a name; the model sets the order. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-13", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.3.0", "theme": "stevetecharc 1.4.0"} WAVE 1: ALREADY THERE, OR REFERENCE WAVE 2: THE PARENT WAVE 3: ITS CHILDREN WAVE 4: WHAT POINTS AT IT Products SKUs and services Retail Partner Accounts already in Salesforce Service Territories the nine DCs Work Types delivery, install, haul-away Work Orders upsert by Partner_Delivery_Key__c Work Order Line Items the items on each delivery Service Appointments the scheduled visit and window Claim Cases already in Salesforce: update the lookup by the partner's key by name of type by DC code by the partner key by SKU by the partner key by the partner key Parents before children, and every child finds its parent by a key, never by a name. The model sets the order. HOW TO READ IT the parent the migration builds around © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Wave 4: the claim Cases already in Salesforce get their link to the delivery. The model sets the order. ⟲

Test knowledge. Keep each legacy record’s key in an External ID field, load parents before children, and let each child find its parent by that key: an upsert on the External ID, and a relationship column in the load file (Parent.External_Id__c) instead of looking up Salesforce IDs. Reloads then update instead of duplicating, and every record traces back to its source. ⟲

เรกคอร์ดที่ถูกผสานต้องมีกลยุทธ์สำหรับเรกคอร์ดลูก

หัวข้อที่มีชื่อว่า “เรกคอร์ดที่ถูกผสานต้องมีกลยุทธ์สำหรับเรกคอร์ดลูก ”

นี่คือปัญหาที่คนประเมินต่ำไป การวิเคราะห์พบว่าลูกค้าเดิม A, B และ C คือลูกค้าคนเดียวกัน ปลายทางจึงได้ Account เดียว ได้ แต่ A มี 12 เคส B มี 4 คำสั่งซื้อ และ C มีผู้ติดต่อ 3 ราย ผสานเรกคอร์ดแม่ในเชิงแนวคิดโดยไม่ออกแบบการจับคู่เรกคอร์ดลูกใหม่ คุณก็แก้เรกคอร์ดแม่ได้แต่ทำความสัมพันธ์พัง การตัดสินใจกำจัดข้อมูลซ้ำทุกครั้งต้องมีกลยุทธ์สำหรับเรกคอร์ดลูก

RouteDesk has its own version. When a partner revised a manifest on the day, a coordinator sometimes keyed the delivery in again instead of editing it. Now RouteDesk has two deliveries with the same partner order number: one with the old window and two stops, one with the new window and the crew’s notes. Salesforce will have one Work Order, because the partner key is unique. Which window wins, and what happens to the stops and notes on the other one? ⟲

ก่อนอื่นคือฟิลด์: เมื่อสองเรกคอร์ดตรงกัน ค่าไหนชนะ? ค่าว่างกับค่าที่มีอยู่นั้นง่าย ความขัดแย้งไม่ง่าย: Steven หรือ Stephen อีเมลใน Salesforce หรืออีเมลในการโหลด? เลือกเรกคอร์ดที่รอดแล้วตัดสินทีละฟิลด์ จากนั้นนำกรณีตัวอย่างไปให้ธุรกิจดูตั้งแต่เนิ่นๆ เพื่อให้รอยนิ้วมือของพวกเขาอยู่บนการตัดสินใจ

Then the children. I see three options: add the children to the survivor, don’t load the merged record’s children, or load the merged record as inactive, linked to the survivor, with its children kept on it. ⟲

Three ways to handle a merged record's children Three equal panels, three ways to handle the children of a merged record. Add the children to the survivor, one record with everything: at RouteDesk, both deliveries' stops and notes move to the one Work Order; you get everything in one place, simple to use; it costs a merged record's history mixed in; choose it when a wrong merge is unlikely and the history matters. Don't load the merged record's children, a clean record: at RouteDesk, the duplicate's stops and notes stay in the archive; you get a clean record and nothing confusing; it costs that history, gone from Salesforce; choose it when nobody needs that history day to day. Load it inactive, linked to the survivor, an archive of its own history: at RouteDesk, the duplicate loads as canceled, pointing to the survivor, with its stops; you get every child traced and nothing lost; it costs a record that shows up in search and can confuse users, and it needs its own key; choose it when a wrong merge is costly and every child must be traced. Underneath: every merge needs a child strategy; weigh the benefit of joining the data against the risk of joining the wrong records. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-14", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "comparison 0.4.0", "theme": "stevetecharc 1.4.0"} Add the children to the survivor one record with everything AT ROUTEDESK Both deliveries' stops and notes move to the one Work Order YOU GET Everything in one place, simple to use IT COSTS The merged record's history is mixed in CHOOSE IT WHEN A wrong merge is unlikely and the history matters Don't load the merged record's children a clean record AT ROUTEDESK The duplicate's stops and notes stay in the archive YOU GET A clean record, and nothing confusing IT COSTS That history is gone from Salesforce CHOOSE IT WHEN Nobody needs that history day to day Load it inactive, linked to the survivor an archive of its own history AT ROUTEDESK The duplicate loads as canceled, pointing to the survivor, with its stops YOU GET Every child traced, nothing lost IT COSTS It shows up in search and can confuse users; it needs its own key CHOOSE IT WHEN A wrong merge is costly and every child must be traced Every merge needs a child strategy. Weigh the benefit of joining the data against the risk of joining the wrong records. © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Three ways, none free. Notice the third one at RouteDesk: the inactive duplicate can’t reuse the partner key, because the survivor already holds it, so it needs a key of its own. ⟲

Whichever you choose, it happens in the preparation store, before anything loads. That’s where the survivor is picked, sometimes a record that’s already in Salesforce, pulled down with its key. That’s where each child gets the key of the parent it will point to. And that’s where the merged record either keeps its children, hands them over or is left out. Salesforce receives the result of the merge, not the job of doing it. ⟲

ผมเลือกอย่างไร? ขึ้นอยู่กับว่าข้อมูลสำคัญแค่ไหน และเราต้องการสืบย้อนกลับไปยังสิ่งที่โหลดหรือไม่ และชั่งความเสี่ยงกับประโยชน์ของการผสานตั้งแต่แรก การรวมประวัติการซื้อของคนผิดสองคนในรายชื่อลูกค้าค้าปลีกเป็นความรำคาญ การแสดงยาของผู้ป่วยรายหนึ่งบนเวชระเบียนของผู้ป่วยอีกรายเป็นการละเมิดร้ายแรง ยิ่งเดิมพันของการจับคู่ผิดสูง การผสานยิ่งต้องระมัดระวัง ไม่ว่าคุณจะตัดสินใจอย่างไร เรกคอร์ดลูกแต่ละรายการยังสืบย้อนไปยังต้นทางเดิมได้ไหม? การกำจัดข้อมูลซ้ำในการย้ายข้อมูลไม่ใช่ “รันการจับคู่ข้อมูลซ้ำบน Accounts” กราฟความสัมพันธ์ทั้งหมดมีความสำคัญ

ผมเคยอยู่อีกฝั่งของเรื่องนี้ ร้านค้าปลีกที่ผมซื้อของมาตั้งแต่สมัยเรียนมหาวิทยาลัยกำลังย้ายข้อมูลลูกค้า และเมื่อเราดู Steve Simpson ปรากฏภายใต้อีเมลและที่อยู่ประมาณครึ่งโหล: ที่อยู่สมัยเรียน บ้านที่ผมเช่า และที่ต่อๆ มา ควรผสานไหม? มี Steve Simpson คนอื่นอยู่ในโลก ธุรกิจตัดสินว่าการรวมประวัติเก่าของผมเข้าด้วยกันไม่คุ้มกับความเสี่ยงที่จะผสานผมกับ Steve Simpson ผิดคน นั่นคือคำถามที่การผสานทุกครั้งต้องตอบ: ประโยชน์ของการรวมข้อมูลเข้าด้วยกันคืออะไร และความเสี่ยงของการเลือกคนผิดคืออะไร?

Test knowledge. Deduplicate before the load, within the incoming data and against what’s already in Salesforce, with matching rules and a survivor chosen field by field. Expect the follow-up question: what happens to the merged record’s child records? Re-parent them to the survivor, leave them out (and archive them), or keep them on an inactive linked record. Each has a cost. ⟲

สถานะเดิม A กลายเป็น Active I กลายเป็น Inactive S กลายเป็น Suspended การจับคู่นั้นอยู่ที่ไหน? ไม่ใช่ในความทรงจำของใคร ไม่ใช่ในสูตร Excel ที่คัดลอกต่างกันไปในสามไฟล์ ไม่ใช่ขั้นตอนที่ทำด้วยมือในคืนวันศุกร์ ถ้าเราโหลดใหม่พรุ่งนี้ เราควรได้ผลเดิม ดังนั้นการจับคู่ กฎการทำให้เป็นมาตรฐานและการทำความสะอาด การแปลง การตัดสินใจกำจัดข้อมูลซ้ำ และการสร้างคีย์ ต้องทำซ้ำได้ทั้งหมด กระบวนการย้ายข้อมูลคือโค้ด แม้บางส่วนจะไม่ได้เขียนด้วยภาษาโปรแกรมตามตัวอักษรก็ตาม

And don’t destroy the starting point. Keep the original extract in raw tables, exactly as it came out, and never change them. Each step writes its result to a new staged table: standardized, cleaned, deduplicated, load-ready. When something looks wrong, I want to know whether it was wrong in the source, changed by our transformation, changed by the load, or changed by Salesforce automation afterward, and with every table kept I can walk back through them and find out. Overwrite your only copy of the source while cleaning it and you lose the evidence. ⟲

I learned how much this pays off on a support migration. A company was moving its support desk from Zendesk into Salesforce, and Zendesk’s tickets were very similar to Salesforce Cases, but not exact. So I loaded every Zendesk export into a SQL database as raw tables, one per Zendesk structure: organizations, users, tickets, custom fields, comments, attachments. Then I built interim tables that got closer and closer to the Salesforce structure, with the field and picklist mappings kept as tables of their own. Then I loaded Salesforce from those tables and brought the Salesforce IDs back. In the end every row had three things: its original Zendesk key, the transformations that had been applied to it, which were never one way, and its Salesforce key. That’s what let me do partial loads and reloads whenever I needed to. ⟲

Here’s the same design for RouteDesk, one step at a time. ⟲

Three sets of keys Four columns from left to right. RouteDesk: deliveries keyed by the RouteDesk delivery number, delivery items by item number, stops by stop number. The preparation store's raw tables, unchanged: rd_delivery, rd_item and rd_stop, each as extracted with its key. The preparation store's tables shaped for Salesforce: sf_work_order, with the partner key built and the status mapped; sf_work_order_line_item, with the product mapped by SKU; sf_service_appointment, with the window and territory; generated from the raw tables, with the mapping tables for status and product, signed off by the business, in amber. Salesforce: Work Orders, highlighted, with the Salesforce ID, the partner key and the RouteDesk number, upserted; Work Order Line Items and Service Appointments, inserted. Last, navy arrows bring each Salesforce ID back to its row in the shaped tables. Underneath: source keys, the transforms, and the Salesforce keys, all kept; now you can reload, load a part, or trace any record back to where it came from. ROUTEDESK PREPARATION STORE: RAW PREPARATION STORE: SALESFORCE SHAPE SALESFORCE Deliveries key: RouteDesk delivery number Delivery items key: item number Stops key: stop number rd_delivery as extracted, with its key rd_item as extracted, with its key rd_stop as extracted, with its key extract extract extract Source keys, the transforms, and the Salesforce keys, all kept. Now you can reload, load a part, or trace any record back to where it came from. HOW TO READ IT a transformation table: the rule, kept as data the Salesforce ID, written back to its row © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Extract: one raw table per RouteDesk structure, each row with its RouteDesk key. These tables never change. ⟲

Three sets of keys Four columns from left to right. RouteDesk: deliveries keyed by the RouteDesk delivery number, delivery items by item number, stops by stop number. The preparation store's raw tables, unchanged: rd_delivery, rd_item and rd_stop, each as extracted with its key. The preparation store's tables shaped for Salesforce: sf_work_order, with the partner key built and the status mapped; sf_work_order_line_item, with the product mapped by SKU; sf_service_appointment, with the window and territory; generated from the raw tables, with the mapping tables for status and product, signed off by the business, in amber. Salesforce: Work Orders, highlighted, with the Salesforce ID, the partner key and the RouteDesk number, upserted; Work Order Line Items and Service Appointments, inserted. Last, navy arrows bring each Salesforce ID back to its row in the shaped tables. Underneath: source keys, the transforms, and the Salesforce keys, all kept; now you can reload, load a part, or trace any record back to where it came from. ROUTEDESK PREPARATION STORE: RAW PREPARATION STORE: SALESFORCE SHAPE SALESFORCE Deliveries key: RouteDesk delivery number Delivery items key: item number Stops key: stop number rd_delivery as extracted, with its key rd_item as extracted, with its key rd_stop as extracted, with its key Mapping tables status and product, signed off by the business sf_work_order partner key built, status mapped sf_work_order_line_item product mapped by SKU sf_service_appointment window and territory extract extract extract generate generate generate status product Source keys, the transforms, and the Salesforce keys, all kept. Now you can reload, load a part, or trace any record back to where it came from. HOW TO READ IT a transformation table: the rule, kept as data the Salesforce ID, written back to its row © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Generate: new tables shaped for Salesforce, built from the raw ones with the mapping tables. The raw tables are still there. ⟲

Three sets of keys Four columns from left to right. RouteDesk: deliveries keyed by the RouteDesk delivery number, delivery items by item number, stops by stop number. The preparation store's raw tables, unchanged: rd_delivery, rd_item and rd_stop, each as extracted with its key. The preparation store's tables shaped for Salesforce: sf_work_order, with the partner key built and the status mapped; sf_work_order_line_item, with the product mapped by SKU; sf_service_appointment, with the window and territory; generated from the raw tables, with the mapping tables for status and product, signed off by the business, in amber. Salesforce: Work Orders, highlighted, with the Salesforce ID, the partner key and the RouteDesk number, upserted; Work Order Line Items and Service Appointments, inserted. Last, navy arrows bring each Salesforce ID back to its row in the shaped tables. Underneath: source keys, the transforms, and the Salesforce keys, all kept; now you can reload, load a part, or trace any record back to where it came from. ROUTEDESK PREPARATION STORE: RAW PREPARATION STORE: SALESFORCE SHAPE SALESFORCE Deliveries key: RouteDesk delivery number Delivery items key: item number Stops key: stop number rd_delivery as extracted, with its key rd_item as extracted, with its key rd_stop as extracted, with its key Mapping tables status and product, signed off by the business sf_work_order partner key built, status mapped sf_work_order_line_item product mapped by SKU sf_service_appointment window and territory Work Orders Salesforce ID, partner key, RouteDesk number Work Order Line Items Salesforce ID Service Appointments Salesforce ID extract extract extract generate generate generate status product upsert insert insert Source keys, the transforms, and the Salesforce keys, all kept. Now you can reload, load a part, or trace any record back to where it came from. HOW TO READ IT a transformation table: the rule, kept as data the Salesforce ID, written back to its row © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Load: the Work Orders upserted by the partner key, then their children. ⟲

Three sets of keys Four columns from left to right. RouteDesk: deliveries keyed by the RouteDesk delivery number, delivery items by item number, stops by stop number. The preparation store's raw tables, unchanged: rd_delivery, rd_item and rd_stop, each as extracted with its key. The preparation store's tables shaped for Salesforce: sf_work_order, with the partner key built and the status mapped; sf_work_order_line_item, with the product mapped by SKU; sf_service_appointment, with the window and territory; generated from the raw tables, with the mapping tables for status and product, signed off by the business, in amber. Salesforce: Work Orders, highlighted, with the Salesforce ID, the partner key and the RouteDesk number, upserted; Work Order Line Items and Service Appointments, inserted. Last, navy arrows bring each Salesforce ID back to its row in the shaped tables. Underneath: source keys, the transforms, and the Salesforce keys, all kept; now you can reload, load a part, or trace any record back to where it came from. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.46.0", "built": "2026-10-27", "id": "DGM-DA-MG-15", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "cells 0.3.0", "theme": "stevetecharc 1.4.0"} ROUTEDESK PREPARATION STORE: RAW PREPARATION STORE: SALESFORCE SHAPE SALESFORCE Deliveries key: RouteDesk delivery number Delivery items key: item number Stops key: stop number rd_delivery as extracted, with its key rd_item as extracted, with its key rd_stop as extracted, with its key Mapping tables status and product, signed off by the business sf_work_order partner key built, status mapped sf_work_order_line_item product mapped by SKU sf_service_appointment window and territory Work Orders Salesforce ID, partner key, RouteDesk number Work Order Line Items Salesforce ID Service Appointments Salesforce ID extract extract extract generate generate generate status product upsert insert insert ID back ID back ID back Source keys, the transforms, and the Salesforce keys, all kept. Now you can reload, load a part, or trace any record back to where it came from. HOW TO READ IT a transformation table: the rule, kept as data the Salesforce ID, written back to its row © 2026 Twinshark LLC · stevetecharc.com
คลิกเพื่อขยาย

Keys back: each Salesforce ID is written to its row. Now every row knows where it came from, what was done to it and where it landed. ⟲

So no transformation is allowed to lose fidelity. If a step throws information away (truncates a note, drops a code it didn’t recognize, keeps one of two conflicting values without saying which), I can’t trace back through it, and I can’t repeat the run and get the same answer. Keep the raw tables, keep the staged tables, keep what each load sent and what came back. Then you can rerun the whole thing from the raw extract at any time, and you have the history of every load. This is migration’s version of lineage: preserve where the data came from and what you did to it. ⟲

The preparation store isn’t the only place to stage. In a few special cases, the last stop before the real objects is a plain custom object inside Salesforce: one flat row per source record, no automation, loaded fast. Then a batch process works through the rows and builds the real records. I’ve used it when Salesforce’s own logic had to create the records and was too slow to load through: a scheduling process that took a few seconds per appointment. Module 3 comes back to that case. ⟲

Salesforce uses the same pattern in its own products, and it’s worth learning from. The Nonprofit Success Pack loads a spreadsheet into its NPSP Data Import object first. A dry run checks for matches without creating anything. Then the importer creates the accounts, contacts and donations, and writes each new record’s ID back onto the row it came from (How the Import Process Works (เปิดในแท็บใหม่), Salesforce Help, checked 2026-10-27). That’s a reference, not a rule: staging inside Salesforce is the special case, not the way to load everything. ⟲

For RouteDesk, a one-time move with heavy cleaning and merging, the preparation store outside Salesforce does the work, and the load sends the result. ⟲

จาก 500,000 เรกคอร์ด 497,800 ผ่านการตรวจสอบ และ 2,200 ไม่ผ่าน ทิ้งไปเงียบๆ? ไม่ ยัดขยะลงในฟิลด์ที่จำเป็น? ไม่ หยุดโครงการจนกว่าเรกคอร์ดประวัติทุกรายการจะสมบูรณ์? คงไม่ ผมต้องการเส้นทางกักกันและแก้ไขที่บันทึกว่าเรกคอร์ดต้นทางไหนล้มเหลว เพราะอะไร กฎไหนปฏิเสธ ต้องแก้ก่อนสลับระบบหรือไม่ ใครเป็นเจ้าของการตัดสินใจ และเลื่อนออกไปได้หรือไม่ ตอนนี้ข้อยกเว้นกลายเป็นงานสถาปัตยกรรมที่มองเห็นได้ แทนที่จะเป็นข้อมูลที่หายไปอย่างซ่อนเร้น

Before you call a record bad, look at the rule that rejected it. Sometimes the record is fine and the rule is wrong. Salesforce’s Well-Architected framework puts it plainly: “data architecture decisions determine the populations that become visible—and invisible,” and a required email address “excludes populations that don’t have reliable internet access or personal email addresses” (Fairness (เปิดในแท็บใหม่), checked 2026-10-27). RouteDesk has thousands of deliveries where the Recipient gave only a phone number. If the new Work Order requires an email, those aren’t bad records. They’re real people the rule would make invisible. Fix the rule, not the person. ⟲

แล้วพิสูจน์การแปลงก่อนโหลด เราเริ่มด้วยเรกคอร์ดต้นทางกี่รายการ ตั้งใจตัดออกกี่รายการ รวมข้อมูลซ้ำไปกี่รายการ พร้อมแล้วกี่รายการ ถูกกักกันกี่รายการ ความสัมพันธ์แม่-ลูกหาคู่ได้กี่รายการ และยอดควบคุมเป็นเท่าไร? ถ้าตัวเลขกระทบยอดไม่ได้ก่อนการโหลด การโหลดให้เร็วขึ้นก็ไม่ช่วย โมดูลที่ 4 พิสูจน์การย้ายข้อมูลด้วยจำนวน ยอดรวม การสุ่มตรวจ และรายงานสรุปรวม แต่การพิสูจน์เริ่มที่นี่

AI ช่วยทำความสะอาดได้ แต่ไม่ได้รับสิทธิ์สร้างความจริงขึ้นมาเอง

หัวข้อที่มีชื่อว่า “AI ช่วยทำความสะอาดได้ แต่ไม่ได้รับสิทธิ์สร้างความจริงขึ้นมาเอง ”

AI มีประโยชน์ในการย้ายข้อมูล: แนะนำการจับคู่ฟิลด์ หาค่าที่น่าสงสัย จัดกลุ่มข้อมูลที่อาจซ้ำ สังเกตความผิดปกติ สร้างโค้ดการแปลง อธิบายแพตเทิร์นในเรกคอร์ดที่ถูกปฏิเสธ แต่ถ้ากระบวนการเพิ่มคุณค่าตัดสินว่า “บริษัทนี้น่าจะอยู่ในแอริโซนา” คำว่าน่าจะยังไม่พอ และถ้ามันตัดสินว่าลูกค้าสองรายดูคล้ายกันพอจะผสาน จำบทที่ 6 ไว้: การจับคู่ผิดสร้างความเสียหายได้มากกว่าการจับคู่น้อยไป ใช้ AI เพื่อเร่งการสืบสวน อย่าปล่อยให้มันผลิตข้อมูลองค์กรที่มีอำนาจชี้ขาดขึ้นมาอย่างเงียบๆ

นอกเหนือจากการสอบ: AI เปลี่ยนอะไร AI เร่งการทำโปรไฟล์ข้อมูล การจับคู่ฟิลด์ การตรวจจับความผิดปกติ และการจับคู่ตัวเลือกระหว่างการย้ายข้อมูลได้อย่างมาก จงรักษากฎแบบ deterministic แหล่งที่มา และการตรวจทานโดยมนุษย์ไว้รอบการตัดสินใจที่สร้าง ผสาน หรือเปลี่ยนข้อมูลธุรกิจที่มีอำนาจชี้ขาด

  • ข้อมูลต้นทางไหนถูกย้าย จัดเก็บถาวร หรือตัดออก ตามคุณค่าทางธุรกิจและข้อกำหนดการเก็บรักษา
  • Where preparation happens (a preparation store outside Salesforce, a staging object inside it, or both), and which parts of the target org are pulled down to merge against. ⟲
  • ข้อมูลถูกทำให้เป็นมาตรฐาน ทำความสะอาด เพิ่มคุณค่า กำจัดข้อมูลซ้ำ และตรวจสอบความถูกต้องอย่างไรก่อนเข้าสู่ปลายทาง
  • ตัวระบุจากต้นทางและ lineage ไหนรอดไปด้วย เพื่อให้เรกคอร์ดปลายทางที่สำคัญทุกรายการสืบย้อนและกระทบยอดได้
  • The load order the target data model dictates, and the keys each child uses to find its parent. ⟲
  • การตัดสินใจกำจัดข้อมูลซ้ำจัดการฟิลด์และเรกคอร์ดลูกทั่วทั้งกราฟความสัมพันธ์อย่างไร โดยชั่งความสำคัญ ความสามารถในการสืบย้อน และความเสี่ยงของการผสานผิด
  • กฎการแปลงและการจัดการข้อยกเว้นไหนต้องทำซ้ำได้ ก่อนการโหลด production ใดๆ จะเริ่ม

“เราโหลด 500,000 จาก 500,000 เรกคอร์ด” บอกผมว่าเครื่องมือโหลดทำงาน ผมอยากรู้ว่า: เราย้ายข้อมูลที่ถูกต้องไหม ปรับปรุงสิ่งที่ต้องปรับปรุงไหม รักษาตัวตนและความสัมพันธ์ไหม รวมข้อมูลซ้ำอย่างปลอดภัยไหม? เราอธิบายสิ่งที่ตัดออก ทำการแปลงซ้ำ สืบย้อนเรกคอร์ด Salesforce ไปยังต้นทาง และพิสูจน์ผลลัพธ์ได้ไหม? ทำงานนั้นก่อน แล้วค่อยกังวลว่าเราจะโหลดได้เร็วแค่ไหน