mysql LAST_DAY () читает только 1 результат подзапроса, как обработать все результаты? используя соединения? - PullRequest
0 голосов
/ 20 марта 2019

У меня есть таблица страховых полисов, подобная этой:

+-------------------------------------------------------------+
| id | cancellation_val | cancellation_interval | expire_date |
+-------------------------------------------------------------+
| 1  | 30               | day                   | 2019-06-09  |
| 2  | 2                | month                 | 2019-12-01  |
+-------------------------------------------------------------+

Мне нужно получить идентификаторы полисов, срок действия которых истекает на основе отмены, с сегодняшнего дня и в течение 4 месяцев, с расчетомпоследний день месяца, например псевдокод:

'today' <= LAST_DAY (expire_date - cancellation_val / interval) <'today + 4 months' <br>

Будучи не профессионалом, я думаю, что я должен использовать JOINs, но я не знаю, как, после нескольких дней попыток, единственное, чего я достиг, это:

SELECT LAST_DAY(
    DATE_FORMAT(
        STR_TO_DATE(
            (SELECT CASE cancellation_interval 
            WHEN "day" THEN date_sub(expire_date, INTERVAL cancellation_val DAY)
            WHEN "month" THEN date_sub(data_scadenzaexpire_date, INTERVAL cancellation_val MONTH)       
            END
            AS newDate
            FROM insurance WHERE id=2
            ), '%Y-%m-%d'
        ), '%Y-%m-%d'
    )
)

Это работает, но мне не нужноПредложение «WHERE id = 2» (потому что мне нужно обработать ВСЕ строки таблицы), и если я его удалю, я получаю сообщение об ошибке «подзапрос возвращает более 1 строки».
Так, как я могу продолжить?И используя результат, чтобы остаться между «сегодня» И «сегодня + 4 месяца»?

Я думаю, что с помощью какого-то типа JOIN я мог бы сделать это проще, но я не знаю, как.

Спасибо всем

Ответы [ 3 ]

0 голосов
/ 21 марта 2019

Проблема заключается в структуре запроса, а не в функции LAST_DAY.

Мы хотим вернуть id значения строк, которые удовлетворяют некоторому условию.Таким образом, запрос будет иметь вид:

SELECT t.id 
     , ... 
  FROM insurance t 
 WHERE ... 
HAVING ...

Введение другого ключевого слова SELECT в основном вводит подзапрос.Существуют ограничения для подзапросов ... в списке SELECT подзапрос может возвращать один столбец и (самое большее) одну строку.

Так что давайте отбросим это дополнительное ключевое слово SELECT.

Мы можем получить newdate как выражение списка SELECT, а затем мы можем сослаться на этот производный столбец в предложении HAVING.В спецификации сказано, что мы хотим вернуть значение id, поэтому мы включили его в список SELECT.Нам не нужно возвращать какие-либо другие столбцы, но для тестирования / отладки может быть полезно вернуть значения, которые использовались для получения столбца newdate.

Примерно так:

SELECT t.id
     , LAST_DAY(
         CASE t.cancellation_interval
         WHEN 'day'    THEN  t.expire_date - INTERVAL t.cancellation_val DAY
         WHEN 'month'  THEN  t.expire_date - INTERVAL t.cancellation_val MONTH
         ELSE t.expire_date
         END
       ) AS newdate
     , t.expire_date
     , t.cancellation_interval
     , t.cancellation_val
  FROM insurance t
HAVING newdate >= DATE(NOW()) 
   AND newdate <= DATE(NOW()) + INTERVAL 4 MONTH
 ORDER 
    BY newdate ASC 

Нам не нужно включать newdate в список SELECT;мы могли бы просто заменить вхождения newdate в предложении HAVING выражением.

Мы также можем использовать встроенное представление, чтобы «скрыть» вывод столбца newdate

SELECT v.id
     , v.newdate
  FROM ( SELECT t.id
              , LAST_DAY(
                  CASE t.cancellation_interval
                  WHEN 'day'    THEN  t.expire_date - INTERVAL t.cancellation_val DAY
                  WHEN 'month'  THEN  t.expire_date - INTERVAL t.cancellation_val MONTH
                  ELSE t.expire_date
                  END
                ) AS newdate
           FROM insurance t
       ) v
 WHERE v.newdate >= DATE(NOW()) 
   AND v.newdate <= DATE(NOW()) + INTERVAL 4 MONTH
 ORDER 
    BY v.newdate ASC
0 голосов
/ 21 марта 2019

Когда вы используете SELECT запрос в качестве выражения, он может вернуть только одну строку.

Если вы хотите обработать все строки, вам нужно вызвать LAST_DAY() внутри запроса, а не в результате.

SELECT *
FROM insurance
WHERE CURDATE() <= LAST_DAY(
    expire_date - IF(cancellation_interval = 'day', 
                    INTERVAL cancellation_val DAY, 
                    INTERVAL cancellation_val MONTH))
AND LAST_DAY(expire_date - IF(cancellation_interval = 'day', 
                                INTERVAL cancellation_val DAY, 
                                INTERVAL cancellation_val MONTH)) < CURDATE + INTERVAL 4 MONTH
0 голосов
/ 21 марта 2019

проверьте этот запрос: удалите строку HAVING , чтобы увидеть все строки

SELECT 
IF(cancellation_interval = 'day',
        i.expire_date - INTERVAL i.`cancellation_val` DAY,
        i.expire_date - INTERVAL i.`cancellation_val` MONTH
    ) as cancellation_day,
    i.*

FROM `insurance` i
HAVING cancellation_day < NOW() + INTERVAL 4 MONTH;

ОБРАЗЦЫ

MariaDB [test]> SELECT IF(cancellation_interval = 'day', i.expire_date - INTERVAL i.`cancellation_val` DAY, i.expire_date - INTERVAL i.`cancellation_val` MONTH ) as cancellation_day, i.* FROM `insurance` i HAVING cancellation_day < NOW() + INTERVAL 4 MONTH;
+------------------+----+------------------+-----------------------+-------------+
| cancellation_day | id | cancellation_val | cancellation_interval | expire_date |
+------------------+----+------------------+-----------------------+-------------+
| 2019-05-10       |  1 |               30 | day                   | 2019-06-09  |
+------------------+----+------------------+-----------------------+-------------+
1 row in set (0.001 sec)
...