Create variable in SQL script before doing queries - mysql

I have the following snippet
select user_id into #selected_user from users where mail = 'mymail#gmail.com';
select * from kc_network_user where user_id = 'previous_id';
which I want to modify to be parametric. I found the following resources:
Using variables in SQL script
How to declare a variable in MySQL?
Declare variables - MySQL Workbench gives me an error with DECLARE
That's what I did:
select #user_mail := 'mymail#gmail.com'; #1
select #user_mail; #2
select user_id into #selected_user from user where mail = #user_mail; #3
select #selected_user;
select * from user_network where user_id = #selected_user; #4
In select #1 I tried also the following:
set #user_mail = 'mymail#gmail.com';
The select #2 returns the correct value, so the variable is initialized.
The select #3 returns the following error:
Error Code: 1267. Illegal mix of collations
(utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for
operation '='
While the select #4 runs correctly (if I set the mail parameter with the literal value).
What's the difference between those queries?
How can I set a variable before doing a query?

I don't understand why not simply
select *
from user_network
join user using (user_id)
where user.mail = 'mymail#gmail.com';
If you need to set mentioned variables additionally (but for what reason?) then use
select *, (#selected_user := user.user_id)
from user_network
join user using (user_id)
where user.mail = (#user_mail := 'mymail#gmail.com');

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.

MySql - Update with Select

I need to update a table with a select inside. This is my query so far:
Update T_STATO_CASA
Set UTENTE = 'Admin'
Where ID_CASA in (
Select ID
From T_CASA
Where ID_RICHIESTA
In (437869, 437233, 437235, 437876)
)
But it returns the following error: "Subquery returned more than 1 value. This is not permitted when the subquery follows
=, !=, <, <= , >, >=
or when the subquery is used as an expression."
The subquery returns exactly 4 results if I run it separately. Is my syntax wrong? Thanks.
EDIT: all the suggested solutions that are using JOIN give me syntax error, as if MySql expects only the update-set-where command sequence. For instance I cannot write something like
update T_STATO_CASA as x
set [...]
where [...]
because it gives me syntax error: "Incorrect syntax near word AS. Expected SET"
UPDATE t_stato_casa x
JOIN t_casa y
ON y.id = x.id_casa
SET x.utente = 'admin'
WHERE y.id_richiesta IN(437869, 437233, 437235, 437876)
The reason is that your subquery will return more than one row of record
The more suitable way is to use JOIN instead
UPDATE T_STATO_CASA
JOIN T_CASA t
ON t.id = ID_CASA
AND t.ID_RICHIESTA
IN (437869, 437233, 437235, 437876)
SET UTENTE = 'Admin
If you still want to use subquery,you need to use group_concat to make the result into one record
This was the right syntax for my case:
UPDATE t_stato_casa
SET
UTENTE = 'Admin'
FROM
t_stato_casa AS sc
INNER JOIN T_CASA AS c
ON c.ID = sc.ID_CASA
WHERE
c.ID_RICHIESTA in (437869, 437233, 437235, 437876)
Thanks to everyone.

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.

Complex MySQL cmd with JOINS and Counters doesnt work

I am working on this SQLFiddle and cant get the command working. Here the command:
SET #n := 1;
SET #start := '2013-07-22 10:00:01';
SET #end := '2013-07-22 10:00:02';
SET #register := 40001;
SELECT * FROM
(
SELECT
`realvalues`.`Timestamp`,
`realvalues`.`Value` * `register`.`Factor`,
#x := #x + 1 AS rank
FROM
`realvalues`,
(SELECT #x := 0) t
WHERE
`realvalues`.`Register` = register AND
`realvalues`.`Timestamp` BETWEEN start AND end
JOIN
`register`
ON
`register`.`DeviceID` = `realvalues`.`DeviceID` AND
`register`.`Register` = `realvalues`.`Register`
) a
WHERE
rank MOD ? = n
Does anybody know where the command fails? MySQL error reporting isnt very usefull.
[EDIT] The Value is now duplicated with Factor.
There are many many things wrong with your query. However, the error that is being reported in your fiddle is:
...check the manual that corresponds to your MySQL server version for the right syntax to use near 'BETWEEN start AND end JOIN register ON ...
Your syntax for BETWEEN is incorrect. There should be no IS token before BETWEEN. Correct syntax is:
<value> BETWEEN <lower-bound-inclusive> AND <upper-bound-inclusive>
Other problems include:
start, end, and n are not columns
register (in the WHERE clause) is ambiguous
You have a JOIN clause after a WHERE clause
You do not specify an alias for the second column of your derived table a (perhaps not necessary but may cause issues)
Use of a ? parameter without a way to specify a value (although this is a limitation of SQL Fiddle and not necessarily a problem with your SQL statement)
i dont see usage of #start and #end
EDIT: now it works !
sqlfiddle.com/#!2/6dc97/50

Sql error : Invalid use of group function?

Hi I want to select a row with max ID(primary key) value having patient_id=xyz
following is my sql script
check="Select * from notes where id=max(ID) in (SELECT * FROM notes WHERE patient_id="+patientSoapBean.getPatientID()+")";
I am getting invalid use of group function error. can you point out the error in this.
You likely are trying to do this:
SELECT * FROM notes
WHERE patient_id = ?
ORDER BY id DESC
LIMIT 1