A weird error in Matlab with MySQL - mysql

I have two tables named t1 and t2, which content list as following:
mysql> use test;
Database changed
mysql> select * from t1;
+----+------+
| id | val |
+----+------+
| 1 | 100 |
| 2 | 200 |
+----+------+
2 rows in set (0.00 sec)
mysql> select * from t2;
+----+-------+
| id | val |
+----+-------+
| -1 | -1000 |
| 1 | 1000 |
| 3 | 3000 |
+----+-------+
3 rows in set (0.00 sec)
There is a sql statement run in mysql command with on problem:
mysql> create or replace view iid as select id from t1 union select id from t2;select iid.id,t1.val,t2.val from iid left join t1 on iid.id=t1.id left join t2 on iid.id=t2.id;
Query OK, 0 rows affected (0.07 sec)
+----+------+-------+
| id | val | val |
+----+------+-------+
| 1 | 100 | 1000 |
| 2 | 200 | NULL |
| -1 | NULL | -1000 |
| 3 | NULL | 3000 |
+----+------+-------+
4 rows in set (0.00 sec)
While it run in matlab with a error:
>> sqlCmd = ['create or replace view iid as select id from t1 union select id from t2;',...
'select iid.id,t1.val,t2.val from iid',...
' left join t1 on iid.id=t1.id',...
' left join t2 on iid.id=t2.id'];
conn = database('test','root','198471',...
'com.mysql.jdbc.Driver','jdbc:mysql://127.0.0.1:3306/test');
>> curs = exec(conn,sqlCmd);
>> curs.Message
ans =
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 'select iid.id,t1.val,t2.val from iid left join t1 on iid.id=t1.id left join t2 o' at line 1
>> curs = exec(conn,'select * from t1');
>> curs = fetch(curs);
>> curs.Data
ans =
1 100
2 200
>> sqlCmd
I'm a pure newbie of SQL, and I have no idea for this error message.
Any help would be appreciated.

It would appear that Matlab treats each string in your sqlCmd matrix as a separate SQL statment. As you are breaking up the queries into string portions this will not work, because each not every portion is a valid standalone SQL statement. As the comment above suggests, you may need to search for a setting that allows this. Alternatively you could try to rewrite your SQL into a single string just like you did with mysql:
sqlCmd = 'create or replace view iid as select id from t1 union select id from t2;select iid.id,t1.val,t2.val from iid left join t1 on iid.id=t1.id left join t2 on iid.id=t2.id;';
curs = exec(conn,sqlCmd);
This should at least run your query without error. If you have not done so already, take a look at the mathworks documentation for exec http://www.mathworks.co.uk/help/toolbox/database/ug/exec.html

Related

MySQL , Exclude result set (from one view) from result set (from another view) [duplicate]

This question already has answers here:
How to select all records from one table that do not exist in another table?
(15 answers)
Closed 1 year ago.
Hi i have issue i cant solve, i have 2 views looking something like this:
Table 1(inserted users) ---------------------- Table 2(deleted users)
[Name] [Date]
[Name] [Date]
John ----
John ----
Andrew ----
Michael ----
Michael ----
Sam ----
And my task is to create a view based only of those 2 views, that contains only STILL EXISTING users, hence check if user with some NAME apper on the deleted table and exclude those from inserted users. I cant figure it out...
you can use a query like this:
SELECT NAME FROM table1 t1
WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t1.name = t2.name);
sample
MariaDB [bernd]> select * from table1;
+----+-------+
| id | name |
+----+-------+
| 1 | Peter |
| 2 | Paul |
| 3 | John |
+----+-------+
3 rows in set (0.02 sec)
MariaDB [bernd]> select * from table2;
+----+------+
| id | name |
+----+------+
| 1 | Paul |
+----+------+
1 row in set (0.00 sec)
MariaDB [bernd]> SELECT NAME FROM table1 t1 WHERE NOT EXISTS (SELECT 1 FROM table2 t2 WHERE t1.name = t2.name);
+-------+
| NAME |
+-------+
| Peter |
| John |
+-------+
2 rows in set (0.09 sec)
MariaDB [bernd]>

"Subquery returns more than 1 row" when using `SET`

