Use parameters in SQL Server referencing MySQL datasource - mysql

I have to run a query where some data comes from a SQL Server Database and some from a MySQL database. I managed to achieve it, but the problem comes when using a parameter with the MySQL database.
Here the faulty query :
select sp.SLC_ID, a.ASS_NAM, p.PCE_NAM, p.PCE_DES, pr.PRF_NAM,
(
SELECT top 1 t2.CleTri
FROM (
SELECT CAST(t1.CLETRI as varchar) CleTri, CAST(t1.LIBELLE as varchar) Libelle
FROM OPENQUERY("PLMStock",'SELECT CLETRI, LIBELLE FROM produits') t1
) t2
WHERE t2.Libelle LIKE pr.PRF_NAM + '%'
) as CLETRI
from SELECT_PART sp
left join PART p on p.PCE_ID = sp.PCE_ID
left join ASSEMBLY a on a.ASS_ID = sp.ASS_ID
left join PROFILE pr on pr.PRF_ID = p.PRF_ID
where sp.SLC_ID = 2930 and p.PRD_ID is null
When running this query, I got that error:
Msg 468, Level 16, State 9, Line 9
Cannot resolve the collation conflict between "French_CI_AS" and
"Latin1_General_CI_AS" in like operation.
But when I hardcode the like parameter it works fine.
Can someone help me with it please?

LIKE comparisons are affected by collation.
https://learn.microsoft.com/en-us/sql/t-sql/statements/collations?view=sql-server-ver15
WHERE t2.Libelle COLLATE database_default LIKE pr.PRF_NAM + '%'

The error indicates differing collations between the two columns, you need to convert one or the other to match.
Does the following work for you?
WHERE t2.Libelle LIKE pr.PRF_NAM + '%' COLLATE French_CI_AS

Related

JOOQ multiset throwing syntax exception

Recently moved to JOOQ 3.15.5 and tried the Multiset feature but it is throwing SQLSyntaxErrorException. Below is the query I wrote:
dslContext.select(
tableA.asterisk(),
multiset(
select(tableB.DELETED, tableB.VALUE)
.from(tableB)
.where(tableB.ORDER_ID.eq(tableA.ORDER_ID))
).as("bookingAdditions")
).from(tableA)
.where(tableA.BATCH_ID.greaterThan(batchId))
.fetchInto(BookingDto.class);
Here is the relations:
|tableA| 1 n |tableB|
| | --------------> | |
| | | |
-------- --------
(tableA) (tableB)
Here is the query that is being generated by JOOQ:
set #t = ##group_concat_max_len; set ##group_concat_max_len = 4294967295; select `tablea`.*, (select coalesce(json_merge_preserve('[]', concat('[', group_concat(json_array(`v0`, `v1`) separator ','), ']')), json_array()) from (select `tableb`.`deleted` as `v0`, `tableb`.`value` as `v1` from `db_name`.`booking_additions` as `tableb` where `tableb`.`order_id` = `tablea`.`order_id`) as `t`) as `bookingadditions` from `db_name`.`booking` as `tablea` where `tablea`.`batch_id` > 0; set ##group_concat_max_len = #t;
Here are exceptions:
org.jooq.exception.DataAccessException: SQL [set #t = ##group_concat_max_len; set ##group_concat_max_len = 4294967295; select `tablea`.*, (select coalesce(json_merge_preserve('[]', concat('[', group_concat(json_array(`v0`, `v1`) separator ','), ']')), json_array()) from (select `tableb`.`deleted` as `v0`, `tableb`.`value` as `v1` from `db_name`.`booking_additions` as `tableb` where `tableb`.`order_id` = `tablea`.`order_id`) as `t`) as `bookingadditions` from `db_name`.`booking` as `tablea` where `tablea`.`batch_id` > ?; set ##group_concat_max_len = #t;]; You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'set ##group_concat_max_len = 4294967295; select `tablea`.*, (select coalesce(jso' at line 1
at org.jooq_3.15.5.MYSQL.debug(Unknown Source)
at org.jooq.impl.Tools.translate(Tools.java:2988)
at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:639)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:349)
at org.jooq.impl.AbstractResultQuery.fetchLazy(AbstractResultQuery.java:295)
at org.jooq.impl.AbstractResultQuery.fetchLazyNonAutoClosing(AbstractResultQuery.java:316)
at org.jooq.impl.SelectImpl.fetchLazyNonAutoClosing(SelectImpl.java:2866)
at org.jooq.impl.ResultQueryTrait.collect(ResultQueryTrait.java:357)
at org.jooq.impl.ResultQueryTrait.fetchInto(ResultQueryTrait.java:1423)
at com.company.BookingDAO.fetchBookings(BookingDAO.java:118)
at
I am using Mysql: 5.7. What am I doing wrong? Any hint?
jOOQ generates three SQL statements separated by semicolons when you use GROUP_CONCAT() in a query. Unfortunately, the default behavior of MySQL is to disallow multiple queries in a single request.
You have to change your JDBC connection options to include allowMultiQueries.
Read more about it here: https://blog.jooq.org/mysqls-allowmultiqueries-flag-with-jdbc-and-jooq/
Regarding the multiple statements
In addition to what Bill Karwin said, you could also specify the Settings.renderGroupConcatMaxLenSessionVariable to be false and increase your server's ##group_concat_max_len variable for your session or your server yourself.
jOOQ's default here is to assume it's easier to add the JDBC connection flag rather than change the server settings, but both approaches are viable.
Regarding correlated derived tables
This particular emulation requires support for correlated derived tables, which MySQL 5.7 doesn't support, see https://github.com/jOOQ/jOOQ/issues/12045. You're not going to get a correlated MULTISET expression to work on MySQL 5.7, but you could write an almost equivalent MULTISET_AGG expression, like this:
dslContext.select(
tableA.asterisk(),
multisetAgg(tableB.DELETED, tableB.VALUE).as("bookingAdditions")
).from(tableA)
.join(tableB).on(tableB.ORDER_ID.eq(tableA.ORDER_ID))
.where(tableA.BATCH_ID.greaterThan(batchId))
// You can group by the primary key, or tableA.fields() if you don't have a PK
.groupBy(tableA.ID)
.fetchInto(BookingDto.class);
Unlike MULTISET, MULTISET_AGG produces NULL values instead of empty lists in case you're left joining tableB, as is usual for SQL aggregate functions. You could then use coalesce(multisetAgg(...), multiset(...)) as a workaround.

