MySQL aggregate function problem - mysql

In the following example, why does the min() query return results, but the max() query does not?
mysql> create table t(id int, a int);
Query OK, 0 rows affected (0.10 sec)
mysql> insert into t(id, a) values(1, 1);
Query OK, 1 row affected (0.03 sec)
mysql> insert into t(id, a) values(1, 2);
Query OK, 1 row affected (0.02 sec)
mysql> select * from t
-> ;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
| 1 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from t where a < 4;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
| 1 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from t where a < 4 having a = max(a);
Empty set (0.00 sec)
mysql> select * from t where a < 4 having a = min(a);
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)

The HAVING clause is used to filter groups of rows. You reference min(a) and max(a) which (in the absence of any GROUP BY clause) aggregate over all a values in the table but then use a comparison against a single a value.
So which a value is MySQL supposed to use? All other RDBMSs that I know of would throw an error at this point however MySQL does allow this. From the docs
Standard SQL does not permit the HAVING clause to name any column
not found in the GROUP BY clause unless it is enclosed in an aggregate
function. MySQL permits the use of such columns to simplify
calculations. This extension assumes that the nongrouped columns will
have the same group-wise values. Otherwise, the result is
indeterminate.
So in your case from the results you are getting it appears that it ended up using 1 as the scalar value for a but this behaviour is not guaranteed and it could equally well have used 2 or any other existing a value.

Related

what syntax to use to update a SET column in mysql?

