I'm looking for way to create a MySQL column where a SELECT statement will automatically display any value formatted as hexadecimal:
1 -> 0x1
16 -> 0x10
Here is an example that achieved basically this result, but the problem is that any user of this data will have to do the processing (http://sqlfiddle.com/#!9/3bc633/2):
Create data:
CREATE TABLE t1 (
c1 int
);
INSERT INTO t1 (c1) VALUES
(0x1),
(0x10);
Select the data:
SELECT c1, CONCAT('0x', HEX(c1))
FROM t1;
I would like to set a property on the column or table, to achieve this result with a simple SELECT c1.
CREATE TABLE t1 (
c1 int,
c2 varchar(32) GENERATED ALWAYS AS (CONCAT('0x', HEX(c1)))
);
MariaDB [test]> INSERT INTO t1 (c1) VALUES
-> (0x1),
-> (0x10);
Query OK, 2 rows affected (0.14 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [test]> select * from t1;
+------+------+
| c1 | c2 |
+------+------+
| 1 | 0x1 |
| 16 | 0x10 |
+------+------+
2 rows in set (0.00 sec)
Or, if you use an older version, it will probably be
CREATE TABLE t1 (
c1 int,
c2 varchar(32) AS (CONCAT('0x', HEX(c1))) VIRTUAL
);
But the same principle apply.
Related
I need to do do an insert where 2 values will be constant and the third will change. So, something like the following:
INSERT INTO
`example_table`(column_a, column_b,column_c)
SELECT 1, [3,4], 409187710
from `example_table`
Desired Result:
column_a
column_b
column_c
1
3
409187710
1
4
409187710
Just to be clear the number of values I need to insert into column_b will vary - sometimes I will need to insert 2 values, sometimes I may need to insert 10 values, but columns a and c will always have the same values. How do I perform such an insert?
My question differs from this question in that a sql case statement will not suffice. This is a different kind of problem.
MySQL 8.0 has a new kind of statement: VALUES.
mysql> create table example_table (column_a int, column_b int, column_c int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into example_table
-> select 1, column_0, 409187710 from (values row(3), row(4)) as t;
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from example_table;
+----------+----------+-----------+
| column_a | column_b | column_c |
+----------+----------+-----------+
| 1 | 3 | 409187710 |
| 1 | 4 | 409187710 |
+----------+----------+-----------+
If you use a version of MySQL that doesn't support the VALUES statement, you can use this syntax:
mysql> insert into example_table
-> select 1, b, 409187710 from (select 3 as b union select 4) as t;
I have two tables:
Table 1: qtrade
qtrade columns
qtrade values
Table 2: qsale
qsale columns
qsale values
These two table have common "tid" which is unique trade id. I need to get tid's with their qsale values if it is available. So, i tried to LEFT JOIN method like this:
'SELECT *
FROM `qtrade`
LEFT JOIN `qsale` ON qtrade.tid = qsale.tid'
The query retrieves joined data, but for tid=11 there is no qsale record, so it retrieves NULL valeus as expected, but also overrides tid with NULL value as not expected. It gets tid NULL.
I have serached that and found COALESCE trick. It might work, but i would write down all column names in qtrade and qsale, these are around 32 columns. Too long. If there any trick to overcome this issue. I think 'SELECT *, COALESCE(qsale.tid, qtrade.tid) tid' will not work. Meaning only coalesce tid, and get all column data. Is there any other way ?
What you describe does work.
Demo:
mysql> create table qtrade (tid int);
Query OK, 0 rows affected (0.01 sec)
mysql> create table qsale (tid int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into qtrade set tid=42;
Query OK, 1 row affected (0.01 sec)
mysql> SELECT *
-> FROM `qtrade`
-> LEFT JOIN `qsale` ON qtrade.tid = qsale.tid;
+------+------+
| tid | tid |
+------+------+
| 42 | NULL |
+------+------+
1 row in set (0.00 sec)
mysql> SELECT *, COALESCE(qsale.tid, qtrade.tid) AS tid
FROM `qtrade` LEFT JOIN `qsale` ON qtrade.tid = qsale.tid;
+------+------+------+
| tid | tid | tid |
+------+------+------+
| 42 | NULL | 42 |
+------+------+------+
1 row in set (0.00 sec)
MySQL query result sets allow multiple columns to have the same name.
But the problem arises when you have a client that fetches the results into an associative array or hashmap, which only allows one entry per name.
In that case, the only alternative is to change the client code to fetch results into an ordinal array instead of an associative array, and then reference the columns of the result by position instead of by name.
I never use SELECT * in production code anyway. Just write out the columns. If typing 32 column names is the bottleneck in your programming productivity, then you're doing it wrong.
Case
In our MySql database the data is stored in combined json-strings like this:
| ID | DATA |
| 100 | {var1str: "sometxt", var2double: 0,01, var3integer: 1, var4str: "another text"} |
| 101 | {var3integer: 5, var2double: 2,05, var1str: "txt", var4str: "more text"} |
Problem
Most of the DATA-fields hold over 2500 variables. The order of variables in the DATA-string is random (as shown in above example). Right now we only know how to extract data with the following querie:
select
ID,
json_extract(DATA,'var1str'),
json_extract(DATA,'var2double'),
FROM table
With this querie, only the values of var1str and var2double will be returned as result. Values of variable 3 and 4 are ignored. There is no overview of what possible variables are hiding in the data fields.
With almost 60.000 entries and over 3.000 possible unique variable names, I would like to create a query that loops through all of the 60.000 DATA-fields and extracts every unique variable name that is found in there.
Solution?
The querie I am looking for would give the following result:
var1str
var2double
var3integer
var4str
My knowledge of MySql is very limited. Any direction given to get to this solution is much appreciated.
What version of MySQL are you using?.
From MySQL 8.0.4 and later JSON_TABLE function is supported and can be useful in this case.
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 8.0.11 |
+-----------+
1 row in set (0.00 sec)
mysql> DROP TABLE IF EXISTS `table`;
Query OK, 0 rows affected (0.09 sec)
mysql> CREATE TABLE IF NOT EXISTS `table` (
-> `ID` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-> `DATA` JSON NOT NULL
-> ) AUTO_INCREMENT=100;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `table`
-> (`DATA`)
-> VALUES
-> ('{"var1str": "sometxt", "var2double": 0.01, "var3integer": 1, "var4str": "another text"}'),
-> ('{"var3integer": 5, "var2double": 2.05, "var1str": "txt", "var4str": "more text"}');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT
-> DISTINCT `der`.`key`
-> FROM
-> `table`,
-> JSON_TABLE(
-> JSON_KEYS(`DATA`), '$[*]'
-> COLUMNS(
-> `key` VARCHAR(64) PATH "$"
-> )
-> ) `der`;
+-------------+
| key |
+-------------+
| var1str |
| var4str |
| var2double |
| var3integer |
+-------------+
4 rows in set (0.01 sec)
Be aware of the Bug #90610 ERROR 1142 (42000) when using JSON_TABLE.
I have a "person" column in a mySQL database that represents the age and weight of a person as a string separated by a comma.
Example:
"24,175"
I want to be able to separate and extract those values and cast them as numbers.
Example: turn "24,175" to
24 as age
175 as weight
So that I can write a query similar to the following
SELECT person
FROM TABLE
WHERE age>140 OR weight>1000
I want to be able to check for values that are not possible. i.e age>140 OR weight >1000.
I cannot modify the table/environment I'm working with
I only have access to queries.
I'm thinking about solving it this way
find the index where the comma exists. CHARINDEX(',',person)
Split the string into substrings using LEFT , RIGHT, CAST and CHARINDEX(',',person)
Cast age substring and weight substring to numbers using CAST(age AS INT) CAST(weight AS INT)
SELECT person
FROM TABLE
WHERE CAST(LEFT(person,CHARINDEX(',',person) AS INT)>150 OR CAST(RIGHT(person,CHARINDEX(',',person) AS INT) >1000
If I did anything wrong please correct me.
Are all the functions usable/supported by mySQL? (RIGHT, LEFT, CHARINDEX) Will this work?
Exception: Another value for this column could be "unknown". Will this cause errors if we're trying to check for the index of , if it doesn't exist in the string? Is there a way to include "unknown" cases in the result and have it output a message of "error, person not recognized"
you can also split is with SUBSTR_INDEX like this:
MariaDB [yourschema]> SELECT * FROM spliit;
+----+--------+
| id | d |
+----+--------+
| 1 | 24,175 |
+----+--------+
1 row in set (0.03 sec)
MariaDB [yourschema]> SELECT
-> SUBSTRING_INDEX(d, ',', 1) AS age
-> , SUBSTRING_INDEX(d, ',', -1) AS weight
->
-> FROM spliit;
+------+--------+
| age | weight |
+------+--------+
| 24 | 175 |
+------+--------+
1 row in set (0.00 sec)
MariaDB [yourschema]>
sample
yes, you can direct calculate with it in MySQL
MariaDB [yourschema]> SELECT
-> SUBSTRING_INDEX(d, ',', 1) + 2 AS age
-> , SUBSTRING_INDEX(d, ',', 1) * 12 AS `month`
-> , SUBSTRING_INDEX(d, ',', -1) + 3 AS weight
-> FROM spliit;
+------+-------+--------+
| age | month | weight |
+------+-------+--------+
| 26 | 288 | 178 |
+------+-------+--------+
1 row in set, 1 warning (0.03 sec)
MariaDB [yourschema]>
SELECT person
FROM TABLE
WHERE CAST(LEFT(person,LOCATE(',',person) AS INTEGER)>150 OR CAST(RIGHT(person,(LOCATE(',',person)+1) AS INTEGER) >1000
Instead of Char index use LOCATE im MqSQL
Also note the CAST function
You also can use VIRTUAL PERSITENT COLUMNS that calculate the fields automatis and you can also use a INDEX on each substr / Integer.
sample
MariaDB [yourschema]> CREATE TABLE `splitit` (
-> `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
-> `d` VARCHAR(32) DEFAULT NULL,
-> age INT(11) AS (SUBSTRING_INDEX(d, ',', 1)) PERSISTENT,
-> weight INT(5) AS (SUBSTRING_INDEX(d, ',', -1)) PERSISTENT,
-> PRIMARY KEY (`id`),
-> INDEX idx_age (age),
-> INDEX idx_weight (weight)
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.79 sec)
MariaDB [yourschema]> INSERT INTO splitit (d) VALUES ('11,234'),('2,66'),('5,2');
Query OK, 3 rows affected (0.06 sec)
Records: 3 Duplicates: 0 Warnings: 0
MariaDB [yourschema]> SELECT * FROM splitit;
+----+--------+------+--------+
| id | d | age | weight |
+----+--------+------+--------+
| 1 | 11,234 | 11 | 234 |
| 2 | 2,66 | 2 | 66 |
| 3 | 5,2 | 5 | 2 |
+----+--------+------+--------+
3 rows in set (0.00 sec)
MariaDB [yourschema]>
You can do this all in the where clause:
where substring_index(person, ',', 1) + 0 > 140 or
substring_index(person, ',' -1) + 0 > 1000
Note that the + 0 does an silent conversion to integers. And, substring_index()is much more convenient than the functions in SQL Server.
You can readily incorporate this logic into a view:
create view v_table as
select t.*,
substring_index(person, ',', 1) + 0 as age,
substring_index(person, ',' -1) + 0 as weight
from table t;
If you want to filter out bad values within the view, you can use a MySQL extension and add:
having age > 140 or weight > 1000
after the from clause.
I would like to fill a table with the results of a query on existing table. How can I do that?
(You don't need to match the table schemas)
INSERT tbl_name (col1, col2)
SELECT value1, value2
FROM othertable
See the reference for INSERT ... SELECT Syntax
insert into table_name ...
select * from table_name where ....
The target table and the source query must match in number of columns and datatypes
See this link
You can even create tables this way, though there the column names must match, or the select results are put in automatically added columns:
mysql> create table foo ( id int primary key auto_increment, bar datetime )
-> select now() as bar, now() as baz from dual;
Query OK, 1 row affected, 1 warning (0.06 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from foo;
+----+---------------------+---------------------+
| id | bar | baz |
+----+---------------------+---------------------+
| 1 | 2009-03-10 17:01:35 | 2009-03-10 17:01:35 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)