How to get MySQL command line tool to show booleans stored as BIT sensibly by default - mysql

I got a problem with selecting boolean types stored as BIT with MySQL. I know that I can get bit values shown in a sensible with with custom queries like with SELECT CAST(1=1 AS SIGNED INTEGER) or with SELECT BOOLFIELD + 0 ...
However, is there any way to get our booleans shown in a sensible way with command line client with queries like SELECT * FROM TABLE ?
UPDATE : At the moment I see only space in the results Example:
mysql> SELECT distinct foo, foo + 0 from table
+------+-------+
| foo | foo_0 |
+------+-------+
| | 0 | <-- Only space
| | 1 | <-- Space, one space less
+------+-------+
With some googling, I found some (maybe related) bugs from MySQL bug DB (http://bugs.mysql.com/bug.php?id=28422, http://bugs.mysql.com/bug.php?id=43670) but not answer or fix?

To store booleans, one really ought to use MySQL's BOOLEAN type (which is an alias for TINYINT(1), given that MySQL doesn't have real boolean types): 0 represents false and non-zero represents true.
Whilst it might feel like storing a boolean in a byte is more wasteful than in a BIT(1) column, one must remember that a few saved bits will translate into more bit operations for the CPU on data storage & retrieval; and I'm unsure whether most storage engines pad BIT columns to the next byte boundary anyway.
If you insist on using BIT type columns, you should be aware that they are returned as binary strings. The MySQL command line client (stupidly) attempts to render binary strings as textual (by applying its default character set), which is what causes the behaviour that you observe—there's no way to avoid this (other than to manipulate the field in the select list in order that it as returned as something other than a binary string, as you are already doing).
However, if you also insist on using SELECT * (which is bad practice, albeit somewhat more understandable from the command line client), you might consider defining a view in which the manipulation is performed and then SELECT from that. For example:
CREATE VIEW my_view AS SELECT foo + 0 AS foo, bar FROM my_table;
Then one could do:
SELECT * FROM my_view WHERE foo = 1 AND bar = 'wibble';

A BIT ugly, but maybe some workaround: CASE WHEN ... THEN ... END
Instead of
> select
guid,
consumed,
confirmed
from Account
where customerId = 'xxxx48' and name between xxxx and xxxx;
+--------------------------------------+----------+-----------+
| guid | consumed | confirmed |
+--------------------------------------+----------+-----------+
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | | |
+--------------------------------------+----------+-----------+
One could do:
> select
guid,
case when consumed then '1' when not consumed then '0' end as been_consumed,
case when confirmed then '1' when not confirmed then '0' end as been_confirmed
from Account
where customerId = 'xxxx48' and name between xxxx and xxxx;
+--------------------------------------+---------------+----------------+
| guid | been_consumed | been_confirmed |
+--------------------------------------+---------------+----------------+
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 1 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 1 |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | 1 | 0 |
+--------------------------------------+---------------+----------------+

Related

MS Access - Data Type Mismatch in Criteria Expression

