SQL-запрос Informix с объединением на определенную дату - PullRequest
0 голосов
/ 05 июня 2019

Я собрал запрос, который собирает мне данные из нескольких таблиц, но мне нужно указать цену труда, где effective_date в таблице labourates равно max(labourates.effective_date), которое меньше или равно labourline.alloc_entry_date

Объединение labourline.alloc_entry_date и labourline.part_code (оба в таблице labourates)

Я пробовал несколько вариантов внешнего соединения, но я не очень хорош в текущей методологии соединения (им со времен *=)

Текущий запрос:

Select  'Labour' part_type,
    labourline.order_num,
    ordhead.order_date,
    labourhead.alloc_entry_date,
    labourline.part_code,
    product.desc_text,
    ordhead.cust_code,
    product.cat_code,
    product.prodgrp_code,
    product.maingrp_code,
    product.ware_code,
    0 unit_rate_amt,
    labourline.order_qty,
    labourline.uom_code,
    product.weight_qty,
    product.cubic_qty,
    product.area_qty,
    product.length_qty
from    ordhead,
    labourline,
    labourhead,
    product
where   labourline.cmpy_code = 'EC'
and product.cmpy_code = 'EC'
and ordhead.cmpy_code = 'EC'
and labourhead.cmpy_code = 'EC'
and labourline.part_code = product.part_code
and labourline.order_num = ordhead.order_num
and labourline.order_num = labourhead.order_num
and ordhead.order_date >= MDY(08,01,2018)
and ordhead.order_date < MDY(08,01,2019)

Этот код дает мне unit_rate_amt, в котором я нуждаюсь при получении PartCode и CheckDate

Select   unit_rate_amt
from    labourates
where   part_code = 'PartCode'
and effective_date = (
        select max(effective_date) from labourates
        where part_code = 'PartCode'
        and effective_date <= 'CheckDate'
    )

Слияние с первоначальным запросом для замены 0 unit_rate_amt, оказывается тем, с чем я не могу справиться.

Ответы [ 2 ]

1 голос
/ 05 июня 2019

Я склонен использовать то, что я называю TDQD - Test-Driven Query Design.Я строю сложный запрос шаг за шагом.Вы дали мне быстрый старт со своим основным запросом и подзапросом, который необходимо интегрировать в основной запрос.Разработка отдельного подзапроса - это именно то, что поощряет TDQD.

Задавая вопросы о SO, убедитесь, что вы минимизируете количество полей в таких вещах, как запросы.Например, четыре элемента product.weight_qty, product.cubic_qty, product.area_qty, product.length_qty, несомненно, все важны в вашем запросе «в реальной жизни», но они действительно не влияют на нас в SO.Одного из них здесь много;может быть, это даже излишне, так как вы выбрали desc_text из product.

Также важно предоставить схематическую схему таблиц - мой TDQD не управляется тестом, потому что вы не предоставили пригодный для использования,минимальные схемы таблиц, не говоря уже о выборке данных для обработки и ожидаемого результата.Вы получите лучшие ответы на свой вопрос, если на ваш вопрос будет легче ответить, потому что вы предоставили эту информацию.

Как общее практическое правило, в текущем тысячелетии не следует использовать FROM table1, table2, table3, …нотация в SQL больше.Вы должны явно использовать JOIN.

Шаг 1 - Упрощение основного запроса и использование JOIN

Взяв ваш основной запрос, я изменил его следующим образом:

SELECT 'Labour' AS part_type,
       ll.order_num,
       oh.order_date,
       lh.alloc_entry_date,
       ll.part_code,
       pr.desc_text,
       oh.cust_code,
       0 unit_rate_amt,
       ll.order_qty,
       ll.uom_code,
       pr.length_qty
  FROM ordhead    AS oh
  JOIN labourline AS ll ON oh.order_num = ll.order_num AND oh.cmpy_code = ll.cmpy_code
  JOIN labourhead AS lh ON lh.order_num = ll.order_num AND lh.cmpy_code = ll.cmpy_code
  JOIN product    AS pr ON pr.part_code = ll.part_code AND pr.cmpy_code = pr.cmpy_code
 WHERE ll.cmpy_code = 'EC'
   AND pr.cmpy_code = 'EC'
   AND oh.cmpy_code = 'EC'
   AND lh.cmpy_code = 'EC'
   AND oh.order_date >= MDY(08,01,2018)
   AND oh.order_date < MDY(08,01,2019)

Iиспользуйте AS, чтобы ввести сокращения для таблиц.Я часто использую однобуквенные сокращения;здесь двухбуквенные казались более подходящими.Я исключил ряд элементов из списка выбора как недостаточно существенный для вашего вопроса.