select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)
I'm using this to find orphaned records and it works fine.
However when I try and assign the result to a var, using SET, I get the "Subquery returns more than 1 row" error.
SET #text_field_ids := (select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies))
For context I'm want to use the var to then text_fields records, e.g.
DELETE from text_fields WHERE id IN #text_field_ids
Incidentally I have tried passing the subquery directly to DELETE such as:
DELETE from text_fields WHERE id IN (select id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies))
But this gives the error You can't specify target table 'text_fields' for update in FROM clause because apparently you can't use the table being deleted from in the WHERE clause.
You can use temporary table :
create temporary table if not exists mytmptable select tf.id as id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)
and then you can use it in delete :
DELETE from text_fields WHERE id IN (select Id from mytmptable)
The usual way round a ERROR 1093 (HY000): Table 'USERS' is specified twice, both as a target for 'DELETE' and as a separate source for data error is to push the select a bit deeper for example see second delete below-
MariaDB [sandbox]> SELECT ID FROM USERS;
+----+
| ID |
+----+
| 1 |
| 2 |
| 3 |
| 6 |
| 7 |
| 8 |
| 10 |
| 12 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
+----+
14 rows in set (0.00 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> DELETE FROM USERS
-> WHERE ID IN (SELECT ID FROM USERS WHERE ID IN (18,19))
-> ;
ERROR 1093 (HY000): Table 'USERS' is specified twice, both as a target for 'DELETE' and as a separate source for data
MariaDB [sandbox]>
MariaDB [sandbox]> DELETE FROM USERS
-> WHERE ID IN (SELECT ID FROM (SELECT ID FROM USERS WHERE ID IN (18,19)) U )
-> ;
Query OK, 2 rows affected (0.11 sec)
MariaDB [sandbox]>
MariaDB [sandbox]> SELECT ID FROM USERS;
+----+
| ID |
+----+
| 1 |
| 2 |
| 3 |
| 6 |
| 7 |
| 8 |
| 10 |
| 12 |
| 14 |
| 15 |
| 16 |
| 17 |
+----+
12 rows in set (0.00 sec)
Since the query
select tf.id from text_fields as tf WHERE tf.study_id NOT IN (select id from studies)
returns more than 1 row, assigning the recordset to a variable fails. however if you really need to assign it to a variable you can do it as
select `tf`.`id` from `text_fields` as tf WHERE `tf`.`study_id` NOT IN
(select `id` from `studies`) into #text_field_ids;
or
SELECT #text_field_ids := `tf`.`id` from `text_fields` as tf WHERE `tf`.`study_id` NOT IN
(select `id` from `studies`);
more info about this is here
Alternatively, If your db user has create temporary table priviliges, you can create a temporary table, to select your records into that lives through your session. Please note that not to suffer performance penalty, the temporary table is created with memory engine.
CREATE TEMPORARY TABLE IF NOT EXISTS temp_table ( INDEX(`id`) )
ENGINE=Memory
AS (
select `tf`.`id` from `text_fields` as `tf` WHERE `tf`.`study_id` NOT IN (select `id` from `studies`)
);
# and remove the records with
delete from `text_fields` where id in (select `id` from `temp_table`)

Pattern for LIKE in SQL Statement

I would like to select all rows that start with any character.
SELECT * FROM table WHERE field LIKE '[a-z]%' ;
The type of rows I would like to find look like this:
ID DATA
993 DEF055900960
994 DEF055900961
995 DEF055900964
996 DEF056102254
997 DEF056131201
I have unsucessfully tried RLIKE and REGEXP and also added upper case A-Z ot the pattern.
Why is the following not working?
SELECT * FROM table WHERE field RLIKE '[a-z]' ;
SQL Fiddle Demo
I went through here to read about Pattern Matching in Mysql
Try this instead:
SELECT * FROM table WHERE field LIKE '[^A-Z]%';
Try this.
SELECT `firstname`
FROM `users`
WHERE firstname
REGEXP BINARY '^[A-Z]'
Use REGEXP
http://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp
For example, assume we have this data set.
mysql> select * from a;
+------+
| b |
+------+
| abc |
| zxxb |
| kkfy |
| 0002 |
+------+
4 rows in set
We want to select everything with the a-z pattern
mysql> SELECT * FROM a WHERE b REGEXP BINARY '[a-z]';
+------+
| b |
+------+
| abc |
| zxxb |
| kkfy |
+------+
3 rows in set
SQLFiddle
For your data set
SQLFiddle
Use the regular expression [a-zA-Z0-9]
mysql> SELECT * FROM a WHERE b REGEXP BINARY '[a-zA-Z0-9]';
+--------------+
| b |
+--------------+
| DEF055900960 |
| DEF055900961 |
| DEF055900964 |
| DEF056102254 |
| DEF056131201 |
+--------------+
5 rows in set

Query returns "LIKE" results despite not having wildcards?

I'm really confused here. Running the following query:
SELECT * FROM `articles` WHERE `form` = 'Depotplåster' AND `size` = 5
returns rows that also start with "5", despite me neither using LIKE nor a % wildcard operator. How come?
The size field is of type VARCHAR.
That is because you're using comparison between numeric and varchar data. MySQL will implicitly convert your column to double, resulting in 5. See this simple test data:
mysql> select * from test;
+-----------------+
| name |
+-----------------+
| 5 |
| 5 and some crap |
+-----------------+
2 rows in set (0.00 sec)
Now, "good" way: compare strings:
mysql> select * from test where name = '5';
+------+
| name |
+------+
| 5 |
+------+
1 row in set (0.00 sec)
And "bad" way: compare integers:
mysql> select * from test where name = 5;
+-----------------+
| name |
+-----------------+
| 5 |
| 5 and some crap |
+-----------------+
2 rows in set, 1 warning (0.05 sec)
-and here is your reason:
+---------+------+-----------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '5 and some crap' |
+---------+------+-----------------------------------------------------+
1 row in set (0.00 sec)
Finally, to understand, why is it so:
SELECT
CAST('5' AS DECIMAL) AS 5d,
CAST('5 and some crap' AS DECIMAL) AS 5sd,
CAST('5' AS DECIMAL) = CAST('5 and some crap' AS DECIMAL) AS areEqual;
Will result in:
+----+-----+----------+
| 5d | 5sd | areEqual |
+----+-----+----------+
| 5 | 5 | 1 |
+----+-----+----------+
1 row in set (0.00 sec)
-as you can see, non-significant part was just truncated (as mentioned in warning message above)
SELECT * FROM `articles` WHERE `form` = 'Depotplåster' AND `size` = '5'
-- this will compare the string 'size' with the string '5'
SELECT * FROM `articles` WHERE `form` = 'Depotplåster' AND `size` = 5
-- this will convert string 'size' to integer and then compare with the integer 5
The conversion of string to integer looks for ints i nthe beginning of the string, and takes the largest integer until the first non-numeric character.
select '5s4'=5, 's5'=5, '5'=5 -- =>1,0,1
SELECT *
FROM `articles`
WHERE `form` = 'Depotplåster'
AND `size` = '5'
You should quote 5 because MySQL convert string from the table to int without quotes.

What's wrong with this simple query?

I did a very simple query yesterday but this morning I couldn't remember how I did it, and whatever I tried doesn't work.
I want to do a simple SELECT COUNT(*) and then update table TEST. We want how many values from column start are (table1) are between the values in column txStart and column txEnd (from table TEST).
The SELECT COUNT(*) alone works well.
mysql> SELECT COUNT(*) FROM table1, TEST where table1.start BETWEEN TEST.txStart AND TEST.txEnd;
+----------+
| COUNT(*) |
+----------+
| 95149 |
+----------+
1 row in set (0.03 sec)
The UPDATE never happened.
mysql> UPDATE TEST
SET rdc_1ips =
SELECT COUNT(*) FROM table1, TEST WHERE table1.start between TEST.txStart AND TEST.txEnd;
ERROR 1064 (42000): 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 'SELECT COUNT(*) FROM table1, TEST WHERE table1.start between TEST.txStart A' at line 1
Here is a preview of the table1 and table TEST
mysql> SELECT * from table1 limit 2;
+----+--------+------+---------+---------+------+-------+
| id | strand | chr | start | end | name | name2 |
+----+--------+------+---------+---------+------+-------+
| 1 | - | 1 | 2999997 | 3000096 | NULL | NULL |
| 2 | + | 1 | 2999998 | 3000097 | NULL | NULL |
+----+--------+------+---------+---------+------+-------+
mysql> SELECT * FROM TEST;
+------+-----------+--------------+-------+---------+---------+----------+
| chr | pos_start | name | name2 | txStart | txEnd | rdc_1ips |
+------+-----------+--------------+-------+---------+---------+----------+
| 1 | 3204575 | NM_001011874 | Xkr4 | 3204562 | 3661579 | 0 |
+------+-----------+--------------+-------+---------+---------+----------+
Put the sub-select in brackets.
Additionally I would give the inner "test" table an alias (just to be sure)
SET rdc_1ips =
(SELECT COUNT(*) FROM table1, TEST t2
WHERE table1.start between t2.txStart AND t2.txEnd)
But I'm not sure if this will work even if the syntax is correct. MySQL has some obnoxious limitiations when it comes to selecting from the same table that you want to update.