Using the '?' Parameter in SQL LIKE Statement - sql

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")

Related

How to remove the first character from the join statement in where clause of the SQL query

I want to remove the first character returning from the cvdl.C statement in the below SQL query and that value should be match up with the ccp.B value.
For an example if the real value return by the cvdl.C statement is 4500, I want to remove 4 and take only the 500 part to match with the value in the ccp.B value. Also I need to pass a input parameter value for the query.
How can I modify below SQL query to achieve this objective?
SELECT ccp.A
FROM ccp, cvdl
WHERE cvdl.J = 'Example' and ccp.B = cvdl.C
you should use the ansi-syntax to join
select ccp.A,
from ccp
inner join cvdl on ccp.B = substr(cvdl.C, 2)
where cvdl.J = 'Example'

Substring in Left Join condition

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

Why does OLEDB (or Access?) rewrite WHERE clause

I'm facing a strange situation where OledbDataAdapter rearranges the WHERE clause of my query, thus shuffling all parameters. In addition, it doesn't recognize one of the parameters used in the query. Here's how it goes:
A simple table with 4 columns (and infinite rows :)):
Name varchar(50)
Category varchar(20) //One of around 15-20 possible values
YR int //Year
Period int //Month
User will query this table using Year, Month and a comma-separated list of categories that he's interested in. Since .NET doesn't support multi-valued parameters through IN operator, what I do is to accept the list of categories as comma-separated list and then prepend and append a comma to this list within the query and use built-in INSTR() function to filter results for desired categories. User can also supply an empty string for categories filter in which case query will need to return all results (i.e. no filter on categories).
Therefore my query looks like this:
SELECT * FROM [Table1] WHERE
YR = ? AND
Period = ? AND
(LTRIM(RTRIM(?)) = '' OR INSTR(1, ?, ',' + Category + ',') > 0)
This worked with MDBs in the past. But recently I tried it against an ACCDB. The first thing I noted is that when I try to run the query in OledbDataAdapter wizard, Visual Studio rewrites it as:
SELECT * FROM [Table1] WHERE
(YR = ? AND Period = ? AND LTRIM(RTRIM(?)) = '') OR
(YR = ? AND Period = ? AND INSTR(1, ?, ',' + Category + ',') > 0)
In other words, it has rearranged the condition A AND B AND (C OR D) as (A AND B AND C) OR (A AND B AND D).
This would have been fine with me, but the additional problem is that this changes the number of parameters from 4 to 6; the query therefore doesn't return any results even when it should. Moreover, it doesn't recognize that last parameter (the question mark within INSTR function) at all.
So my questions are:
Who is rewriting the query (OledbDataAdapter, Access query parser or something else)?
Why is it doing so? Optimization? Apparently my version of the WHERE clause is more efficient.
Why doesn't it see the last parameter?
How to fix/workaround this issue? (plz do not suggest using 2 separate queries for it).

HQL Date throwing unexpected token

Hi I have trouble executing the following query in HQL:
This is a very dangerous approach to running queries. It's the sort of thing that creates SQL injection risks. Never concatenate values into SQL or HQL strings like that. Always use the PreparedStatement approach of using placeholders in the SQL/HQL string and setting the values programmatically. This way the driver (and Hibernate in the case of HQL) can do the correct thing with the SQL that gets generated. Of course here the value is a date and not a user-submitted string, but the principle still holds.
What you need to do is run a query more like
'select stuff from bar b where b.dateCreated = ?'
In HQL you can also use named parameters, and those are usually a lot easier to read and self-documenting, e.g.
'select stuff from bar b where b.dateCreated = :date'
Then set the value as part of the call, not with string concatenation.
The problem here is that the Java/Groovy toString value of a date is nothing at all like what the date format should be in SQL (or HQL). Luckily you don't need to know what that format should be, because the JDBC driver does.
So your query should be
def co = Bid.executeQuery(
'select b.job from Bid b left join b.job j where j.dateCreated = :date',
[date: fromDates[i])
Here I'm using the name date but that's arbitrary, is just has to match the key name in the map with values. You can also use SQL-style ? chars and a list of values:
def co = Bid.executeQuery(
'select b.job from Bid b left join b.job j where j.dateCreated = ?',
[fromDates[i])
Once you get this working you'll find that comparing dates like this rarely works because the dates have to agree to the millisecond, but that's a problem for another question :)

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