Substring in Left Join condition - sql

I want to do substring within the join condition, but it is not working.
SELECT
IF (ps.shop = 'NL',TopCat.Parent_Title, CategoryUID.Parent_Title) as Parent_Title,
IF (ps.shop = 'NL',TopCat.Sub_Title_1, CategoryUID.Sub_Title_1) as Sub_Title_1,
IF (ps.shop = 'NL',TopCat.Sub_Title_2, CategoryUID.Sub_Title_2) as Sub_Title_2,
ps.ean, ps.product_resource_id
FROM `xxlhoreca-bi.PriceSearch.XXL_PriceComparison` ps
LEFT JOIN
`xxlhoreca-bi.DataImport.TopCategories` topCat
ON
ps.product_resource_id = topCat.product_resource_id
LEFT JOIN
`DataImport.CategoryUID` CategoryUID
ON
SAFE_CAST(SUBSTR('DataImport.CategoryMappingWithLocalID.Reporting_ID', 4) AS INT64) = CategoryUID.Category_ID
GROUP BY
1, 2, 3, 4, 5
Is there any way around how I can write substring within LEFT JOIN condition?
I need to change the substring part, but I have not been able to achieve it. Any helps would be really appreciated!
Thanks in advance!

You are on roughly the right track.
I am going to make a few assumptions here so bear with me, but I think there are educated guesses.
I think this DataImport.CategoryMappingWithLocalID.Reporting_ID is a field (Reporting_ID) from a table (CategoryMappingWithLocalID) you have in your dataset (DataImport).
What you are trying to achieve is to get the categories that are included in your CategoryMappingWithLocalID.
You are trying to get a substring from the Reporting_ID field because it has the ID you want within the first 4 characters.
Because SUBSTR requires a string, you are trying to turn that dataset.table.field reference in a string by putting it in single quotes, which leads me to think it might actually be a numeric field in the original table.
Now, the solution.
You need to use the table in your query if you want to use it in your JOIN ON clause. Therefore, you need to add an extra JOIN there.
You are on the right track with the SUBSTR part, but what you need to use is CAST(field AS STRING) to convert your numeric value into a string.
Put those two things together in your query and you are ready to go my friend.
JOIN `DataImport.CategoryMappingWithLocalID` AS category_mapping
ON
SAFE_CAST(SUBSTR(CAST(DataImport.CategoryMappingWithLocalID.Reporting_ID AS STRING), 4) AS INT64) = CategoryUID.Category_ID

Related

How to Replace a part of string in Left Join Statement in SQL

I have sql statement
LEFT JOIN SeniorCitizen on FinishedTransaction.SCID = SeniorCitizen.OSCAID
SCID has 1234
OSCAID has 1234/102938
How can I remove /102938 so that it matches
Hmmm, one method is to use LIKE:
ON SeniorCitizen.OSCAID LIKE FinishedTransaction.SCID + '/%'
No guarantees on performance, but this should do the join correctly.
EDIT:
You can do this operation efficiently by using a computed column and then an index on the computed column.
So:
alter table SeniorCitizen
add OSCAIDshort as ( cast(left(OSCAID, CHARINDEX('/', OSCAID) - 1) as int) );
create index idx_SeniorCitizen_OSCAIDshort on SeniorCitizen(OSCAIDshort);
(The cast presumes that the SCID column is an integer.)
Then you can use this in the join as:
LEFT JOIN SeniorCitizen on FinishedTransaction.SCID = SeniorCitizen.OSCAIDshort
This formulation can use the index on the computed column and hence is probably the fastest way to do the join.
If you knew that the length of the numbers you were comparing was always 4, you could use SUBSTRING, like so:
LEFT JOIN SeniorCitizen on FinishedTransaction.SCID = SUBSTRING(SeniorCitizen.OSCAID, 1, 4)
to just grab the first four characters from OSCAID for the comparison.
However, even if you knew the length was always 4, it's still safer to assume that you won't know the length, because maybe at some point in the future the length grows. And if it does, your query can scale with it with no issues. To do this, you can use a combination of SUBSTRING and CHARINDEX, like so:
LEFT JOIN SeniorCitizen on FinishedTransaction.SCID = SUBSTRING(SeniorCitizen.OSCAID, 1, CHARINDEX('/', SeniorCitizen.OSCAID, 0))
This will start at the first character in OSCAID and continue reading until it finds a /. So if the string is 1234/102938, it'll return 1234. And if grows to 123456/102938, it'll return 123456.
Be sure to check out the docs for each of those functions to get a better understanding of their capabilities:
SUBSTRING: https://msdn.microsoft.com/en-us/library/ms187748.aspx
CHARINDEX: https://msdn.microsoft.com/en-us/library/ms186323.aspx
You Can Use LEFT or SUBSTRING Functions to do this.
SUBSTRING(SeniorCitizen.OSCAID, 1, 4)
LEFT(SeniorCitizen.OSCAID, 4)
But keep in mind that, usage of user defined functions might make the query non-sargable.