Using the query grid , comparing a String field with a Replace function result of another String field (same table) results in a Data Type Mismatch error when trying to filter for ‘Not Like’ (or <>).
‘TypeName’ confirms that all records are of type “String”.
The problem is caused by “MyStrCalc: Replace([StrA],".","_")” which is compared with StrB. StrA contains Null for some records. These are filtered out (Criterium = “Is Not Null”). But even when creating a new query that uses the result of the first, the same error occurs. I have also tried Nz.
If I use Make Table to create a new table where StrA “Is Not Null” and run effectively the same query, there’s no issue.
The data in the table changes frequently, so having to create a separate table every time (tens of thousands of records) is a real nuisance.
Any suggestions how to make the query work would be greatly appreciated.
(By the way – the version used is MS Access 2019 under Windows 10, both with latest updates.)
Thank you for your much appreciated quick reply.
I tried a few things as detailed below with the fourth attempt providing the desired result.
Source table t1:
| UID | StrA | StrB |
| ---:| ----- | ----- |
| 1 | Str.1 | Str_1 |
| 2 | | Str_2 |
| 3 | Str.3 | Str_4 |
Desired Result = StrA<>StrB after replacing dots in StrA with underscores:
| UID | StrA | StrB
| ---:| ----- | -----
| 2 | | Str_2
| 3 | Str.3 | Str_4
q1_Bad:
SELECT t1.UID, t1.StrA, t1.StrB, Replace([StrA],".","_",1,-1,1) AS StrACalc
FROM t1
WHERE (((Replace([StrA],".","_",1,-1,1)) Not Like [StrB]));
Result: “Data type mismatch in criteria expression”.
q2_Runs_CannotFilter:
SELECT t1.UID, t1.StrA, t1.StrB, Replace([StrA],".","_",1,-1,1) AS StrACalc, [StrACalc] Not Like [StrB] AS StrACalc_NtEq_StrB
FROM t1
WHERE (((t1.StrA) Is Not Null));
Result: Runs, but filtering field ‘StrACalc_NtEq_StrB’ (SQL or after running query) results in “Data type mismatch in criteria expression”.
q3_OK_SQL_FilterFail:
SELECT t1.UID, t1.StrA, t1.StrB, Replace(Nz([StrA]),".","_",1,-1,1) AS StrACalc, Nz([StrACalc] Not Like [StrB]) AS StrACalc_NtEq_StrB
FROM t1;
Result: Runs, but filtering field ‘StrACalc_NtEq_StrB’ is only possible after running query. Adding “Nz([StrACalc] Not Like [StrB]) AS StrACalc_NtEq_StrB” results in “Enter Parameter Value | StrACalc”.
Note: If the result of the above is called in another query, the SQL filtering will work.
q4_OK
SELECT t1.UID, t1.StrA, t1.StrB
FROM t1
WHERE (t1.StrB) Not Like Replace(Nz([StrA]),".","_",1,-1,1);
Finally – Desired result:
| UID | StrA | StrB |
| ---:| ----- | ----- |
| 2 | | Str_2 |
| 3 | Str.3 | Str_4 |

Why this sql is correct? (sql injection)

