Select Statement using Mysql - 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
;

Related

SQL comparing strings from two tables with different data formats

I have two tables, with different columns that I would like to compare. There is an issue in our system with serial numbers, and I want to make sure that all of the serial numbers (CMMTTEXT - in comma delimitted form) in Table B are being transferred to Table A (SERLTNUM - where each individual serial number has its own line)
Basically, what I would like to try and do is take the SOPNUMBER's from the last 3 months (which I would get from Table C), then get all rows from Table B and Table A with the last 3 months SOPNUMBER's and then somehow to make sure all serial numbers in CMMTTEXT in Table B are in Table A as SERLTNUM.
I know how to get all of the data, but I'm not sure what I can do in order to compare the two columns in SQL when they have different data formats. I am trying to think if there is someway I can just use substr() to search CMMTTXT but don't know how I could then display rows where there was no match found.
The LNITMSEQ table is an ID that corresponds to different line items in an order.
Table A
+-----------+----------+----------+---------------+
| SOPNUMBER | LNITMSEQ | SERLTNUM | ITEMNMBR |
+-----------+----------+----------+---------------+
| I327478 | 16384 | ABC123 | someItem |
+-----------+----------+----------+---------------+
| I327478 | 32768 | DEF123 | someOtherItem |
+-----------+----------+----------+---------------+
Table B
+-----------+----------+-----------------------------+
| SOPNUMBER | LNITMSEQ | CMMTTEXT |
+-----------+----------+-----------------------------+
| I327478 | 16384 | ABC123,ABC124,ABC125,ABC126 |
+-----------+----------+-----------------------------+
| I327478 | 32768 | DEF123,DEF124,DEF125,DEF126 |
+-----------+----------+-----------------------------+
Table C
+-----------+-----------+
| SOPNUMBER | DATE |
+-----------+-----------+
| I327478 | 5/20/2017 |
+-----------+-----------+
| I327479 | 5/21/2017 |
+-----------+-----------+
I have commented above, but a clearer answer can be found here for what you need:
SQL split values to multiple rows
You can use FIND_IN_SET function like as follows
SELECT * FROM TableA INNER JOIN TAableB
ON FIND_IN_SET(TableA.SERLTNUM, TableB.CMMTTEXT) > 0
FIND_IN_SET function returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. for more detail see the manual

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.

How to replace substring in mysql where string is based on other table-column values

I have two mysql tables as
Component
+----+-------------------------+--------+
| OldComponentId | NewComponentId |
+----+-------------------------+--------+
| 15 | 85 |
| 16 | 86 |
| 17 | 87 |
+----+-------------------------+--------+
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+15-16+17 |
| 2 | 16+15-17 |
+----+-------------------------+--------+
I want to replace value of formula_string on the basis of NewComponentId as
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+85-86+87 |
| 2 | 86+85-87 |
+----+-------------------------+--------+
I have tried with following mysql query but its not working
update Formulae fr, Component comp set formula_string=REPLACE(fr.formula_string,comp.OldComponentId,comp.NewComponentId).
Please suggest the solutions
thanks.
There is no easy way to do this. As you observed in your update statement, the replacements don't nest. They just replace one at a time.
One thing that you can do is:
update Formulae fr cross join
Component comp
set formula_string = REPLACE(fr.formula_string, comp.OldComponentId, comp.NewComponentId)
where formula_string like concat('%', comp.OldComponentId, '%')
Then continue running this until row_count() returns 0.
Do note that your structure could result in infinite loops (if A --> B and B --> A). You also have a problem of "confusion" so 10 would be replaced in 100. This suggests that your overall data structure may not be correct. Perhaps you should break up the formula into separate pieces. If they are just numbers and + and -, you can have a junction table with the value and the sign for each component. Then your query would be much easier.

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

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 |
+--------------------------------------+---------------+----------------+

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