[SQL] เมื่อ JOIN ผสมกับ CASE WHEN

วันนี้ระหว่างทำ DS_FTA ลองอ่าน ฺBOT Manual และก็เริ่มลงมือ Query ดึงข้อมูลเลยครับ พอมีข้อมูลแล้วมีกำลังใจเขียน Code ต่อครับ ไม่งั้นมืดมน เพราะ User เองก็ไม่รู้ว่าต้องส่งอะไรให้ BOT แต่พอเขียน Query ไปได้สัก 80% ช่วงประมาณ 4 โมงเย็น อยู่ๆ มี Idea ทำไมเราไม่ลองใช้ CASE WHEN ในการเขียน JOIN Table หละ ถ้ามันทำได้นี่ มันทำให้เราพลิกแพลงได้เยอะมากครับ

ขั้นแรก มาลองหาข้อมูลกันก่อนว่ามีชาวบ้านเค้าทำไหม ? ปรากฏว่ามีด้วยแหละ

เท่าที่ดูเป็นของ MS SQL Server ที่มี และเท่าที่ดู Syntax มันไม่ได้มีคำสั่งเฉพาะตัวนะ เอาหละ พร้อมจะลุยกันดีกว่า โดยสิ่งที่ผมทำ เป็นลักษณะ ดังนี้ครับ

  • แบบเดิม - JOIN แบบปกติ
SELECT A.*
FROM TABLE_A A
  INNER JOIN TABLE_B B
    ON A.COL1 = B.COL1

  • แบบใหม่ - ลองใช้ CASE WHEN ครับ
SELECT A.*
FROM TABLE_A A
  INNER JOIN TABLE_B B
    ON A.COL1 = (
      CASE  WHEN A.COL2 = 'XXX' OR A.COL2 = 'YYY' THEN 'N'
            WHEN A.COL2 = 'AAA' OR A.COL2 = 'BBB' THEN 'E'
               ELSE 'Y'
         END
       )

มาลองดูโจทย์ในการทำงานจริงของผมดีกว่า (แต่ปรับย่อมาลงมาครับ) ผมมีโจทย์อยู่ว่า หา Leg Type กับ Transaction ที่มีในระบบครับ

  • ข้อมูล Leg Type ของ BOT ครับ
CodeValueDescription
182001Buy Foreign Currencyนิติบุคคลรับอนุญาตซื้อเงินตราต่างประเทศแลกกับสกุลเงินบาท
182002Sell Foreign Currencyนิติบุคคลรับอนุญาตขายเงินตราต่างประเทศแลกกับสกุลเงินบาท
182003Cross Currencyการซื้อขายระหว่างเงินตราต่างประเทศ 2 สกุล
  • ข้อมูล Transaction
Portfolio CodeTransaction TypeFI Arrangement NumberExchange RateCommodity CurrencyCommodity AmountQuote CurrencyQuote Amount
PING-RISK-MGBUYSO52-2016070335.5328THB3,553,280USD100,000
PING-RISK-MGSELLSO53-2016070335.5328USD100,000THB3,553,280
PING-RISK-MGBUYSO54-2016070332.3974EUR100,000THB3,239,740
PING-RISK-MGSELLSO55-2016070332.3974EUR100,000THB3,239,740
PING-RISK-MGBUYSO56-201607031.0968EUR100,000USD109,680
PING-RISK-MGSELLSO57-201607030.1504CNY2,000,000USD300,800
  • ออกแบบ Table
CREATE TABLE INVESTTX(
     `PortfolioCode` varchar(12)
   , `TransactionType` varchar(4)
   , `FIArrangementNumber` varchar(13)
   , `ExchangeRate` Decimal(11,6)
   , `CommodityCurrency` varchar(3)
   , `CommodityAmount` Decimal(24,6)
   , `QuoteCurrency` varchar(3)
   , `QuoteAmount` Decimal(24,6)
);
    
INSERT INTO INVESTTX(
     `PortfolioCode`
   , `TransactionType`
   , `FIArrangementNumber`
   , `ExchangeRate`
   , `CommodityCurrency`
   , `CommodityAmount`
   , `QuoteCurrency`
   , `QuoteAmount`)
VALUES
    ('PING-RISK-MG', 'BUY', 'SO52-20160703', 35.5328, 'THB', 3553280, 'USD', 100000),
    ('PING-RISK-MG', 'SELL', 'SO53-20160703', 35.5328, 'USD', 100000, 'THB', 3553280),
    ('PING-RISK-MG', 'BUY', 'SO54-20160703', 32.3974, 'EUR', 100000, 'THB', 3239740),
    ('PING-RISK-MG', 'SELL', 'SO55-20160703', 32.3974, 'EUR', 100000, 'THB', 3239740),
    ('PING-RISK-MG', 'BUY', 'SO56-20160703', 1.0968, 'EUR', 100000, 'USD', 109680),
    ('PING-RISK-MG', 'SELL', 'SO57-20160703', 0.1504, 'CNY', 2000000, 'USD', 300800)
;

CREATE TABLE MappingLegType(
    `TransactionType` varchar(4)
  , `ISCrossCurrency` varchar(1)
  , `BOTCode` int
  , `BOTValue` varchar(21)
  , `BOTDescription` varchar(56)
);
    
INSERT INTO MappingLegType(
    `TransactionType`
  , `ISCrossCurrency`
  , `BOTCode`
  , `BOTValue`
  , `BOTDescription`)
VALUES
    ('BUY', 'N', 182001, 'Buy-Foreign-Currency', 'นิติบุคคลรับอนุญาตซื้อเงินตราต่างประเทศแลกกับสกุลเงินบาท'),
    ('SELL', 'N', 182002, 'Sell-Foreign-Currency', 'นิติบุคคลรับอนุญาตขายเงินตราต่างประเทศแลกกับสกุลเงินบาท'),
    ('BUY', 'Y', 182003, 'Cross-Currency', 'การซื้อขายระหว่างเงินตราต่างประเทศ-2-สกุล'),
    ('SELL', 'Y', 182003, 'Cross-Currency', 'การซื้อขายระหว่างเงินตราต่างประเทศ-2-สกุล')
;
  • ลองเขียน Query ครับ
SELECT ITX.PortfolioCode
     , ITX.TransactionType
     , ITX.FIArrangementNumber
     , LEGTYPE.BOTCode
     , LEGTYPE.BOTValue
     , ITX.CommodityCurrency
     , ITX.QuoteCurrency
     , ITX.ExchangeRate
     , ITX.CommodityAmount
     , ITX.QuoteAmount
FROM INVESTTX ITX
  LEFT OUTER JOIN MappingLegType LEGTYPE
    ON LEGTYPE.ISCrossCurrency = (
      CASE  WHEN ITX.CommodityCurrency = 'THB' OR ITX.QuoteCurrency = 'THB' THEN 'N' 
               ELSE 'Y'
         END
       )
       AND LEGTYPE.TransactionType = ITX.TransactionType
  • สำหรับตัวอย่างผม ทำไว้ใน SQL Fiddle โดยผมได้ทดสอบบน MySQL
  • สำหรับ MS SQL Server ผมได้ลองใน VM แล้วครับ หากใครอยากทดสอบลองแก้ Table และปรับ Syntax ดูครับ
  • ส่วนอันนี้เป็น Query ที่ผมเขียนบน DB2 ครับ ยังไม่ Optimize อะไร
