【问题标题】:How to convert the values in string text into a list for table joins - Teradata SQL如何将字符串文本中的值转换为表连接列表 - Teradata SQL
【发布时间】:2019-12-11 03:26:56
【问题描述】:

您好,我对 Teradata SQL 中的表连接有疑问。所以我有一个交易表(T1)和另一个国家映射表(M1)来连接在一起。

在事务表(T1)中,还包括(对于表连接):(i)。销售组织代码; (二)。销往国家代码

表 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 Country Code 不为 NULL 且不包含“Ex”,则根据 SalesOrg Code 和 Sold-To Country Code 映射来自 T1 的交易;
3)。如果 Sold-To Country Code 包含“Ex”(表示排除),则从相同的 SalesOrg 代码映射 T1 交易,但不包括最后一列中指定的国家代码,如上例:NOT:FR IE IT。

对于#3 条件,我最终想将字符串文本 NOT: FR IE IT 中的值转换为列表,以便它可以在 JOIN 中使用,就像 NOT IN ('FR','IE','IT ')。

最终我想得到如下结果(最后的附加列 - 报告国家):

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  ) 

我在下面尝试过,但它无法正确映射,因为它将与荷兰的重复映射以及 Sold-To 国家代码 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')

希望我的解释清楚。 不确定这些是否可以实现。感谢您提供任何意见或建议。

【问题讨论】:

  • edit您的帖子正确使用降价来格式化您的所有代码示例/术语。
  • 这是一次性加载吗?输入或更改新行的频率。此表的工作方式是错误的,如果您使用真正的关系模型,您应该将内容出售给其他表中的列
  • 为什么不进行子字符串匹配以确保要匹配的值的两侧都存在分隔符,例如POSITION(' '||T1.Country_cd||' ' IN M1.Sold_to_Country_Name||' ') > 0
  • @GordonLinoff 嗨,戈登。我只是在加入后添加了 T1 和所需的表。希望它更清楚。非常感谢您的帮助!
  • @Hogan 嗨,霍根,这不是一次性的事情,对于一些处于同样复杂情况的国家,地图故事需要不时更新我知道如果我列出所有对于向荷兰报告的其他国家/地区,它会起作用。但是,与 NOT IN(“国家列表”)方法相比,它需要更多的维护。因此,我正在尝试为此寻求任何可能的解决方案。谢谢你的帮助!:)

标签: sql teradata teradata-sql-assistant


【解决方案1】:

我想出了一个条件#1的方法:使用TO_NUMBER函数将T1.Country_cd中的所有值转换为NULL,然后使用COALESCE将NULL转换为0,并对M1.Sold_to_Country_Code做类似的事情转换null到 0。因此,结合@Fred 的条件 #3 的解决方案,完整的查询应该是这样的:

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!

【讨论】:

  • 不确定我是否理解第一个条件的 COALESCETO_NUMBER 背后的原因。为什么M1.Sold_to_Country_Code IS NULL 本身不够用?有时,与其在连接 (ON) 条件中使用 OR 进行一个查询,不如为每个条件单独查询 UNION ALL
  • 嗨@Fred。你是对的,我不需要COALESCETO_NUMBER 作为第一个条件,它只适用于M1.Sold_to_Country_Code IS NULL。再次感谢你!对于在连接中使用OR,我想如果我将它们分成3个查询然后UNION ALL将它们合并在一起,它会起作用,但是查询会很长并且执行需要很长时间?
  • 有时UNION ALL 会比JOINOR 快,但有时不会。取决于数据。
猜你喜欢
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-27
  • 2022-10-15
  • 2021-06-05
相关资源
最近更新 更多