Pentaho Dynamic SQL queries

I have a Pentaho CDE project in development and i wanted to display a chart wich depends on several parameters (like month, year, precise date, country, etc). But when i want to "add" another parameter to my query, it doesn't work anymore... So i'm sure i'm doing something wrong but what ? Please take a look for the parameter month for example :
Select_months_query : (this is for my checkbox)
SELECT
"All" AS MONTH(TransactionDate)
UNION
SELECT DISTINCT MONTH(TransactionDate) FROM order ORDER BY MONTH(TransactionDate);
Select_barchart_query : (this is for my chart, don't mind the other tables)
SELECT pginit.Family, SUM(order.AmountEUR) AS SALES
FROM pginit INNER JOIN statg ON pginit.PG = statg.PGInit INNER JOIN order ON statg.StatGroup = order.StatGroup
WHERE (MONTH(order.TransactionDate) IN (${month}) OR "All" IN (${month}) OR ${month} IS NULL) AND
/*/* Apply the same pattern for another parameter (like year for example) *\*\
GROUP BY pginit.Family
ORDER BY SALES;
(Here, ${month} is a parameter in CDE)
Any ideas on how to do it ?
I read something there that said to use CASE clauses... But how ?
http://forums.pentaho.com/showthread.php?136969-Parametrized-SQL-clause-in-CDE&highlight=dynamic
Thank you for your help !
Try simplifying that query until it runs and returns something and work from there.
Here are some things I would look into as possible causes:
I think you need single quotes around ${parameter} expressions if they're strings;
"All" should probably be 'All' (single quotes instead of double quotes);
Avoid multi-line comments. I don't think you can have multi-line comments in CDE SQL queries, although -- for single line comments usually works.
Be careful with multi-valued parameters; they are passed as arrays, which CDA will convert into comma separated lists. Try with a single valued parameter, using = instead of IN.

How can I use LEFT & RIGHT Functions in SQL to get last 3 characters?

I have a Char(15) field, in this field I have the data below:
94342KMR
947JCP
7048MYC
I need to break down this, I need to get the last RIGHT 3 characters and I need to get whatever is to the LEFT. My issue is that the code on the LEFT is not always the same length as you can see.
How can I accomplish this in SQL?
Thank you
SELECT RIGHT(RTRIM(column), 3),
LEFT(column, LEN(column) - 3)
FROM table
Use RIGHT w/ RTRIM (to avoid complications with a fixed-length column), and LEFT coupled with LEN (to only grab what you need, exempt of the last 3 characters).
if there's ever a situation where the length is <= 3, then you're probably going to have to use a CASE statement so the LEFT call doesn't get greedy.
You can use RTRIM or cast your value to VARCHAR:
SELECT RIGHT(RTRIM(Field),3), LEFT(Field,LEN(Field)-3)
Or
SELECT RIGHT(CAST(Field AS VARCHAR(15)),3), LEFT(Field,LEN(Field)-3)
Here an alternative using SUBSTRING
SELECT
SUBSTRING([Field], LEN([Field]) - 2, 3) [Right3],
SUBSTRING([Field], 0, LEN([Field]) - 2) [TheRest]
FROM
[Fields]
with fiddle
select right(rtrim('94342KMR'),3)
This will fetch the last 3 right string.
select substring(rtrim('94342KMR'),1,len('94342KMR')-3)
This will fetch the remaining Characters.

Using the '?' Parameter in SQL LIKE Statement

I'm accessing a Firebird database through Microsoft Query in Excel.
I have a parameter field in Excel that contains a 4 digit number. One of my DB tables has a column (TP.PHASE_CODE) containing a 9 digit phase code, and I need to return any of those 9 digit codes that start with the 4 digit code specified as a parameter.
For example, if my parameter field contains '8000', I need to find and return any phase code in the other table/column that is LIKE '8000%'.
I am wondering how to accomplish this in SQL since it doesn't seem like the '?' representing the parameter can be included in a LIKE statement. (If I write in the 4 digits, the query works fine, but it won't let me use a parameter there.)
The problematic statements is this one: TP.PHASE_CODE like '?%'
Here is my full code:
SELECT C.COSTS_ID, C.AREA_ID, S.SUB_NUMBER, S.SUB_NAME, TP.PHASE_CODE, TP.PHASE_DESC, TI.ITEM_NUMBER, TI.ITEM_DESC,TI.ORDER_UNIT,
C.UNIT_COST, TI.TLPE_ITEMS_ID FROM TLPE_ITEMS TI
INNER JOIN TLPE_PHASES TP ON TI.TLPE_PHASES_ID = TP.TLPE_PHASES_ID
LEFT OUTER JOIN COSTS C ON C.TLPE_ITEMS_ID = TI.TLPE_ITEMS_ID
LEFT OUTER JOIN AREA A ON C.AREA_ID = A.AREA_ID
LEFT OUTER JOIN SUPPLIER S ON C.SUB_NUMBER = S.SUB_NUMBER
WHERE (C.AREA_ID = 1 OR C.AREA_ID = ?) and S.SUB_NUMBER = ? and TI.ITEM_NUMBER = ? and **TP.PHASE_CODE like '?%'**
ORDER BY TP.PHASE_CODE
Any ideas on alternate ways of accomplishing this query?
If you use `LIKE '?%', then the question mark is literal text, not a parameter placeholder.
You can use LIKE ? || '%', or alternatively if your parameter itself never contains a LIKE-pattern: STARTING WITH ? which might be more efficient if the field you're querying is indexed.
You can do
and TP.PHASE_CODE like ?
but when you pass your parameter 8000 to the SQL, you have to add the % behind it, so in this case, you would pass "8000%" to the SQL.
Try String Functions: Left?
WHERE (C.AREA_ID = 1 OR Left(C.AREA_ID,4) = "8000")

decoding a text string to use in a join

I'm trying to extract the number from a text string and join it to another table. Here's what I have so far:
SELECT sect.id,
sect.section_number,
sect.expression,
p.abbreviation
FROM sections sect
JOIN period p ON SUBSTR(sect.expression, 1, (INSTR(sect.expression,'(')-1)) = p.period_number
AND p.schoolid = 73253
AND p.year_id = 20
JOIN courses c ON sect.course_number = c.course_number
WHERE sect.schoolid = 73253
AND sect.termid >= 2000
I read some other threads and figured out how to strip out the number (which always comes before the left parenthesis). The problem is that this only accounts for two of the three styles of data that live in the sect.expression column-
9(A) - check
10(A) - check
but not
5-6(A)
5-6(A) would kick back an Oracle 01722 invalid number error.
Is there a way I could modify the substr... line so that for the 5-6(A) data type it would grab the first number (the 5) and join off of that?
It's worth mentioning that I only have read rights to this table so any solution that depends on creating some kind of helper table/column won't work.
Thanks!
You can use REGEXP_REPLACE
1) If you want to extract only numbers:
JOIN period p ON REGEXP_REPLACE(sect.expression, '[^0-9]', '') = p.period_number
2) If you want to match with the digits in the start of the string and ignore the ones that appear later:
JOIN period p ON REGEXP_REPLACE(sect.expression, '^(\d+)(.*)', '\1')
Being Oracle 10g, you could use a regex instead:
JOIN period p ON REGEXP_SUBSTR(sect.expression, '^\d+', 1, 1) = p.period_number
Admittedly, the regex I provided needs work - it will get the first number at the start of the string. If you need a more complicated regex, I recommend this site: http://www.regular-expressions.info/tutorial.html