The Clean SQL

ถ้าจะถามภาษาที่นิยมที่สุด มาเป็นเวลาอย่างยาวนานแล้ว มันมีภาษานึงครับที่ยอดฮิตตั้งแต่อดีตจนถึงปัจจุบัน และในอนาคตอีกหลาย 10 ปีครับ ภาษานั้นก็คือ ภาษา SQL ครับ สำหรับตัว SQL หรือ Structured Query Language มีไว้ เพื่อจัดการกับข้อมูลเป็นหลักครับ แม้ว่าตัว SQL ช่วยให้เราจัดการชีวิตได้ง่ายขึ้นแล้ว อยากได้ข้อมูลเขียน

SELECT * FROM TABLE WHERE CONDITION

ได้ข้อมูลมาแล้วครับ ถ้าในยุคแรกๆนี้เขียน Relational Algebra เพื่อมาหาข้อมูลกันเลย

แต่ตัว SQL มันมีปัญหาในตัวเองครับ

  • กว่าจะรู้ว่าเขียน Query ไม่ใช่ตอน Complie Time นะครับ แต่เป็นตอน Run Time
  • จากข้อที่แล้ว ปัญหานี้แก้ได้โดยการใช้ ORM เข้ามาช่วยครับ แต่มันช่วยได้ระดับนึงครับ
  • เพราะ งานจริงๆ SQL มันไม่ได้สั้นๆ 2-3 บรรทัดครับ แต่มันยาว 1 หน้า A4 ครับ

SQL ที่ไม่ดีเป็นยังไง

  • อ่านยาก  SQL ขนาด 1 หน้า A4 แต่ย่อตบๆให้เหลือ 2 บรรทัด
  • การตั้งชื่อตัวแปร หรือ Alias ที่ไม่สื่อความหมายเลย

ทำยังไงใช้ SQL มัน Clean ได้หละ

  • Naming ตั้งชื่อให้มันสื่อ
    • Column นี้ เพื่ออะไร AccountCode หรือ A-Code ชื่อไหนง่ายกว่ากัน
    • Alias ไม่ต้องตั้ง A B C D ตั้งชื่อย่อ ที่เราและทีมที่ทำด้วยกัน เข้าใจครับ
  • ชื่อ Column , Table ใช้ camelCase ก็ได้ อย่าไปใช้ - มันมีปัญหากับพวก ORM บางตัว
    • Bad
      select stdacc.account-code
    • Good
      select stdacc.accountCode
  • ชื่อ Function หรือ Store Procudure ตั้งให้มันชัดเจนไปเลย อาจจะใช้เป็น Verb มาช่วยอธิบาย
    • Bad - fn_exchangeRate()
    • Good - getExchangeRate () //อันนี้น่าเข้าใจง่ายกว่านะ
  • จัด Format บ้าง ใช้มีเยื้อง มี Tab ให้อ่านง่ายครับ
    • Bad
      select invin.investTxId, portin.purpose   as purposeTransferIn, invout.investtxid, portout.purpose  as purposeTransferOut, invout.orgCostPerUnit, invin.costAmount, invin.unit 
      from   investtx invin
        left outer join portfolio portin on portin.portfolioId = invin.portfolioId and portin.activeFlag = 'A'
        left outer join investtx invout on invout.investTxId = invin.refInvestTxId
        left outer join portfolio portout on portout.portfolioId = invout.portfolioId and portout.activeFlag = 'A' 
      where  invin.investTxId = 64484
    • Good
      select invin.investTxId
           , portin.purpose   as purposeTransferIn
           , invout.investtxid
           , portout.purpose  as purposeTransferOut
           , invout.orgCostPerUnit
           , invin.costAmount
           , invin.unit 
      from   investtx invin
        left outer join portfolio portin
          on portin.portfolioId = invin.portfolioId
            and portin.activeFlag = 'A'
        left outer join investtx invout
          on invout.investTxId = invin.refInvestTxId
        left outer join portfolio portout
          on portout.portfolioId = invout.portfolioId
            and portout.activeFlag = 'A' 
      where  invin.investTxId = 64484
  • ถ้า SQL ยาวๆ และซับซ้อนควรมี Comment บอกด้วย ว่า Join มาเพื่ออะไร
    • ถ้าใช้งานบ่อยๆ มี 10 Query ที่ต้อง Join Table Portfolio Company ประจำ เราสามารถแยกเป็น View ก็ได้นะ
  • ใน T-SQL ใช้ CTE เท่าที่จำเป็น ถ้ามี CTE ที่ใช้งานเรื่องเดียวกันบ่อย ถ้าไปแปะแยกตามแต่ละ Query มันจะ Maintain ยาก พยายามย้ายไปเป็น Function หรือ Store Procedure
  • Business บางอย่างของระบบ ถ้ามีโอกาสแก้บ่อย หรือตัวระบบเองใช้กับ DBMS ได้หลายค่าย ให้ยกไปไว้ในส่วนของ Application จัดการดีกว่าครับ ยอมเสีย Performance (ถ้าจัดการในตัว DBMS บางงานทำได้เร็วกว่า การส่งข้อมูลโยนให้ Application ครับ) แต่แลกมาด้วยการ Maintain ที่ง่าย มี Code ที่ต้องตามแก้ไขน้อยครับ

จำไว้เสมอว่าเขียน Code ไว้ เพื่อให้คนอื่นอ่าน
เพราะ มันช่วยลดเวลาในการทำความเข้าใจได้เยอะครับ
เมื่อ เราต้องกลับมาแก้ไขมันอีกครั้งครับ

Reference


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.