I created a column called oilcompany that has SET data (Hunt, Pioneer, Chevron, BP)
I can enter any one of those into the oilcompany column and change from one to another one but I can not figure out how to change from one oilcompany to multiple oilcompany (eg. Hunt and BP)... any suggestion?
In the MySQL documentation there are not examples for UPDATE statements, but I normally use two ways to update these kind of columns:
Using text values
Using numeric values
Creating the test environment
mysql> CREATE TABLE tmp_table(
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> oilcompany SET('Hunt', 'Pioneer', 'Chevron', 'BP')
-> );
Query OK, 0 rows affected (0.54 sec)
mysql> INSERT INTO tmp_table(oilcompany) VALUES ('Hunt'), ('Pioneer');
Query OK, 2 rows affected (0.11 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp_table;
+----+------------+
| id | oilcompany |
+----+------------+
| 1 | Hunt |
| 2 | Pioneer |
+----+------------+
2 rows in set (0.00 sec)
Alternative#1: Using Text Values
As a SET is a collection of ENUM elements, and any ENUM element can be treated as a string, then we can do things like:
mysql> UPDATE tmp_table
-> SET oilcompany = 'Hunt,BP'
-> WHERE id = 1;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM tmp_table;
+----+------------+
| id | oilcompany |
+----+------------+
| 1 | Hunt,BP |
| 2 | Pioneer |
+----+------------+
2 rows in set (0.00 sec)
Alternative#2: Using Numeric Values
Any SET element is stored internally as a 64bit number containing the combination of the bits that represent each SET element.
In our table: 'Hunt'=1, 'Pioneer'=2, 'Chevron'=4, 'BP'=8.
Also, mysql allows to use these numbers instead of text values. If we need to see the numeric value in the select, we need to use the SET column inside a numeric expression (E.g. adding zero).
Let's see the current values:
mysql> SELECT id, oilcompany+0, oilcompany FROM tmp_table;
+----+--------------+------------+
| id | oilcompany+0 | oilcompany |
+----+--------------+------------+
| 1 | 9 | Hunt,BP |
| 2 | 2 | Pioneer |
+----+--------------+------------+
2 rows in set (0.00 sec)
Here 9 = 'Hunt' (1) + 'BP' (8) and 2 = 'Pioneer' (2).
Now, let's change the Pioneer to 'Hunt' (1) + 'Chevron' (4):
mysql> UPDATE tmp_table
-> SET oilcompany = 5
-> WHERE id = 2;
Query OK, 1 row affected (0.08 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT id, oilcompany+0, oilcompany FROM tmp_table;
+----+--------------+--------------+
| id | oilcompany+0 | oilcompany |
+----+--------------+--------------+
| 1 | 9 | Hunt,BP |
| 2 | 5 | Hunt,Chevron |
+----+--------------+--------------+
2 rows in set (0.00 sec)

Use of UNION when creating tables

Database-1
create table sample (
id INT,
nm VARCHAR(10)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
UNION=(for tables from another databases);
So, when we do union what actually it meance?
Please explain, I am getting confusing for this type of UNION.
That looks close to the syntax for creating a merge table, but it has the engine type wrong. Your statement will ignore the union clause and simply create a new, empty table. In order to create merge table you need to specify ENGINE=MERGE.
14.3 The MERGE Storage Engine
The MERGE storage engine, also known as the MRG_MyISAM engine, is a
collection of identical MyISAM tables that can be used as one.
The tables you specify in the UNION clause there, must all be identical - ie, having the same index and column specification, and they must all be in the same order in each table.
After that, can you query your merge table and access the data from all of the tables that form it.
You can also insert into your merge table, which is something you cannot do with a view:
You can optionally specify an INSERT_METHOD option to control how
inserts into the MERGE table take place. Use a value of FIRST or LAST
to cause inserts to be made in the first or last underlying table,
respectively. If you specify no INSERT_METHOD option or if you specify
it with a value of NO, inserts into the MERGE table are not permitted
and attempts to do so result in an error.
Anyway, the doco has the rest of the information if you want to peruse more - I've never felt the need to use this type of table.
Example:
mysql>
mysql> create table t2 (
-> id integer primary key auto_increment,
-> val char(20)
-> ) engine=myisam;
Query OK, 0 rows affected (0.05 sec)
mysql>
mysql> insert into t1(val) values ('table1 a'), ('table1 b');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into t2(val) values ('table2 a'), ('table2 b');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql>
mysql>
mysql> create table mt (
-> id integer primary key auto_increment,
-> val char(20)
-> ) engine=merge union=(t1,t2) insert_method=last;
Query OK, 0 rows affected (0.04 sec)
mysql>
mysql> select * from mt;
+----+----------+
| id | val |
+----+----------+
| 1 | table1 a |
| 2 | table1 b |
| 1 | table2 a |
| 2 | table2 b |
+----+----------+
4 rows in set (0.00 sec)
mysql> insert into mt(val) values ('12345');
Query OK, 1 row affected (0.00 sec)
mysql> select * from mt;
+----+----------+
| id | val |
+----+----------+
| 1 | table1 a |
| 2 | table1 b |
| 1 | table2 a |
| 2 | table2 b |
| 3 | 12345 |
+----+----------+
5 rows in set (0.01 sec)
mysql> select * from t2;
+----+----------+
| id | val |
+----+----------+
| 1 | table2 a |
| 2 | table2 b |
| 3 | 12345 |
+----+----------+
3 rows in set (0.00 sec)

INT(3) column not cliping the value to appropriate length and allowing the full value to be inserted - MySQL

I have an INT(3) UNSIGNED column. If I insert a value with character length more that 3, it doesn't clip that value but inserts it.
Whats happening?
FROM What does "size" in int(size) of MySQL mean?
Finally, let's come to the place of the manual where there is the
biggest hint to what the number means:
Several of the data type descriptions use these conventions:
M indicates the maximum display width for integer types. For
floating-point and fixed-point types, M is the total number of digits
that can be stored. For string types, M is the maximum length. The
maximum allowable value of M depends on the data type.
It's about the display width. The weird thing is, though2, that, for
example, if you have a value of 5 digits in a field with a display
width of 4 digits, the display width will not cut a digits off.
If the value has less digits than the display width, nothing happens
either. So it seems like the display doesn't have any effect in real
life.
Now2 ZEROFILL comes into play. It is a neat feature that pads values
that are (here it comes) less than the specified display width with
zeros, so that you will always receive a value of the specified
length. This is for example useful for invoice ids.
So, concluding: The size is neither bits nor bytes. It's just the
display width, that is used when the field has ZEROFILL specified.
mysql> create table a ( a tinyint );
Query OK, 0 rows affected (0.29 sec)
mysql> show columns from a;
+-------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| a | tinyint(4) | YES | | NULL | |
+-------+------------+------+-----+---------+-------+
1 row in set (0.26 sec)
mysql> alter table a change a a tinyint(1);
Query OK, 0 rows affected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into a values (100);
Query OK, 1 row affected (0.00 sec)
mysql> select * from a;
+-----+
| a |
+-----+
| 100 |
+-----+
1 row in set (0.00 sec)
2 Some code to better explain what I described so clumsily.
mysql> create table b ( b int (4));
Query OK, 0 rows affected (0.25 sec)
mysql> insert into b values (10000);
Query OK, 1 row affected (0.00 sec)
mysql> select * from b;
+-------+
| b |
+-------+
| 10000 |
+-------+
1 row in set (0.00 sec)
mysql> alter table b change b b int(11);
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from b;
+-------+
| b |
+-------+
| 10000 |
+-------+
1 row in set (0.00 sec)
mysql> alter table b change b b int(11) zerofill;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from b;
+-------------+
| b |
+-------------+
| 00000010000 |
+-------------+
1 row in set (0.00 sec)
mysql> alter table b change b b int(4) zerofill;
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from b;
+-------+
| b |
+-------+
| 10000 |
+-------+
1 row in set (0.00 sec)
mysql> alter table b change b b int(6) zerofill;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from b;
+--------+
| b |
+--------+
| 010000 |
+--------+
1 row in set (0.00 sec)
actually 3 there is a display width which works for ZEROFILL that pads zero on the right. It doesn't limit the capacity of the integer as it stores upto 4294967295 starting from zero.
example,
CREATE TABLE tableName
(
x INT(3) ZEROFILL NOT NULL,
y INT NOT NULL
);
INSERT INTO tableName (x,y) VALUES
(1, 1),
(12, 12);
SELECT x, y FROM tableName;
Result:
x y
001 1
012 12
Using display width has no effect on how the data is stored. It affects only how it is displayed.
Integer Types (Exact Value)

mysql Like ambiguios result

I have two tables a and b.
Table a has a field named gr which can have multiple values concatained with string.
Table b holds it seperately in fields lg.
How do i run the below query to check whether b.lg is in a.gr?
now b.lg has values me,me01,me02 and a.gr has to be checked agianst me02.
But the error here is that the three as matched with this
SELECT lg
FROM a, b
WHERE a.id = 22 AND
a.gr LIKE CONCAT('%', b.lg, '%');
a.gr example values
'm301,you,weall'
'me,you,me2'
'me'
b.lg value
1.'m301'
2.'you'
3.'weall'
4.'me2'
5.'me'
6.'me1'
You can use the LOCATE or FIND_IN_SET functions. LOCATE will find partial matches; for example it will find a match for me in me1,me2. If this is not what you want, maybe you are looking for FIND_IN_SET.
SELECT lg
FROM a, b
WHERE a.id = 22 AND
LOCATE(b.lg, a.gr) > 0;
Replicating the data you have posted this is the output from the SELECT:
mysql> create temporary table a (gr varchar(100));
Query OK, 0 rows affected (0.36 sec)
mysql> create temporary table b (lg varchar(100));
Query OK, 0 rows affected (0.08 sec)
mysql> insert into a values ('m301,you,weall'),('me,you,me2'),('me');
Query OK, 3 rows affected (0.11 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> insert into b values ('m301'),('you'),('weall'),('me2'),('me'),('me1');
Query OK, 6 rows affected (0.06 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> SELECT lg, gr FROM a, b WHERE locate(lg,gr) > 0;
+-------+----------------+
| lg | gr |
+-------+----------------+
| m301 | m301,you,weall |
| you | m301,you,weall |
| you | me,you,me2 |
| weall | m301,you,weall |
| me2 | me,you,me2 |
| me | me,you,me2 |
| me | me |
+-------+----------------+
7 rows in set (0.02 sec)
I recommend using the FIND_IN_SET() function to join the two tables.
Try something like this:
select b.lg
from a
inner join b on find_in_set(b.lg,a.gr) > 0
where a.id = 22;

How to select from MySQL where a SET does not equal a value?

we have an issue because this is how the table was setup. How do we select from a table where a set does not contain a value? If we have a set with one,two and we do
SELECT *
FROM table
WHERE column NOT IN('one')
we will still get that row. What is the correct syntax for this?
Thanks
this is what worked:
SELECT *, FIND_IN_SET('hidden', props) As hidden
FROM gt_content
HAVING hidden IS NULL
Try:
SELECT *
FROM table
WHERE FIND_IN_SET('one',column) = 0
Some test I did:
mysql> CREATE TABLE setTest (s SET('a','b','c','d'));
Query OK, 0 rows affected (0.60 sec)
mysql> INSERT INTO setTest VALUES ('a'),('a,b'),('b'),('a,c'),('c,d');
Query OK, 5 rows affected (0.14 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM setTest;
+------+
| s |
+------+
| a |
| a,b |
| b |
| a,c |
| c,d |
+------+
5 rows in set (0.20 sec)
mysql> SELECT * FROM setTest WHERE FIND_IN_SET('a',s) = 0;
+------+
| s |
+------+
| b |
| c,d |
+------+
2 rows in set (0.12 sec)
mysql> SELECT * FROM setTest WHERE FIND_IN_SET('b',s) = 0;
+------+
| s |
+------+
| a |
| a,c |
| c,d |
+------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM setTest WHERE FIND_IN_SET('b',s) > 0;
+------+
| s |
+------+
| a,b |
| b |
+------+
2 rows in set (0.04 sec)
From the mysql manual at http://dev.mysql.com/doc/refman/5.0/en/set.html:
Normally, you search for SET values using the FIND_IN_SET() function or the LIKE operator:
SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
The first statement finds rows where set_col contains the value set member. The second is similar, but not the same: It finds rows where set_col contains value anywhere, even as a substring of another set member.