2

I want to simplify the below sql code without change the business logic.here I mentioned postgresql code that I want to modify.

SELECT IF(
    (SELECT `rate` FROM `vat_rate` WHERE '2017-05-12' BETWEEN from_date AND to_date) is not null ,
    (SELECT `rate` FROM `vat_rate` WHERE '2017-05-12' BETWEEN from_date AND to_date) ,

         IF((SELECT `rate` FROM `vat_rate` WHERE from_date is null and '2017-05-12' < to_date ) is not  null,
            (SELECT `rate` FROM `vat_rate` WHERE from_date is null and '2017-05-12' < to_date ),

                IF(
                    (SELECT `rate` FROM `vat_rate` WHERE to_date is null and '2017-05-12' > from_date) is not   null,
                          (SELECT `rate` FROM `vat_rate` WHERE to_date is null and '2017-05-12' > from_date),
                          'not found'
                         )
            )
    ) as rate 
2
  • 5
    SQL has no if statement. And backticks are also illegal for SQL identifiers. Please edit your question and explain the actual problem you are trying to solve (instead of throwing a bunch of invalid SQL at us) and add some sample data and the expected output based on that data. Formatted text please, no screen shots Commented Aug 22, 2016 at 10:33
  • 1
    Note: You can avoid this kind of mess by using -infinity and +infinity as default values for from_date and to_date. Commented Aug 22, 2016 at 10:44

3 Answers 3

3

The complexity is caused by allowing NULLs in the dates. Using -infinity and (+)infinity as the default values would have avoided the tests for NULL dates. Changing the table definition:

ALTER TABLE vat_rate
        ALTER COLUMN from_date SET DEFAULT '-infinity'
        , ALTER COLUMN to_date SET DEFAULT 'infinity'
        ;

UPDATE vat_rate SET from_date = DEFAULT WHERE from_date IS NULL;
UPDATE vat_rate SET to_date = DEFAULT WHERE to_date IS NULL;

ALTER TABLE vat_rate
       ALTER COLUMN from_date SET NOT NULL
       , ALTER COLUMN to_date SET NOT NULL
        ;

could reduce your query to just:


SELECT rate AS the_reet
FROM vat_rate
WHERE '2017-05-12' BETWEEN from_date AND to_date
                ;

If you cannot change the table definition, you could fold the date values inside the query:


SELECT rate AS the_reet
FROM vat_rate 
WHERE '2017-05-12' BETWEEN COALESCE(from_date, '-infinity'::date)
                AND COALESCE(to_date, 'infinity'::date)
                ;

Avoiding the COALESCE() (this could be faster)

SELECT rate AS the_reet
FROM vat_rate 
WHERE ('2017-05-12' >=  from_date OR from_date IS NULL)
AND ( '2017-05-12' <= to_date OR to_date IS NULL)
                ;

The extreme case of no matching range could be solved by adding a union.

Sign up to request clarification or add additional context in comments.

Comments

2

You're after the Coalesce() operator:

SELECT 
  COALESCE (
    (SELECT rate FROM vat_rate WHERE '2017-05-12' BETWEEN from_date AND to_date),
    (SELECT rate FROM vat_rate WHERE from_date is null and '2017-05-12' < to_date ),
    (SELECT rate FROM vat_rate WHERE to_date is null and '2017-05-12' > from_date),
    'not found'
  ) as rate 

1 Comment

Still not very efficient. As you can see the same table is used 3 times.
2

Why not just use CASE EXPRESSION directly on the vat_rate table instead of selecting each value from it over and over? Here is a solution that should do the same using conditional aggregation :

SELECT COALESCE(t.val_1,t.val_2,t.val_3) as calc_col
FROM (
    SELECT MAX(CASE WHEN vat_rate between  from_date AND to_date THEN rate END) as val_1,
           MAX(CASE WHEN from_date is null and '2017-05-12' < to_date THEN rate END) as val_2,
           MAX(CASE WHEN to_date is null and '2017-05-12' > from_date THEN rate END) as val_3
    FROM vat_rate) t

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.