SELECT  ITX.PORTFOLIOID
      , P.PORTFOLIOCODE
      , P.PURPOSE                  AS PORTFOLIOTYPEID
      , PORTTYPE.NAME              AS PORTFOLIOTYPECODE
      , ITX.INVESTTXID
      , ITX.INVESTTXNO
      , ITX.SECURITYID
      , SEC.SECURITYCODE
      , UNDSEC.UNDERLYINGTYPECODE
      , INDEXTYPE.INDEXINVOLVEMENTTYPECODE
      , ITX.BROKERID
      , BR.BROKERCODE              AS BROKERCODE
      , BRCOM.DSET_ORGANIZATIONID  AS BROKERORGANIZATIONID
      , BRUNIQUEIDTYPE.CODE        AS BROKERUNIQUEIDTYPECODE
      , ITX.COUNTERPARTYID
      , CTP.COUNTERPARTYCODE       AS COUNTERPARTYCODE
      , CTPCOM.DSET_ORGANIZATIONID AS COUNTERPARTYORGANIZATIONID
      , CTPUNIQUEIDTYPE.CODE       AS COUNTERPARTYUNIQUEIDTYPECODE
      , EX.BOTFUTUREMARKETCODE     AS FUTUREMARKETCODE
      , EX.EXCHANGETYPE
      , ITX.TRADEDATE
      , SEC.MATURITYDATE
      , ITX.INVESTTXTYPEID
      , ITX.FUTURESPRICE
      , ITX.UNIT                   AS NOOFCONTRACT
      , FTA.MULTIPLIER 
      , ITX.EXCHANGERATE
      , ITX.CURRENCYID             AS COMMODITYCCYID
      , COMCCY.CURRENCYCODE        AS COMMODITYCCYCODE
      , FTA.QUOTED                 AS QUOTECCYID
      , QUOTECCY.CURRENCYCODE      AS QUOTECCYCODE
      , LEGTYPE.LEGTYPECODE        AS LEGTYPECODE
 FROM INVESTTX ITX
   LEFT OUTER JOIN PORTFOLIO P  
     ON ITX.PORTFOLIOID = P.PORTFOLIOID
       AND P.ACTIVEFLAG = 'A'
   --JOIN TO FIND PORTFOLIO TYPE 10010017
   LEFT OUTER JOIN SYSTEMLOOKUP PORTTYPE
     ON P.PURPOSE = PORTTYPE.ID
       AND PORTTYPE.LOOKUPCATEGORYID = 10010017
       AND PORTTYPE.ACTIVEFLAG = 'A'
   --JOIN TO FIND PORTFOLIO TYPE 10010017 
   LEFT OUTER JOIN SECURITY SEC  
     ON ITX.SECURITYID = SEC.SECURITYID
       AND SEC.ACTIVEFLAG = 'A'
   LEFT OUTER JOIN SECURITYTYPE ST
     ON SEC.SECURITYTYPEID = ST.SECURITYTYPEID
       AND ST.ACTIVEFLAG = 'A'
   LEFT OUTER JOIN INVESTMENT INV
     ON ST.INVESTMENTID = INV.INVESTMENTID
       AND INV.ACTIVEFLAG = 'A'
   --JOIN FUTURES MASTER
   LEFT OUTER JOIN FUTURES FTA
     ON SEC.SECURITYID = FTA.SECURITYID
       AND FTA.ACTIVEFLAG = 'A'
   LEFT OUTER JOIN UNDERLYINGSECURITY UNDSEC
     ON FTA.UNDERLYINGSECURITYID = UNDSEC.UNDERLYINGSECURITYID
       AND UNDSEC.ACTIVEFLAG = 'A'
   --JOIN FUTURES MASTER
   --JOIN BROKER DATA
   LEFT OUTER JOIN BROKER BR
     ON ITX.BROKERID = BR.COMPANYID
       AND BR.ACTIVEFLAG = 'A'
   LEFT OUTER JOIN COMPANY BRCOM 
     ON BR.COMPANYID = BRCOM.COMPANYID
       AND BRCOM.ACTIVEFLAG = 'A'
   --FIND UNIQUE ID TYPE 10026094
   LEFT OUTER JOIN SYSTEMLOOKUP BRUNIQUEIDTYPE
     ON BRCOM.DSET_INVOLVEDPARTYTYPEID = BRUNIQUEIDTYPE.ID
       AND BRUNIQUEIDTYPE.LOOKUPCATEGORYID = 10026094
       AND BRUNIQUEIDTYPE.ACTIVEFLAG = 'A'
   --FIND UNIQUE ID TYPE 10026094
   --JOIN BROKER DATA
   --JOIN COUNTER PARTY DATA
   LEFT OUTER JOIN COUNTERPARTY CTP  
     ON ITX.COUNTERPARTYID = CTP.COUNTERPARTYID
   LEFT OUTER JOIN COMPANY CTPCOM
     ON CTP.REFERENCEID = CTPCOM.COMPANYID
       AND CTPCOM.ACTIVEFLAG = 'A'
   --FIND UNIQUE ID TYPE 10026094
   LEFT OUTER JOIN SYSTEMLOOKUP CTPUNIQUEIDTYPE
     ON CTPCOM.DSET_INVOLVEDPARTYTYPEID = CTPUNIQUEIDTYPE.ID
       AND CTPUNIQUEIDTYPE.LOOKUPCATEGORYID = 10026094
       AND CTPUNIQUEIDTYPE.ACTIVEFLAG = 'A'
   --FIND UNIQUE ID TYPE 10026094
   --JOIN COUNTER PARTY DATA
   --JOIN EXCHANGE
   LEFT OUTER JOIN EXCHANGE EX
     ON FTA.EXCHANGEID = EX.EXCHANGEID
       AND EX.ACTIVEFLAG = 'A'
   --JOIN EXCHANGE
   --COMMODITY CURRENCY
   LEFT OUTER JOIN CURRENCY COMCCY
     ON ITX.CURRENCYID = COMCCY.CURRENCYID
       AND COMCCY.ACTIVEFLAG = 'A'
   --COMMODITY CURRENCY
   --QUOTE CURRENCY
   LEFT OUTER JOIN CURRENCY QUOTECCY
     ON FTA.QUOTED = QUOTECCY.CURRENCYID
       AND QUOTECCY.ACTIVEFLAG = 'A'
   --QUOTE CURRENCY
   --JOIN TO FIND INDEX INVOLVEMENT 
   LEFT OUTER JOIN DSET_MAPPARAM_INDEXINVOLVEMENTTYPE INDEXTYPE
     ON INV.INTERNALCODE = INDEXTYPE.INTERNALCODE
       AND UNDSEC.UNDERLYINGTYPECODE = INDEXTYPE.UNDERLYINGTYPECODE
       AND INDEXTYPE.DATASETTYPE = 'FTA'
       AND INDEXTYPE.ISENABLE = 'Y'
   --JOIN TO FIND INDEX INVOLVEMENT
   --JOIN TO FIND ARRANGEMENT BY PRODUCT-FUTURE
   LEFT OUTER JOIN DSET_MAPPARAM_ARRANGEMENTTYPE_FTA ARR_FTA
     ON INV.INTERNALCODE = ARR_FTA.INTERNALCODE
       AND UNDSEC.UNDERLYINGTYPECODE = ARR_FTA.UNDERLYINGTYPECODE
       AND ARR_FTA.ISENABLE = 'Y'
       AND ARR_FTA.DATASETTYPE = 'FTA'
   --JOIN TO FIND ARRANGEMENT BY PRODUCT-FUTURE
   --JOIN TO FIND ARRANGEMENT BY TX TYPE
   LEFT OUTER JOIN DSET_MAPPARAM_ARRANGEMENTTYPE_TX ARR_TX
     ON ITX.INVESTTXTYPEID = ARR_TX.TXTYPEID
       AND ARR_TX.ISENABLE = 'Y'
       AND ARR_TX.DATASETTYPE = 'FTA'
   --JOIN TO FIND ARRANGEMENT BY TX TYPE
   --JOIN TO FIND LEGTYPE 
   LEFT OUTER JOIN DSET_MAPPARAM_LEGTYPE LEGTYPE
     ON LEGTYPE.ISCROSSCURRENCY = (
         CASE  WHEN ITX.CURRENCYID = 1 OR FTA.QUOTED = 1 THEN 'N' 
               ELSE 'Y'
         END
       )
       AND LEGTYPE.TXARRANGEMENTTYPEID = ARR_TX.ARRANGEMENTTYPEID
       AND LEGTYPE.PRODUCTARRANGEMENTTYPEID = ARR_FTA.ARRANGEMENTTYPEID
       AND LEGTYPE.ISENABLE = 'Y'
       AND LEGTYPE.DATASETTYPE = 'FTA'
   --JOIN TO FIND LEGTYPE
 WHERE ITX.ISDELETED = 'N'
   AND ITX.ISCANCELLED = 'N'
   AND ITX.ISPOSTED = 'Y'
   AND ITX.TRADEDATE = '2016-02-01'
   AND ITX.PORTFOLIOID = 201
   AND INDEXTYPE.CONFIGID IN (SELECT TINDEXTYPE.CONFIGID
                              FROM DSET_MAPPARAM_INDEXINVOLVEMENTTYPE TINDEXTYPE
                              WHERE TINDEXTYPE.ISENABLE = 'Y'
                                AND TINDEXTYPE.DATASETTYPE = 'FTA'
                                AND INV.INTERNALCODE = TINDEXTYPE.INTERNALCODE
                                AND UNDSEC.UNDERLYINGTYPECODE = TINDEXTYPE.UNDERLYINGTYPECODE)

หมายเหตุ : ผมยังไม่ได้สนใจ Performance และอาจจะมีวิธีอื่นๆ ที่ทำได้ดีกว่านะครับ ที่เขียน Blog เพื่อไปเป็นแนวทาง สำหรับการไปประยุกต์ใช้ครับ ^__^


Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts sent to your email.