What does it mean?
SELECT * from users where password = ''*'';
if I check this in mysql workbench I get only one line, although I have lot of users in table.
What exactly does this select?
Interesting question. Let's see what ''*'' does.
mysql> select ''*'';
+-------+
| ''*'' |
+-------+
| 0 |
+-------+
Let's create some users:
mysql> select * from users;
+------+-------+
| id | name |
+------+-------+
| 1 | joe |
| 2 | moe |
| 3 | shmoe |
| 4 | 4four |
+------+-------+
And test our query:
mysql> select * from users where name = ''*'';
+------+-------+
| id | name |
+------+-------+
| 1 | joe |
| 2 | moe |
| 3 | shmoe |
+------+-------+
Interestingly enough, user 4 was not selected! But let's try this way:
mysql> select * from users where name = 4;
+------+-------+
| id | name |
+------+-------+
| 4 | 4four |
+------+-------+
So, what can we deduct from this?
''*'' somehow means 0 (I am not that fluent in mysql string operators, so let's take it as a fact);
MySQL, apparently, does type conversions in this case. So if you query a varchar column against an integer, it tries to convert those strings to ints and see if it's a match;
You have only one row whose password begins with 0 or non-digit.
You can always use an expression in SQL. Like SELECT 5-4 AS one and get 1. So you can tell that here is an expression.
MySQL is a loosely typed language, so it can multiply strings. Casting them to numbers. And get you zero as a result of '' * ''
When comparing a string with a number, MySQL casts both to a number. So 0 = 'name' condition will get you true
The ''*'' is a multiplication: its two arguments (empty strings) are converted to numericals (i.e. 0) and the result is 0. Then the left side of the equation is also converted to a number, which will sometimes be zero (when the password cannot be evaluated to a non-zero number), sometimes not.
It is a bit obscure, and you could ask yourself whether this was intended in your case or an accidental behaviour, while the actual intention was to test for '*'. A user with bad intentions might have entered '*' as a password hoping you were not protected against SQL injection in order to get into the system without a valid password.

Select Statement using Mysql

I am new to using databases,
I have a table ( easy_drinks )
+------------+-------------+---------+
| Drink_name | main | amount1 |
+------------+-------------+---------+
| Blackthorn | Blackthorn | 1.5 |
| BlueMoon | soda | 1.5 |
| OhMyGosh | peachnectar | 1 |
+------------+-------------+---------+
I have a Query
SELECT Drink_name 
FROM easy_drinks 
WHERE main > 'soda'
;
It is giving results as Blakcthorn
Can you please explain how string comparison occurs between i.e with main and 'soda' ?
It compairs the strings using the underlying values of the collation the fields use in a lexiographic order. That means that capitals are "bigger" (before) non capitals.
Note: If both strings use a different collation, one will be converted.
If you do not prefer to distinguish capitals and non capitals use something like
SELECT Drink_name 
FROM easy_drinks 
WHERE LOWER(main) > 'soda'
;
You can also use the strcmp function (see here ).
SELECT Drink_name 
FROM easy_drinks 
WHERE strcmp(LOWER(main),'soda') = 1
;

MySQL - IF something, THEN also select where

So, I have a confusing MySQL issue. I feel like I need to use some IF statements, but I'm really not sure how to implement them into this situation! First, consider the following query. It's simple:
SELECT *
FROM flow
INNER JOIN flow_strings
USING(node_id)
WHERE
(
flow.parent = 0
OR flow.parent = :user_flow
)
AND flow.source = 0
AND :input LIKE flow_strings.sql_regex
However, I need to expand it, and that's where I'm stuck. Thinking through this, I'm not really sure how to explain it, so following are the table structures, and then some examples.
TABLE flow
+---------+--------+--------+
| node_id | parent | source |
+---------+--------+--------+
| 1 | 0 | 0 |
+---------+--------+--------+
| 2 | 0 | 0 |
+---------+--------+--------+
| 3 | 1 | 1 |
+---------+--------+--------+
| 4 | 3 | 0 |
+---------+--------+--------+
TABLE flow_strings
+----------------+---------+-----------+
| flow_string_id | node_id | sql_regex |
+----------------+---------+-----------+
| 1 | 1 | fish |
+----------------+---------+-----------+
| 2 | 1 | wish |
+----------------+---------+-----------+
| 3 | 1 | *yes* |
+----------------+---------+-----------+
| 4 | 2 | *no* |
+----------------+---------+-----------+
| 5 | 2 | nay |
+----------------+---------+-----------+
| 6 | 3 | *herp* |
+----------------+---------+-----------+
[ ... ]
TABLE placeholder_variables
+-------------+--------+------+-------+
| variable_id | source | name | value |
+-------------+--------+------+-------+
| 1 | 0 | yes | sure |
+-------------+--------+------+-------+
| 2 | 0 | yes | yeah |
+-------------+--------+------+-------+
| 3 | 0 | no | nope |
+-------------+--------+------+-------+
| 4 | 1 | herp | derp |
+-------------+--------+------+-------+
NOW, here's what I need to happen based on :input.
"fish", "wish", "sure", or "yeah" ---SELECT flow.node_id 1
This is because "fish", "wish", and "*yes*" are all associated with flow.node_id 1. Note that *yes* is surrounded by asterisks, so instead of "yes" being interpreted literally, it instead draws the values from placeholder_variables.
"nope" or "nay" ---SELECT flow.node_id 2
This is because "*no*" and "nay" are associated with flow.node_id 2. Again, because of the asterisks, "no" is not interpreted literally, but "nope" matches because "no" is in the placeholder_variables table, even though "nope" is not in the flow_strings table.
"no" and "*no*" ---NO MATCH
Even though *no* is in flow_strings, it should not match because it has asterisks around it (and a corresponding placeholder_variable) which means it should not be interpreted literally, and so can only be evaluated by its corresponding placeholder variable's value(s).
"baby" ---NO MATCH
Even though "baby" does not have asterisks around it, it corresponds to flow.node_id 3, and that node's flow.source is 1.
"derp" ---NO MATCH
This is because placeholder_variables.source is 1 for *herp*, even though it is in the flow_strings table.
"*herp*" ---SELECT flow.node_id 4
Even though there are asterisks around *herp* in the flow_strings table, the corresponding placeholder_variable.source is 1.
** TO SUM UP **
No source = 1
Interpret placeholder_variables if the sql_regex is surrounded by asterisks, but only if the corresponding placeholder_variable's source is 0.
If source is 0, and no asterisks are present, interpret sql_regex literally.
I know that I can use MySQL's SUBSTRING() to work with the asterisks. I also know that, (as I am using PHP) I could theoretically split this into two queries, and then dynamically generate the second query by looping through the first. However, this would be both A) memory intensive, and B) sloppy.
So my question is this: Is it possible to do this using MySQL alone? If yes, how would you recommend I format it? You don't need to write the query for me, but if you could help me with some of the logic, I'd be very grateful! I have absolutely no idea what to try besides what I have already outlined, and I definitely don't want to do that.
Thanks!
You can use this solution:
SELECT a.*,
COALESCE(c.value, b.sql_regex) AS string #-- If there was a successful JOIN (sql_regex was a variable), then display the value of the "value" column in placeholder_variables, otherwise if the JOIN did not succeed (sql_regex was a literal value), just display sql_regex instead.
FROM flow a
JOIN flow_strings b ON a.node_id = b.node_id
LEFT JOIN placeholder_variables c #-- LEFT JOIN placeholder_variables on these conditions:
ON b.sql_regex LIKE '*%*' AND -- That sql_regex is a variable
REPLACE(b.sql_regex, '*', '') = c.name AND -- Match sql_regex up with the "name" column in placeholder_variables. We must replace the asterisks in sql_regex so that the values can match ("name" column do not contain asterisks)
c.source = 0
WHERE a.source = 0 AND
COALESCE(c.value, b.sql_regex) = :input -- If the string was interpreted as a placeholder variable, make the condition on the interpreted value in the placeholder_variables table ("name" column), otherwise, just make the condition on the sql_regex column.
SQLFiddle Demo

Disable scientific notation in MySQL command-line client?

I have a MySQL table with many numeric columns (some INT, some FLOAT). I would like to query it with the MySQL command-line client (specifically, mysql Ver 14.14 Distrib 5.1.41, for debian-linux-gnu (x86_64) using readline 6.1), like so:
SELECT * FROM table WHERE foo;
Unfortunately, if the value of any numeric field exceeds 10^6, this client displays the result in scientific notation, which makes reading the results difficult.
I could correct the problem by FORMAT-ing each of the fields in my query, but there are many of them and many tables I would like to query. Instead I'm hoping to find a client variable or flag I can set to disable scientific notation for all queries.
I have not been able to find one in the --help or the man page, nor searching Google or this site. Instead all I find are discussions of preserving/removing scientific notation when using <insert-programming-language>'s MySQL API.
Thank you for any tips.
::edit::
Here's an example table ...
mysql> desc foo;
+--------------+-------------+------+-----+-------------------+
| Field | Type | Null | Key | Default |
+--------------+-------------+------+-----+-------------------+
| date | date | NO | PRI | NULL |
| name | varchar(20) | NO | PRI | NULL |
| val | float | NO | | NULL |
| last_updated | timestamp | NO | | CURRENT_TIMESTAMP |
+--------------+-------------+------+-----+-------------------+
and some example values ...
mysql> select * from foo where date='20120207';
+------------+--------+--------------+---------------------+
| date | name | val | last_updated |
+------------+--------+--------------+---------------------+
| 2012-02-07 | A | 88779.5 | 2012-02-07 13:38:14 |
| 2012-02-07 | B | 1.00254e+06 | 2012-02-07 13:38:14 |
| 2012-02-07 | C | 78706.5 | 2012-02-07 13:38:15 |
+------------+--------+--------------+---------------------+
Now, the actual values I loaded into the third field are:
88779.5, 1002539.25, 78706.5390625
and they can be seen exactly if I manipulate the value:
mysql> select date, name, ROUND(val, 10), last_updated from foo where ...
+------------+---+--------------------+---------------------+
| 2012-02-07 | A | 88779.5000000000 | 2012-02-07 13:38:14 |
| 2012-02-07 | B | 1002539.2500000000 | 2012-02-07 13:38:14 |
| 2012-02-07 | C | 78706.5390625000 | 2012-02-07 13:38:15 |
Something in the client seems to be enforcing that I only be allowed to see six significant figures, even though there are more in the table.
If a query such as
mysql> select ROUND(*, 2) from foo ...
were possible, that would be great! Otherwise I can't really take the time to individually wrap 100 column names in "ROUND()" whenever I need to inspect some data.
Interestingly, I occasionally use a phpMyAdmin interface to browse the contents of some of these tables, and that interface also has this 6 significant figure limitation. So it's not limited to just the CLI.
Well, after reading the documentation more thoroughly, I still can't see any reason why a client would limit itself to displaying only 6 sig figs from a FLOAT (especially when the table itself is definitely storing more).
Nonetheless, an acceptable solution (for this weary user) is to change all my tables to use DECIMAL(16,4) instead of FLOAT. Unfortunately, this makes all my numbers show up with 4 decimal places (even if they're all '0'). But at least all numbers have the same width now, and my client never displays them in scientific notation or limits the number of sig figs in its output.
Wouldn't the CAST function allow you to request that the values for a certain field are returned as DECIMAL ? Not an expert and haven't tried it, but that would be the first thing I try.
I know this is old but this helped me.. I used a view..
create view foo2 as select date, name, ROUND(val, 10) val, last_updated from foo
Then just do your queries on foo2. also works in phpmyadmin