Equivalent of SQL Server's CONTAINSTABLE in MySQL

I am converting a Query from SQL Server to MySQL but I have a problem converting the sentence contains table , because it uses rank .
I´ve looked for a similar property but I didn´t find anything , here is my Query at SqlServer
SELECT KEY_TBL.RANK
FROM CATS
INNER JOIN containsTABLE (CATS,(COLOR,CITY),'ORANGE',1000) AS KEY_TBL ON RUP.ID = KEY_TBL.[KEY]
ORDER BY RANK

SQLite / MySQL compatibility issue

I know SQL in SQLite is not completely implemented the same way as in MySql. My problem with the following queries is, that they are not compatible and I like to avoid a conditional if <DBMS> ... else
SQLite query
UPDATE sorties SET state = '#'
WHERE `key` IN (
SELECT `key` FROM sorties
INNER JOIN reports AS r
ON r.sortieId=sorties.`key`);
Error on MySQL:
SQL Error (1093): Table 'sorties' is specified twice, both as a target for 'UPDATE' and as a separate source for data
MySQL query (adapted from here)
UPDATE sorties AS s SET s.state='#'
WHERE s.`key` IN (
SELECT t.sortieId FROM (
SELECT r.sortieId AS sortieId
FROM reports AS r
INNER JOIN sorties AS sort
ON sort.`key`=r.sortieId)
AS t);
Error on SQLite:
SQLiteManager: Likely SQL syntax error: UPDATE sorties AS s SET s.state='#'
WHERE s.key IN ( SELECT t.sortieId FROM (
SELECT DISTINCT r.sortieId AS sortieId
FROM reports AS r
INNER JOIN sorties AS sort
ON sort.key=r.sortieId) AS t); [ near "AS": syntax error ]
Exception Name: NS_ERROR_FAILURE
Exception Message: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [mozIStorageConnection.createStatement]
I can't figure out how to make this queries work on both systems equally!
All I want to have is, that each state of sorties must be '#' when it's key can be found in reports.sortieId.
Maybe there is a different approach for this?
Thank you
The first command reads the key value from the sorties table in the subquery, and then checks whether those key values exist in the sorties table in the outer statement. That check is superfluous; you can just compare the values to the ones in reports directly:
UPDATE sorties
SET state = '#'
WHERE key IN (SELECT sortieId
FROM reports);
As for the second command, SQLite does not support aliasing a table used in INSERT/UPDATE/DELETE because those commands work only on a single table. You can just remove the AS s and replace s with sorties everywhere.

MySQL: union query fails on MySQL 5.5, works on MySQL 5.1

