[英]How to convert the values in string text into a list for table joins - Teradata SQL
嗨,我对Teradata SQL中的表联接有疑问。 因此,我有一个交易表(T1)和另一个国家/地区映射表(M1)结合在一起。
在事务表(T1)中,还包括(对于表联接):(i)。 SalesOrg代码; (ii)。 售至国家/地区代码
表T1:
SalesOrg Code Sold-To Country Cd Product Code Trans. Date Revenue Amt
0001 ES P001 01/08/2019 199.00
0002 IE P002 02/08/2019 399.00
0002 FR P003 02/08/2019 299.00
0002 IT P005 02/08/2019 599.00
0002 BE P002 02/08/2019 399.00
0002 LU P005 02/08/2019 599.00
0002 NL P001 02/08/2019 199.00
对于国家/地区映射表(M1),它看起来像这样:
SalesOrg Code Reporting Country Sold-To Country Code Sold-To Country Name
0001 Spain null null
0002 UK IE Ireland
0002 UK FR France
0002 UK IT Italy
0002 Netherlands Ex: NOT: FR IE IT
.......
我要实现的是根据以下条件联接两个表:
1)。 如果Sold-To Country Code为空,则从销售组织代码中的T1提取所有交易(例如#0001);
2)。 如果Sold-To国家/地区代码为NOT NULL并且不包含“ Ex”,则根据SalesOrg代码和Sold-To国家/地区代码映射来自T1的交易;
3)。 如果“售至”国家/地区代码包含“ Ex”(表示排除),则使用相同的SalesOrg代码映射T1交易,但不包括最后一列中指定的国家/地区代码,例如上面的示例:NOT:FR IE IT。
对于#3条件,我最终希望将字符串文本NOT:FR IE IT中的值转换为列表,以便可以像NOT IN('FR','IE','IT')一样在JOIN中使用它。
最终,我想获得如下结果(最后一列-报告国):
SalesOrg Code Sold-To Country Cd Product Code Trans. Date Revenue Amt Reporting Country
0001 ES P001 01/08/2019 199.00 Spain
0002 IE P002 02/08/2019 399.00 UK
0002 FR P003 02/08/2019 299.00 UK
0002 IT P005 02/08/2019 599.00 UK
0002 BE P002 02/08/2019 399.00 Netherlands
0002 LU P005 02/08/2019 599.00 Netherlands
0002 NL P001 02/08/2019 199.00 Netherlands
........
有更好的主意吗?
我尝试使用STRTOK_SPLIT_TO_TABLE将FR IE IT值转换为行,并且确实可以创建此类列表。 但是,这不是唯一的情况,其他国家/地区也存在相同的情况,因此,我需要联接条件基于M1表中记录的每一行。
(
CASE WHEN M1.Sold_to_Country_Code LIKE 'Ex%') THEN (
SELECT DISTINCT TOKEN
FROM TABLE (STRTOK_SPLIT_TO_TABLE(1,
(SELECT DISTINCT
TRIM(BOTH FROM (SUBSTR(M1.Sold_to_Country_Name,INSTR(M1.Sold_to_Country_Name,' ')))) AS Exclude_Country
FROM M1
WHERE M1.Sold_to_Country_Code LIKE 'Ex%'
),' ')
RETURNS (OUTKEY INTEGER,
TOKENNUM INTEGER,
TOKEN VARCHAR(2) CHARACTER SET UNICODE)
) AS d )
END )
我在下面尝试过,但是无法正确映射,因为它将与荷兰的国家代码IE FR IT一起重复映射到荷兰。
SELECT DISTINCT
T1.sales_org_cd,
M1.Reporting_Country,
M1.Sold_to_Country_Code,
OREPLACE(TRIM(BOTH FROM (SUBSTR(M1.Sold_to_Country_Name,INSTR(M1.Sold_to_Country_Name,' ')))),' ',',') AS SC,
T1.Country_Cd
FROM T1
FULL OUTER JOIN M1
ON T1.Sales_org_cd = M1.Sales_org_code
AND (
(M1.Sold_to_Country_Code IS NULL AND T1.Country_cd ?? (not sure for condition #1)
(M1.Sold_to_Country_Code IS NOT NULL AND M1.Sold_to_Country_Code NOT LIKE 'Ex%' AND T1.Country_cd=M1.Sold_to_Country_Code )
OR (T1.Country_cd IS NOT NULL AND M1.Sold_to_Country_Code LIKE 'Ex%' AND T1.Country_cd NOT IN (OREPLACE(TRIM(BOTH FROM (SUBSTR(M1.Sold_to_Country_Name,INSTR(M1.Sold_to_Country_Name,' ')))),' ',',')) )
)
WHERE T1.sales_org_cd IN ('0001','0002')
希望我的解释清楚。 不确定是否可以实现。 感谢您是否可以提供任何意见或建议。
我想出了条件#1的一种方法:使用TO_NUMBER函数将T1.Country_cd中的所有值转换为NULL,然后使用COALESCE将NULL转换为0,并对M1.Sold_to_Country_Code将null转换为0进行类似操作。因此,将条件3的@Fred解决方案汇总在一起,完整的查询应如下所示:
SELECT DISTINCT
T1.sales_org_cd,
M1.Reporting_Country,
M1.Sold_to_Country_Code,
T1.Country_Cd
FROM T1
LEFT OUTER JOIN M1
ON T1.Sales_org_cd = M1.Sales_org_code
AND (
(M1.Sold_to_Country_Code IS NULL AND COALESCE(TO_NUMBER(T1.Country_cd),'0')=COALESCE(M1.Sold_to_Country_Code,'0') )
OR
(M1.Sold_to_Country_Code IS NOT NULL AND M1.Sold_to_Country_Code NOT LIKE 'Ex%' AND T1.Country_cd=M1.Sold_to_Country_Code )
OR
(T1.Country_cd IS NOT NULL AND M1.Sold_to_Country_Code LIKE 'Ex%' AND POSITION(' '||T1.Country_cd||' ' IN M1.Sold_to_Country_Name||' ')=0 )
)
WHERE T1.sales_org_cd IN ('0001','0002')
我刚刚对其进行了测试,它确实可以用于示例查询。 但是,在实际实践中执行查询似乎需要更长的时间。
有谁可以在优化查询中有更好的主意/解决方案? 任何帮助都非常感谢!
再次感谢@Fred!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.