find_in_set return different value - mysql

I have a table with this declaration:
CREATE TABLE foobar (
id int(11) NOT NULL AUTO_INCREMENT,
dow set('q','w','e','r','t','y', 'u') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT;
With those values inside:
id, dow
'1', '1,3,6'
'1', '2,4,7'
Those query returns different values.
SELECT dow, FIND_IN_SET('4', dow) FROM (SELECT * from pippo.pluto) as B;
SELECT dow, FIND_IN_SET('4', dow) FROM pippo.pluto as B;
The first query returns those results:
'1,3,6', '0'
'2,4,7', '2'
The second query returns those results:
'1,3,6', '0'
'2,4,7', '4'
Why?
Tested against 5.6 and 5.7 mysql version.
Edit:
This behaviour remains the same if I use the mysql views.
CREATE VIEW selectInner AS SELECT dow, FIND_IN_SET('r', dow) FROM (SELECT * from pippo.foobar) as B;
CREATE VIEW selectDirect AS SELECT dow, FIND_IN_SET('r', dow) FROM pippo.foobar as B;

There are two things interacting here:
"If the first argument is a constant string and the second is a column of type SET, the FIND_IN_SET() function is optimized to use bit arithmetic." per FIND_IN_SET docs
One of the two queries operates directly on the table, and the second on a derived table.
The behaviour demonstrates this:
When operating directly on the table (where dow refers to the defined column in that table's metadata), FIND_IN_SET returns the index of the entry in the column's definition
When operating on a derived table (where dow refers to a derived column), FIND_IN_SET returns the index of the entry in the derived value
This is clear if you search for e.g. y and u in a column containing q,e,y,u: you'd get 6 and 7 when querying the table directly, where dow is a SET containing q,w,e,r,t,y,u and FIND_IN_SET uses bitwise optimizations; but 3 and 4 when searching the derived table, where dow is the string containing q,e,y,u for that row.

Related

MYSQL: How to update unique random number to existing rows

It's been my first question to this website, I'm sorry if I used any wrong keywords. I have been with one problem from quite a few days.
The Problem is, I have a MYSQL table named property where I wanted to add a ref number which will be a unique 6 digit non incremental number so I alter the table to add a new column named property_ref which has default value as 1.
ALTER TABLE property ADD uniqueIdentifier INT DEFAULT (1) ;
Then I write a script to first generate a number then checking it to db if exist or not and If not exist then update the row with the random number
Here is the snippet I tried,
with cte as (
select subIdentifier, id from (
SELECT id, LPAD(FLOOR(RAND() * (999999 - 100000) + 100000), 6, 0) AS subIdentifier
FROM property as p1
WHERE "subIdentifier" NOT IN (SELECT uniqueIdentifier FROM property as p2)
) as innerTable group by subIdentifier
)
UPDATE property SET uniqueIdentifier = (
select subIdentifier from cte as c where c.id = property.id
) where property.id != ''
this query returns a set of record for almost all the rows but I have a table of entries of total 20000,
but this query fills up for ~19000 and rest of the rows are null.
here is a current output
[current result picture]
If anyone can help, I am extremely thanks for that.
Thanks
Instead of trying to randomly generate unique numbers that do not exist in the table, I would try the approach of randomly generating numbers using the ID column as a seed; as long as the ID number is unique, the new number will be unique as well. This is not technically fully "random" but it may be sufficient for your needs.
https://www.db-fiddle.com/f/iqMPDK8AmdvAoTbon1Yn6J/1
update Property set
UniqueIdentifier = round(rand(id)*1000000)
where UniqueIdentifier is null
SELECT id, round(rand(id)*1000000) as UniqueIdentifier FROM test;

MySQL - get date column from a table

I have a MySQL db with a MappingTable which consists of two columns. First column is a date column and another is ID - Autoincrement int column. I created this table for mapping dates and the ID's. When I query the date column with dates to retrieve the ID, no rows are getting selected. Any reason?
I tried
date_format in the SELECT query
str_to_date while checking in the WHERE clause
Compared like current_date > "2016-07-12" AND current_date <= "2016-07-12"
IfI compare LIKE "2016-07-1%" I'm getting matching rows but if I select "2016-07-12%" though there are matching rows, it is giving 0 rows.
I defined my column as DATE only.
Anything I'm missing here?
CREATE TABLE `mapping_table` (
`Current_date` date DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
My question is, I want to select something like this.
select id from mapping_table where current_date="2016-07-12";
I tried with all approaches as mentioned above, but no rows are not retrieving.
use back tick on columns and table names so it wont be read/parse as keyword.
select `id` from `mapping_table` where `current_date` = "2016-07-12";
In the sample you provided you should use a date_format
select id from mapping_table where current_date= DATE_FORMAT("2016-07-12",'%Y-%d-%m') ;
or use a range
select id from mapping_table where current_date
BETWEEN DATE_FORMAT("2016-07-12",'%Y-%d-%m')
and DATE_FORMAT("2016-07-10",'%Y-%d-%m')

MySQL Order By doesn't work on Concat(enum)

Currently we have an interessting problem regarding the sort order of MySQL in an enum-field. The fields enum entries have been sorted in the order we want it. Just to be save, we added a CONCAT around it, so it would be cast to char and ordered in alphabetical order, just as suggested by the MySQL-reference (MySQL Reference - Enum)
Make sure that the column is sorted lexically rather than by index number by coding ORDER BY CAST(col AS CHAR) or ORDER BY CONCAT(col).
But that didn't produce the expected results, so we started to investigate further. It seems that the order by statement doesn't work on a combination of enum and the concat function. I've wrote the following sample script, which should show my point:
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO test
VALUES ('b'), ('c'), ('a');
SELECT * FROM test; -- b, c, a
SELECT * FROM test ORDER BY col1 ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS CHAR) ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS BINARY) ASC; -- a, b, c
SELECT * FROM test ORDER BY CONCAT(col1) ASC; -- b, c, a - This goes wrong
I am currently suspecting some kind of problem with the collation/encoding, but I'm not sure. My databases default encoding is also utf8. The MySQL version is 5.6.12 but it seems to be reproduceable with MySQL 5.1. The storage engine is MyIsam but it also occurs with the memory engine.
Any help would be appreciated.
Update:
As it seems the problem is produced only in MySQL 5.6 and by the collation of the column. With the first CREATE TABLE statement, the queries work fine.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_general_ci DEFAULT NULL
)
With the second they don't.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
)
The collation of the table and/or database don't seem to affect the queries. The queries can be tested in this SQL Fiddle
Strange,it works in this fiddle.Do you have a trigger or something?
http://sqlfiddle.com/#!2/0976a/2
BUT,in 5.6 goes haywire:
http://sqlfiddle.com/#!9/0976a/1
Mysql bug,probably.
More,if you input the values in the enum in the "proper" order it works:
http://sqlfiddle.com/#!9/a3784/1
IN the doc:
ENUM values are sorted based on their index numbers, which depend on
the order in which the enumeration members were listed in the column
specification. For example, 'b' sorts before 'a' for ENUM('b', 'a').
As per the document:
Under the Handling of Enumeration Literals section, it states that:
If you store a number into an ENUM column, the number is treated as
the index into the possible values, and the value stored is the
enumeration member with that index. (However, this does not work with
LOAD DATA, which treats all input as strings.) If the numeric value is
quoted, it is still interpreted as an index if there is no matching
string in the list of enumeration values. For these reasons, it is not
advisable to define an ENUM column with enumeration values that look
like numbers, because this can easily become confusing.
For example, the following column has enumeration members with string values of '0', '1', and '2', but numeric index values of 1, 2, and 3:
numbers ENUM('0','1','2')
If you store 2, it is interpreted as an
index value, and becomes '1' (the value with index 2). If you store
'2', it matches an enumeration value, so it is stored as '2'. If you
store '3', it does not match any enumeration value, so it is treated
as an index and becomes '2' (the value with index 3).
mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1 |
| 2 |
| 2 |
+---------+
In your case:
INSERT INTO test
VALUES ('2'), ('3'), ('1');
Index value of '2' is 2, '3' is 3 and '1' is 1.
So the output is 2,3,1

