简体   繁体   中英

Select case with multiple columns along with other columns in Oracle?

Consider the following tables

ID_TYPE

ID TYPE
1 3
2 3
3 1
4 2
5 2

ID_HISTORY

DEBIT_ID DEBIT_LOCATION AMOUNT CREDIT_ID CREDIT_LOCATION MONTH
3 LOC1 100 1 LOC5 MAY
4 LOC2 200 3 LOC6 MAY
2 LOC3 300 5 LOC7 MAY
1 LOC4 400 3 LOC8 JUNE
3 LOC9 500 2 LOC10 JUNE

Now suppose I want to fetch all rows from ID_HISTORY in the MONTH of MAY, and result should contain only these columns:

Id, Location, Amount

Cases:

  • If the DEBIT_ID is of TYPE = 3 in the ID_TYPE table, then pick DEBIT_ID as "Id", else pick CREDIT_ID as "Id"
  • Similarly, If the DEBIT_ID is of TYPE 3 in the ID_TYPE table, then pick DEBIT_LOCATION as "Location", else pick CREDIT_LOCATION as "Location"

For example, above tables should result in the following:

Id Location Amount
1 LOC5 100
2 LOC3 300

I know that something like the following should work:

SELECT 
    (CASE
        WHEN (Tab.DEBIT_ID IN (
            SELECT ID
            FROM ID_TYPE Typ
            WHERE Typ.TYPE = 3)
            ) THEN Tab.DEBIT_ID
        ELSE Tab.CREDIT_ID END
        )                           "Id",
    (CASE
        WHEN (Tab.DEBIT_ID IN (
            SELECT ID
            FROM ID_TYPE Typ
            WHERE Typ.TYPE = 3)
            ) THEN Tab.DEBIT_LOCATION
        ELSE Tab.CREDIT_LOCATION END
        )                           "Location",
    Tab.AMOUNT                      "Amount"
FROM (
    SELECT *
    FROM ID_HISTORY Tab
    WHERE Tab.MONTH = 'MAY'
    --this block will be very complicated and contain complex multi-level queries to fetch data
)

But as you can see this will be inefficient as I have to basically duplicate the full case logic for each conditional columns. Also, this is no way "clean" in case there are a lot of similar columns.

Also, if the case logic is complex, it will be inefficient even further. It would be better if i could select multiple columns in THEN / ELSE cases. I tried doing that, but it just gives me "ORA-00913: too many values" error.

What would be the optimized version?

You could use a join to remove the sub-queries:

SELECT CASE
       WHEN typ.id IS NOT NULL
       THEN h.debit_id
       ELSE h.credit_id
       END AS id,
       CASE
       WHEN typ.id IS NOT NULL
       THEN h.debit_location
       ELSE h.credit_location
       END AS location,
       h.AMOUNT
FROM (
       SELECT *
       FROM   ID_HISTORY
       WHERE  MONTH = 'MAY'
       -- this block will be very complicated and contain complex multi-level queries to fetch data
     ) h
     LEFT OUTER JOIN (
       SELECT id
       FROM   id_type
       WHERE  type = 3
     ) typ
     ON (h.debit_id = typ.id)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM