Hi I have a question about table joins in Teradata SQL. So I have a transaction table (T1) and another country mapping table (M1) to join together.
In the transaction table (T1), there are also including (for tables joins): (i). SalesOrg Code; (ii). Sold-To Country Code
Table 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
For the country mapping table (M1), it looks like this:
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
.......
What I want to achieve is to join two tables based on below conditions:
1). If Sold-To Country Code is null, then pull all transactions from T1 in the sales org code (eg. #0001);
2). If Sold-To Country Code is NOT NULL and doesn't contains "Ex", then map the transactions from T1 based on SalesOrg Code and Sold-To Country Code;
3). If Sold-To Country Code contains "Ex" (which means excluding), then map the T1 transactions from the same SalesOrg code but excluding the country codes specified in the last column, as example above: NOT:FR IE IT.
For #3 condition, I eventually want to convert the values in the string text NOT: FR IE IT into a list so it can be used in the JOIN as like NOT IN ('FR','IE','IT').
Ultimately I want to get the results like below (additional column at last - Reporting Country):
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
........
Any better idea?
I tried to use STRTOK_SPLIT_TO_TABLE to convert the values FR IE IT into rows and it did work to create such list. However, this is not unique case, and there are same situations for other countries, hence, I need the join conditions to be based on each row of the record from M1 table.
(
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 )
I have tried below, but it can't be mapped correctly as it will be duplicated mapping for Netherlands with Sold-To country code IE FR IT as well.
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')
Hope my explanation is clear. Not sure if those are achievable. Appreciate if you could provide any inputs or suggestion.
I figured out a way for the condition #1: to convert all values in T1.Country_cd into NULL by using TO_NUMBER function, and then convert NULL into 0 by using COALESCE, and do the similar thing for M1.Sold_to_Country_Code converting null to 0. So taking together the solution from @Fred for condition #3, the full query should be like this:
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')
I just tested it and it did work for sample querying. However, it seems to take longer time in executing the query in real practice.
Anyone who can have any better idea/solutions in optimising the query? Any help is really appreciated!
Thank you @Fred again!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.