How to select some default value if there is no such column in a table?

For example, I have a table that doesn't have a column "type". But I need to have my sql query having that column. When I run the query I get an error:
SELECT t.foo, t.boo, t.type FROM tabl AS t;
Unknown column 't.type' in 'field list'
I need something like ternary operator. I tried these solutions but they both do not work:
SELECT f.foo, f.boo, IF(f.type IS NULL, 'x', f.type) AS type FROM tabl AS f
SELECT f.foo, f.boo, (CASE WHEN f.type IS NULL THEN "x" ELSE f.type) AS type FROM tabl AS f
Is there a possibility to implement such a query?
Use something like this. Assume you want to join 2 tables rows and one is missing the column:
SELECT t.foo, t.boo, t.type FROM tabl1 as t1
UNION
SELECT t.foo, t.boo, NULL as type FROM tabl2 AS t2;
You can replace NULL with a string "" or whatever you application desires.
Unfortunately, that is not the way columns work. If you need to introspect your table to determine if it have this column, then you might try using data in the information_schema to get at this. Overall sounds like a weird approach to me. Why not just create all the tables with this column?
I think you mean that you have a table with entries ... Some of your entries has got no "type" column filled in. To have default value, you need to change your table. You can change it using either phpmyadmin (set default value) or through SQL code.
This would be something on these lines:
CREATE TABLE Persons
(
P_Id int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255) DEFAULT 'London'
)
This sets each entry's city to be London by default

Is there an easy SELECT-Statement that creates an empty set?

Is there an easy and simple way to create a result table that has specified columns but zero rows? In set theory this is called an empty set, but since relational databases use multidimensional sets the term doesn't fit perfectly. I have tried these two queries, but both deliver exactly one row and not zero rows:
SELECT '' AS ID;
SELECT null AS ID;
But what I want is the same result as this query:
SELECT ID FROM sometable WHERE false;
I'm searching for a more elegant way because I don't want to have a table involved, so the query is independent from any database scheme. Also a generic query might be a bit faster (not that it would matter for such a query).
SELECT "ID" LIMIT 0;
Without any real tables.
Do note that most (My)SQL clients simply will display "Empty set". However, it actually does what you want:
create table test.test_table
select "ID" limit 0;
show create table test.test_table\G
Table: test_table
Create Table: CREATE TABLE `test_table` (
`ID` varchar(2) character set latin1 NOT NULL default ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
SELECT * FROM (SELECT NULL AS ID) AS x WHERE 1 = 0
You can use the DUAL pseudo-table.
SELECT whatever FROM DUAL WHERE 1 = 0
Check the documentation (look for the DUAL section).