我汇总了一个查询,该查询从几张表中获取了很多数据,但我需要输入一个人工价格,其中劳工表中的effective_date
是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,
证明是我无法解决的问题。
答案 0 :(得分:1)
我倾向于使用我所谓的TDQD —测试驱动查询设计。我逐步建立了一个复杂的查询。您为我提供了一个巨大的飞跃,它从您的主查询和需要集成到主查询中的子查询开始。开发独立子查询正是TDQD鼓励的事情。
在询问关于SO的问题时,请确保将诸如查询之类的字段的数量最小化。例如,product.weight_qty
,product.cubic_qty
,product.area_qty
,product.length_qty
这四个项目在您的“现实生活”查询中无疑都是很重要的,但它们确实不会影响我们所以。其中之一是很多。也许甚至因为您已从desc_text
中选择了product
而变得矫kill过正。
提供表的概要架构也很重要-我的TDQD不受测试驱动,因为您没有提供可用的最小表架构,更不用说要处理的样本数据和预期的输出了。如果您的问题更容易回答,因为您已经提供了该信息,那么您将获得更好的答案。
作为一般的经验法则,在当前的千年中,您不应再在SQL中使用FROM table1, table2, table3, …
表示法。您应该显式使用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)
我使用AS
来介绍表的缩写。我经常使用单字母缩写。在这里,双字母似乎更合适。我从选择列表部分中删除了一些元素,因为它们对您的问题不够重要。
从您反复使用xyz.cmpy_code = 'EC'
推断出,可以将表与cmpy_code
进行连接作为连接条件的一部分;我在ON
条件中使用该连接。我还推断出labourline
是此查询的中心表,并首先列出了它。其他表连接到它,而不是彼此连接。我在查询中保留了诸如AND pr.cmpy_code = 'EC'
之类的重复条件,但是除非查询计划显示出通过保持常数项带来的显着收益,否则我可能会消除除ll.cmpy_code = 'EC'
之外的所有条件。
这需要对“工作子查询”进行一些解释。我假设您所指的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
和其他列上具有联接的主查询,也会从适当的索引中受益。
答案 1 :(得分:0)
为了完整起见,我设法解决了这个问题。它会在某处创建重复对象,我不知道该在哪里但区别在于它的作用:
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教给我了join结构。