I'm having trouble with a stubborn MySQL query. It's a quite long and complex query, sorry about that. I really did my best to find it myself but I could use a hand here.
The following query is used to emulate a full outer join of column information in the information_schema, and column information in a table called nexedit_schema. The PHP variable $db contains the target database that contains the latter table.
The query actually successfully runs on my own server (MySQL version 5.1), but fails to run on a friend's server (MySQL version 5.5). It claims that I have a syntax error near "ON (schema_tables.db_table..."
I'm probably overlooking something really stupid. Anyone kind enough to help me out?
SELECT information_schema.tables.table_name, schema_tables.db_table, schema_tables.ne_page
FROM information_schema.tables
LEFT JOIN (
(SELECT DISTINCT db_table, ne_page FROM {$db}.nexedit_schema)
AS schema_tables)
ON (schema_tables.db_table = information_schema.tables.table_name
COLLATE utf8_unicode_ci)
WHERE information_schema.tables.table_schema = '{$db}'
AND information_schema.tables.table_name NOT LIKE 'nexedit_%'
UNION
SELECT information_schema.tables.table_name, schema_tables.db_table, schema_tables.ne_page
FROM information_schema.tables
RIGHT JOIN (
(SELECT DISTINCT db_table, ne_page FROM {$db}.nexedit_schema)
AS schema_tables)
ON (schema_tables.db_table = information_schema.tables.table_name
COLLATE utf8_unicode_ci)
WHERE information_schema.tables.table_schema IS NULL
AND schema_tables.db_table NOT LIKE 'nexedit_%'
GROUP BY information_schema.tables.table_name,schema_tables.db_table;
There's unnecessary ) here: AS schema_tables) Should be before AS

MySQL Syntax error message "Operand should contain 1 column(s)"

I tried running the following statement:
INSERT INTO VOUCHER (VOUCHER_NUMBER, BOOK_ID, DENOMINATION)
SELECT (a.number, b.ID, b.DENOMINATION)
FROM temp_cheques a, BOOK b
WHERE a.number BETWEEN b.START_NUMBER AND b.START_NUMBER+b.UNITS-1;
which, as I understand it, should insert into VOUCHER each record from temp_cheques with the ID and DENOMINATION fields corresponding to entries in the BOOK table (temp_cheques comes from a database backup, which I'm trying to recreate in a different format). However, when I run it, I get an error:
Error: Operand should contain 1 column(s)
SQLState: 21000
ErrorCode: 1241
I'm running this in SQuirrel and have not had issues with any other queries. Is there something wrong with the syntax of my query?
EDIT:
The structure of BOOK is:
ID int(11)
START_NUMBER int(11)
UNITS int(11)
DENOMINATION double(5,2)
The structure of temp_cheques is:
ID int(11)
number varchar(20)
Try removing the parenthesis from the SELECT clause. From Microsoft TechNet, the correct syntax for an INSERT statement using a SELECT clause is the following.
INSERT INTO MyTable (PriKey, Description)
SELECT ForeignKey, Description
FROM SomeView
The error you're getting, "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay.", is actually correct, assuming you have many rows in both BOOK and temp_cheques. You are trying to query all rows from both tables and make a cross-reference, resulting in an m*n size query. SQL Server is trying to warn you of this, before performing a potentially long operation.
Set SQL_BIG_SELECTS = 1 before running this statement, and try again. It should work, but note that this operation may take a long time.
Does B contain the UNITS column?
What is the table structure for temp_cheques and Book?
EDIT: As I said in comments, all the columns should be numeric when doing +/- and when comparing. Does the following simple SELECT work?
SELECT b.START_NUMBER+b.UNITS-1 FROM Books B
I don't have a MySQL instance handy, but my first guess is the WHERE clause:
WHERE a.number BETWEEN b.START_NUMBER AND b.START_NUMBER+b.UNITS-1;
I imagine that the MySQL parser may be interpreting that as:
WHERE number
(BETWEEN start_number AND start_number) + units - 1
Try wrapping everything in parentheses, ie:
WHERE a.number BETWEEN b.START_NUMBER AND (b.START_NUMBER + b.UNITS - 1);
The final version of the query is as follows:
Set SQL_BIG_SELECTS = 1;
INSERT INTO VOUCHER (VOUCHER_NUMBER, BOOK_ID, DENOMINATION)
SELECT a.number, b.ID, b.DENOMINATION
FROM temp_cheques a, BOOK b
WHERE a.number BETWEEN b.START_NUMBER AND (b.START_NUMBER+b.UNITS-1);
The parsing of the BETWEEN statement required parentheses, the SELECT did not, and because of the size of the two tables (215000 records in temp_cheques, 8000 in BOOK) I was breaking a limit on the select size, requiring me to set SQL_BIG_SELECTS = 1.
I ran into the same error when using Spring Repositories.
My repository contained a method like:
List<SomeEntity> findAllBySomeId(List<String> ids);
This is working fine when running integration tests against an in-memory database (h2). However against a stand alone database like MySql is was failing with the same error.
I've solved it by changing the method interface to:
List<someEntity findBySomeIdIn(List<String> ids);
Note: there is no difference between find and findAll. As described here: Spring Data JPA difference between findBy / findAllBy