Из вашего повторного использования xyz.cmpy_code = 'EC' я заключил, что таблицы могут быть объединены с cmpy_code как частьусловие соединения;Я использую это в ON условиях для соединений.Я также сделал вывод, что labourline является центральной таблицей в этом запросе и перечислил его первым.Другие таблицы присоединяются к нему, а не друг к другу.Я оставил в запросе повторяющиеся условия, такие как AND pr.cmpy_code = 'EC', но, вероятно, я бы исключил все, кроме ll.cmpy_code = 'EC', если только планы запросов не продемонстрировали существенную выгоду от сохранения постоянных терминов.query

Это требует некоторой интерпретации вашего «рабочего подзапроса».Я предполагаю, что то, что вы называете CheckDate, является labourline.alloc_entry_date, а код детали - labourline.part_code.С помощью нотации JOIN легко вставить подзапрос в основной запрос, например:

SELECT 'Labour' AS part_type,
       ll.order_num,
       oh.order_date,
       lh.alloc_entry_date,
       ll.part_code,
       pr.desc_text,
       oh.cust_code,
       lr.unit_rate_amt,
       ll.order_qty,
       ll.uom_code,
       pr.length_qty
  FROM labourline AS ll
  JOIN ordhead    AS oh ON oh.order_num = ll.order_num AND oh.cmpy_code = ll.cmpy_code
  JOIN labourhead AS lh ON lh.order_num = ll.order_num AND lh.cmpy_code = ll.cmpy_code
  JOIN product    AS pr ON pr.part_code = ll.part_code AND pr.cmpy_code = ll.cmpy_code
  JOIN (SELECT lr1.part_code, lr1.unit_rate_amt AS unit_rate_amt
          FROM labourates AS lr1
         WHERE lr1.part_code = ll.part_code
           AND lr1.effective_date =
               (SELECT MAX(effective_date)
                  FROM labourates AS lr2
                 WHERE lr2.part_code =  ll.part_code
                   AND lr2.effective_date <= ll.alloca_entry_date
               )
       )          AS lr ON lr.part_code = ll.part_code
 WHERE ll.cmpy_code = 'EC'
   AND oh.order_date >= MDY(08,01,2018)
   AND oh.order_date < MDY(08,01,2019)

Это коррелированный подзапрос из-за ссылок на ll.part_code и ll.alloc_entry_dateв подзапросе.Я подозреваю, что были бы способы преобразовать это из коррелированного подзапроса в некоррелированный подзапрос.Конечно, если / когда это вызывает проблемы с медленным временем отклика, это первое место, где я бы искал улучшения.Однако значение ll.alloc_entry_date имеет решающее значение для подзапроса, поэтому корреляция может быть неизбежной.Если корреляция неизбежна, то обеспечение наличия соответствующих индексов также становится критически важным.Даже основной запрос с объединениями на cmpy_code и другими столбцами получит выгоду от доступности соответствующих индексов.

0 голосов
/ 12 июня 2019

Для полноты мне удалось заставить это работать.Он где-то создает дуплексы, и я не могу понять, где, но как это работает:

Select  distinct 'Labour' part_type,
    ll.order_num,
    oh.order_date,
    lh.alloc_entry_date,
    ll.part_code,
    pr.desc_text,
    oh.cust_code,
    oh.sale_code,
    pr.cat_code,
    pr.prodgrp_code,
    pr.maingrp_code,
    pr.ware_code,
    lr1.unit_rate_amt,
    ll.order_qty,
    ll.uom_code,
    pr.weight_qty,
    pr.cubic_qty,
    pr.area_qty,
    pr.length_qty
from    labourline AS ll
JOIN    ordhead    AS oh ON oh.order_num = ll.order_num AND oh.cmpy_code = ll.cmpy_code
JOIN    labourhead AS lh ON lh.order_num = ll.order_num AND lh.cmpy_code = ll.cmpy_code
JOIN    product    AS pr ON pr.part_code = ll.part_code AND pr.cmpy_code = ll.cmpy_code
JOIN    labourates    AS lr1 ON lr1.part_code = ll.part_code AND lr1.cmpy_code = ll.cmpy_code
where   ll.cmpy_code = 'EC'
and oh.order_date >= MDY(08,01,2017)
and oh.order_date < MDY(08,01,2018)
and lr1.effective_date = 
    (
    SELECT  MAX(effective_date)
    FROM    labourates lr2
    WHERE   lr2.part_code =  ll.part_code
    AND lr2.effective_date <= lh.alloc_entry_date
    AND lr2.ware_code = ll.ware_code
    )

Спасибо @Jonathan Leffler за то, что научил меня конструкции соединения.

...