I wanna create temporary tables with random names in a MySQL stored procedure. I also need to store the name in order to access the table from another stored procedure. I was thinking of using MD5 hashes:
SELECT md5(RAND()+CURRENT_TIMESTAMP());
I wonder if this will generate totally collision free strings or not?
You could use uuid() and remove the dashes from the result... that is the closest thing I can think of that would give you anything reliably unique.
select concat("table_prefix_", replace(uuid(), '-', '')) as unique_name;
it would end up being like this:
mysql> select concat("table_prefix_",replace(uuid(), '-', '')) as unique_name;
+-----------------------------------------------+
| unique_name |
+-----------------------------------------------+
| table_prefix_39f14dd9418011e3bd86c0cb38cd4f18 |
+-----------------------------------------------+
1 row in set (0.00 sec)
Related
I want to write a SELECT statement, where the tablename is based on the response to a different SELECT query. I can't use stacked queries, and I can only use MySQL.
As pseudo-code, this is what I'd like to do:
tablenamevariable = (SELECT 'tablename');
SELECT * FROM tablenamevariable;
Which should be equivalent to executing SELECT * FROM tablename (where the string tablename comes from the database).
What I have so far is the following, which executes successfully:
SELECT * FROM (SELECT 'tablename') AS x;
However, the result simply prints tablename (which isn't what I want).
The background is an SQL injection which upper-cases all input. So what I want to do is SELECT * FROM (SELECT CHAR([...] USING UTF8MB4)) to be able to select data from a table with lower-case characters in the name.
You can't use a string as an identifier in the same query.
A subquery or an expression can return a string, but not an identifier.
So your subquery like select ... from (select ...) as x doesn't work the way you think. It will not query from the table named by the string. It will query from a derived table which consists of the string value returned by the subquery.
mysql> select * from (select 'abc' as tablename) as x;
+-----------+
| tablename |
+-----------+
| abc |
+-----------+
The reason for this is that in SQL, all identifiers must be fixed at the time the query is parsed, before it evaluates any expressions. This is so the table names can be validated that the corresponding tables exist, and you have SQL privileges to read those tables.
Another reason is that if the subquery worked the way you expect, then there would be no way to simply query strings from a subquery without querying an hypothetical table named by those strings. Also what would you expect it to do if the subquery returned multiple columns or multiple rows?
You clarified in an edit that what you're trying to do is to query a table after your query is formatted with uppercase table names, regardless of how the table was defined.
Case-sensitivity of identifiers in MySQL is a bit complex, because MySQL has versions on different operating systems, some of which have case-sensitive filesystems and some have case-insensitive filesystems.
But the result is that in most cases, it doesn't matter that your table names are uppercase in your query. Table name comparisons are case-insensitive by default on an OS that has uses case-insensitive filesystems.
mysql> select * from mytable limit 1;
+----+-------+
| pk | name |
+----+-------+
| 3 | hello |
+----+-------+
mysql> select * from MYTABLE limit 1;
+----+-------+
| pk | name |
+----+-------+
| 3 | hello |
+----+-------+
mysql> select * from MyTable limit 1;
+----+-------+
| pk | name |
+----+-------+
| 3 | hello |
+----+-------+
(Test performed on MySQL 8.0.31 on MacOS)
On UNIX and Linux, the default is that table comparisons are case-sensitive. But there is an option to configure this if you want it to work in a case-insensitive manner on UNIX or Linux. You should read https://dev.mysql.com/doc/refman/8.0/en/identifier-case-sensitivity.html to understand how this works on different operating systems, and the option you can use to control it.
To do that you would need to use prepared statements:
set #t = 'tablename';
PREPARE stmt FROM concat('select * from ', #n);
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
It is highly unusual that you would need to do that though.
Synopsis
I would like to use multiple REGEXP_REPLACE function calls in a SELECT statement. The idea is to replace different expressions with different values.
Using a single call to REGEXP_REPLACE works perfectly fine. Anyone with a first name that doesn't start with T is displayed as NOT TREVOR, and anyone who has a name starting with T is simply displayed as-is.
DROP DATABASE cbtnuggets;
CREATE DATABASE cbtnuggets;
CREATE TABLE IF NOT EXISTS cbtnuggets.people (firstName varchar(30));
INSERT INTO cbtnuggets.people (firstName) VALUES ('Trevor'), ('Daniel'), ('Sally');
SELECT
REGEXP_REPLACE(firstName, '^[^T].*', 'NOT TREVOR')
FROM cbtnuggets.people;
Problematic Query
The following query does not work the way that I would like for it to. Due to the OR statement, the result is a 0 or 1, instead of a string.
DROP DATABASE cbtnuggets;
CREATE DATABASE cbtnuggets;
CREATE TABLE IF NOT EXISTS cbtnuggets.people (firstName varchar(30));
INSERT INTO cbtnuggets.people (firstName) VALUES ('Trevor'), ('Daniel'), ('Sally');
SELECT
REGEXP_REPLACE(firstName, '^[^T].*', 'NOT TREVOR')
OR REGEXP_REPLACE(firstName, '^T', 'This is Trevor')
FROM cbtnuggets.people;
Expected Result
I would like to return different values for different expressions in a single SELECT statement (if possible), using the REGEXP_REPLACE function.
Question
Is there any way to handle this desired result in a select statement, or would I need to create a MySQL function to handle these multiple expressions?
You can run one regexp_replace(), which returns a string, and that string can be the input to another regexp_replace().
mysql> select regexp_replace(regexp_replace('Frank', '^T.*', 'This is Trevor'), '^[^T].*', 'This is not Trevor') as newlabel;
+--------------------+
| newlabel |
+--------------------+
| This is not Trevor |
+--------------------+
1 row in set (0.00 sec)
mysql> select regexp_replace(regexp_replace('Trevor', '^T.*', 'This is Trevor'), '^[^T].*', 'This is not Trevor') as newlabel;
+----------------+
| newlabel |
+----------------+
| This is Trevor |
+----------------+
1 row in set (0.00 sec)
This usage works, but it's pretty confusing to write, especially if you have more than two patterns to check. I'd try to use a different approach.
I'm not even sure you need regex here for your query:
SELECT
CASE WHEN firstName LIKE 'T%'
THEN 'This is Trevor'
ELSE 'NOT TREVOR' END AS label
FROM cbtnuggets.people;
The REGEXP_REPLACE function is intended to take an input string and output a modification of that input, rather than a boolean value. If you did want to assert a regex pattern against a string, then use REGEXP:
SELECT
CASE WHEN firstName REGEXP '^T'
THEN 'This is Trevor'
ELSE 'NOT TREVOR' END AS label
FROM cbtnuggets.people;
Can you create a table in mysql with dots (.) in it?
I´m having trouble manipulating a table with a dot in its name. I did it this way as a shortcut for a php query.
You can create table names with punctuation by delimiting the identifiers with back-ticks.
mysql> create table `my...table` (id serial primary key);
Query OK, 0 rows affected (0.05 sec)
mysql> insert into `my...table` values (1234);
Query OK, 1 row affected (0.02 sec)
mysql> select * from `my...table`;
+------+
| id |
+------+
| 1234 |
+------+
It's legal, but probably more trouble than it's worth. You have to remember to use the back-ticks every time you reference the table.
A good compromise is to use _ instead of a dot, because you don't have to delimit the table name for that character.
You could quote the table name(s) with back-ticks — or, if you have control over it, and it's not too late, substitute the special characters with a standardized alternative:
select * from `table.name`
Permissible characters (without the need for quotes):
[0-9,a-z,A-Z$_]
I've got a table which contains a varchar(1024) field, which in that contains strings which has hex encoded strings. This table is filled automatically and I have to provide an SP to allow users to download this, therefore, I need to change the hex back into human readable form.
If I manually run this statement (taking the Hex data from the field), it works just fine:
SELECT X'5468697320697320612074657374206D6573736167652031323334353637383930';
But I cannot find a working example of getting this to work when calling the field/column name. I've found a few examples, but these just return a null or 0.
I've tried X and UnHex() and neither give me a result.
Where am I going wrong?
Thanks
EDIT:
Okay, after doing a bit more testing, it appears it must be the way it's being written to the database in the first place.
It's a Classic ASP page that calls an SP, which creates the database entry. In this method, the write to the DB works, and I can see the HEX content in the field. Copying the content of the field, and putting this into a Select X'123123' gives me the ASCII values, as I want.
If I try this as a Select, this fails, giving me a zero or Null return.
SELECT Message_Body_Hex, UNHEX(Message_Body_Hex) FROM messages_inbound
returns:
Message_Body_Hex......unhex(Message_Body_Hex)
417265612032........(NULL)
Still confused! :)
I realize this is an old question but I ran into this same problem today and solved it using a combination of HEX and CAST. Using your example, try this:
SELECT HEX(CAST(X'5468697320697320612074657374206D6573736167652031323334353637383930' AS CHAR(33)))
When pulling from a table you'd substitute the field name:
SELECT HEX(CAST(binary_field AS CHAR(33)))
I've seen other answers recommending to use MAX in place of the 33 but this appears to work fine. Here are some sources I used:
SQL Server converting varbinary to string
and
How to convert from varbinary to char/varchar in mysql
Using the UNHEX() function seems to work fine on MySQL 5.5.29-1:
mysql> create table t1 ( f1 varchar(1024) );
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t1 values('5468697320697320612074657374206D6573736167652031323334353637383930');
Query OK, 1 row affected (0.02 sec)
mysql> select f1 from t1;
+--------------------------------------------------------------------+
| f1 |
+--------------------------------------------------------------------+
| 5468697320697320612074657374206D6573736167652031323334353637383930 |
+--------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> select unhex(f1) from t1;
+-----------------------------------+
| unhex(f1) |
+-----------------------------------+
| This is a test message 1234567890 |
+-----------------------------------+
1 row in set (0.00 sec)
Environment: MySQL 5.1, Linux
I have a stored procedure that computes several values from a single input value. The values are returned as OUT parameters. I would like to call this procedure for every row set and have the values appear as columns in the result set. The values have a complex relationship such that distinct functions for each value is not easily constructed.
The question: How can I get OUT parameters to show up as columns in a table?
Here's what I have so far:
DELIMITER $_$
DROP PROCEDURE IF EXISTS in_out;
CREATE PROCEDURE in_out (
IN s TEXT,
OUT op TEXT,
OUT opn INT,
OUT opd TEXT,
OUT len INT
)
BEGIN
SET op = 'del';
SET opn = 1;
SET opd = substr(s,4);
SET len = LENGTH(SUBSTR(s,4));
END
$_$
DELIMITER ;
Then:
mysql> call in_out('delACT',#op,#opn,#opd,#len);
Query OK, 0 rows affected (0.00 sec)
mysql> select #op,#opn,#opd,#len;
+------+------+------+------+
| #op | #opn | #opd | #len |
+------+------+------+------+
| snv | 1 | ACT | 3 |
+------+------+------+------+
1 row in set (0.00 sec)
So far so good, but I can't figure out how to call this procedure for every row and return the results in the result set. I want is something like this:
dream> select mycol,in_out(mycol) from mytable
+---------+------+------+------+------+
| mycol | #op | #opn | #opd | #len |
+---------+------+------+------+------+
| delACT | del | 1 | ACT | 3 |
+---------+------+------+------+------+
Thanks!
You confuse the stored procedures and stored functions:
stored function will be return a value, the results can be used in
expressions (like COS() and other mysql built-in functions).
stored procedure need use CALL , is an independent operation, can not
be used in expressions.
If you want to "select mycol,in_out(mycol) from mytable",you must:
CREATE FUNCTION in_out( ...
This appears to be a trick question: one can't create table relations out of function/procedure results in MySQL. I ended up refactoring into separate functions (as suggested by Michał). I had been hoping for a MySQL equivalent to PostgreSQL's table functions (http://goo.gl/77QVE).
I'd recommend to prepare data in stored procedure for each possible value in:
select distinct mycol
from mytable
where <... condition that you would use anyway in final result ...>
where mycol is your parameter for stored procedure save it to temporary table and than join to this values.
-- way the temp table may look in your sp
create temporary table tmptable (
mycol text
op text,
opn int,
opd text,
len int
)
after that use join:
select m.mycol, t.op, t.opn, t.opd, t.len
from mytable m
join tmptable t on m.mycol = t.mycol
where <... condition that you would use anyway in final result ...>
Bit different question, are you absolutely sure that there is no different way to process your final result than using a stored procedure?