MySql Binary query - mysql

I have a table with a Binary PK:
CREATE TABLE `codes` (
`Code` binary(45) NOT NULL,
PRIMARY KEY (`Code`),
UNIQUE KEY `Code_UNIQUE` (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When I insert I use BINARY('value').
I attempted to retrieve a row by Code using the following:
SELECT * from codes WHERE `Code` = BINARY('value')
This doesn't work because the length of the Code field is 45, so MySql pads the data with empty bytes.
This can be visualised running the following:
SELECT HEX(Code), HEX(BINARY('value')) FROM codes
I can get it to work with this (ugly) query:
SELECT * FROM codes WHERE TRIM('0' from HEX(Code)) = HEX(BINARY('value'))
So I was just wondering if anyone can provide a nice and performant way to achieve this. This is straightforward if you know the size of your data, but the Code field can be any length.

Instead of Binary datatype, you should use Varbinary. This will not pad the data with trailing 0s, in case the length of data is smaller than the maximum size defined.
When BINARY values are stored, they are right-padded with the pad
value to the specified length. The pad value is 0x00 (the zero byte).
Values are right-padded with 0x00 on insert, and no trailing bytes are
removed on select.
For VARBINARY, there is no padding on insert and no bytes are stripped
on select.
Also, you do not need to define Unique constraint on an already defined Primary Key. Primary Key basically satisfied the Unique constraint, with additional condition of NOT NULL values. So, defining Unique constraint further does not add anything upon it.
This is how the CREATE TABLE statement can be:
CREATE TABLE `codes` (
`Code` Varbinary(45) NOT NULL, -- Changed to Varbinary
PRIMARY KEY (`Code`) -- Removed Unique constraint
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into codes (Code) VALUES (BINARY('value'));
Query #1
SELECT HEX(Code), HEX(BINARY('value')) FROM codes ;
| HEX(Code) | HEX(BINARY('value')) |
| ---------- | -------------------- |
| 76616C7565 | 76616C7565 |
Query #2
SELECT * from codes WHERE `Code` = BINARY('value');
| Code |
| --------------- |
| [object Object] |
View on DB Fiddle

Related

Bi-directional unique key constraint for combination of two columns

I have the below table columns in MySQL.
id
user_primary_email
user_secondary_email
I want to make the combination of columns user_primary_email and user_secondary_email unique which I can achieve by using UNIQUE KEY unique_key_name (user_primary_email, user_secondary_email)
The above addition of unique key constraint will help me achieve the below scenario or rather just by adding a unique key to the individual column itself.
user_primary_email = 'xyz#gmail.com' AND user_secondary_email = 'pqr#gmail.com'
user_primary_email = 'xyz#gmail.com' AND user_secondary_email = 'pqr#gmail.com' //This will not be allowed to enter due to unique key constraint
Now the problem which I am facing is the same combination should not be allowed to add in a reverse way as mentioned below.
user_primary_email = 'pqr#gmail.com' AND user_secondary_email = 'xyz#gmail.com' //This should not be allowed to add since already same email id combination added once
id | user_primary_email | user_secondary_email
-------------------------------------------------------
1 | xyz#gmail.com | pqr#gmail.com
-------------------------------------------------------
2 | pqr#gmail.com | xyz#gmail.com
-------------------------------------------------------
In the above case during insert of row id 2 it should throw error as both the email id combination is already used in row id 1.
Any help would be great.
In any MariaDB:
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`user_primary_email` varchar(64) DEFAULT NULL,
`user_secondary_email` varchar(64) DEFAULT NULL,
`mycheck` varchar(128) AS (IF(user_primary_email<user_secondary_email,CONCAT(user_primary_email,user_secondary_email),CONCAT(user_secondary_email,user_primary_email))) PERSISTENT,
PRIMARY KEY (`id`),
UNIQUE KEY `mycheck` (`mycheck`)
);
MariaDB [test]> insert into t values (1,'a','b',null);
Query OK, 1 row affected (0.03 sec)
MariaDB [test]> insert into t values (2,'b','a',null);
ERROR 1062 (23000): Duplicate entry 'ab' for key 'mycheck'
There is no direct support for that, but you can use a workaround to create your bidirectional key: You need a unique key on an ordered version of your two columns.
Fortunately, you can very easily do that. MySQL 5.7.6+ supports generated columns and unique indexes for them, which you can use to order your two values and to enforce uniqueness.
create table testBiDirKey (
a varchar(100),
b varchar(100),
a_ordered varchar(100) as (least(a, b)) STORED,
b_ordered varchar(100) as (greatest(a, b)) STORED,
unique key unqBi_test_ab (a_ordered, b_ordered)
);
insert into testBiDirKey(a,b) values('a', 'b');
insert into testBiDirKey(a,b) values('b', 'a');
Error Code: 1062. Duplicate entry 'a-b' for key 'unqBi_test_ab'
This will treat null exactly as your current normal unique key, so
insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values(null, 'a');
are all allowed. You can add coalesce(x,'') to only allow one empty value (either null OR '') if you want. If you verify your values before you add them (e.g. if they don't contain a ,), you can combine the two columns to just one, concatenated with an , - although with little benefit apart from just having 1 additional column.
For 5.7.8+, you don't need the STORED keyword anymore to be able to use these columns in an index. That keyword effects if the values are stored (using disk space) or calculated when required (default).
Before MySQL 5.7.6, you can use a trigger (on update and insert) to update the two columns with the these values, the same logic applies, it's just a little more code.

Mysql ignore contition 'where' on varchar primary key

I have table
DROP TABLE IF EXISTS `slug`;
CREATE TABLE `slug` (
`slug` varchar(255) NOT NULL,
`id` int(10) unsigned NOT NULL,
`table` varchar(64) NOT NULL,
PRIMARY KEY (`slug`),
UNIQUE KEY `id_table` (`id`,`table`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `slug` (`slug`, `id`, `table`) VALUES
('aaa', 3, 'team');
I have select
SELECT `slug`, `id`, `table`
FROM `slug`
WHERE (`slug` = 0)
and result is
+------+----+-------+
| slug | id | table |
+------+----+-------+
| aaa | 3 | team |
+------+----+-------+
Condition is slug = 0, but I get row where slug is 'aaa'.
Any idea?
Mysql version 5.5.38-0ubuntu0.12.04.1
As a note, it is a bad idea to use reserved words, such as table as column names. This however is irrelevant to your question.
The important part of the query is:
WHERE slug = 0
How does MySQL handle this? What can it do? After all, you've declared slug to be a varchar() but it is being compared to an integer. Well, what MySQL does is silent conversion to the numeric type. So, it converts the value in slug to an integer.
Which integer? If slug were '123', then it would be easy. The value would be 123. Instead, the value is aaa. MySQL's conversion rules are to convert the leading "digits" of the string to a number, until are no more "digits". When there are no digits at all, the value is 0. I've put digits in quotes because it includes '-', '.', and 'e' (for exponential notation).
So, your where clause is comparing any string that doesn't start with a numeric 0 to 0. The following values should all pass: 'aaa', 'zzz', '0abc', and so on.
This is expected behavior.
In MySQL, a zero number can be equal to any string.
So when you want to compare a string with a value of an integer column, you have to cast your integer value into a string.

ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'

I have a table:
CREATE TABLE passenger_details
(
bank_card INT(20) NOT NULL AUTO_INCREMENT,
email VARCHAR(20),
mobile INT(15) NOT NULL,
p_id INT NOT NULL,
PRIMARY KEY (bank_card),
FOREIGN KEY (p_id) REFERENCES passenger(p_id)
);
INSERT INTO passenger_details
VALUES (0123012301230123,'blah_#hotmail.com',0872863492,1234);
select*from passenger_details;
+------------+--------------------+-----------+------+
| bank_card | email | mobile | p_id |
+------------+--------------------+-----------+------+
| 2147483647 | blah_#hotmail.com | 872863492 | 1234 |
+------------+--------------------+-----------+------+
1 row in set (0.00 sec)
As we can see, the previous value, just went wrong into table. Should be 16 numbers and not only 10, actually different numbers.
When i try to insert a new value:
INSERT INTO passenger_details
VALUES (1234258431681842,'blah#icloud.com',0895764829,123548);
I get this error:
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'
If bank_card is AUTO_INCREMENT why there is error? Should I change the PK to another place?
INT has a maximum signed value of 2147483647. Any number greater than that will be truncated to that value. What you need to do is change that column to be a varchar(20) which will hold strings of up to 20 characters since bank card numbers are strings and not actually numbers (you don't do math with the). You also should remove AUTO_INCREMENT as that is not a value you will be incrementing.
Something to ask yourself. How did the number get that big? I did not insert 2 billion rows!
Well, possibly you 'burned' that many AUTO_INCREMENT ids. This can happen in man ways:
INSERT IGNORE ... -- when the insert is ignored (because it the row already exists)
REPLACE
IODKU
and probably others.
With MySQL phpmyadmin panel , this is how I got rid from this issue
>Go to your Table's structure from phpmyadmin panel
>> select that PRIMARY column , click on change
>>> Change Column type to "BIGINT" and Attributes to "unsigned"
with other SQLs > change column attributes to "BIGINT unsigned"
that worked for me

where is the duplicate in ON DUPLICATE KEY query?

Description:
I am trying to insert user's preferences into a database. If the user hasn't yet placed any, I want a insert, otherwise, I want an update. I know I can insert default values in the creation of the user and than exclusively use update, but that adds another query (I think)
Problem:
I have read up on ON DUPLICATE KEY UPDATE but I don't understand it. This is almost the exact question I have but without the answer. The answer says:
It does sound like it will work for what you want to do as long as you hav the proper column(s) defined as UNIQUE KEY or PRIMARY KEY.
If I do a simple insert like so:
INSERT INTO table (color, size) VALUES ('blue', '18') ...
How will that ever produce at DUPLICATE KEY? As far as mysql knows it's just another insert and the id is auto-incremented. I have the primary key in the table set to unique, but the insert isn't going to check against that, right?
Table:
CREATE TABLE `firm_pref` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`firm_id` int(9) NOT NULL, //user_id in this case
`header_title` varchar(99) NOT NULL,
`statement` varchar(99) NOT NULL,
`footer_content` varchar(99) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
Well, unless you want your application to be used by a single person only, you would have to specify someone's user_id in that INSERT - when this 'someone' guy or girl updates his/her preferences, right?
This field (user_id) is exactly what would be checked by ON DUPLICATE KEY UPDATE clause.
And if you want to insert a new record, just send NULL instead:
INSERT INTO table (user_id, color, size) VALUES (NULL, 'blue', 18);
... so auto-increment will have a chance to move on and save the day. )
UPDATE: Take note that to understand that some field should be considered a unique identifier, you should mark it as such. Usually it's done naturally, as this field is used as a PRIMARY KEY. But sometimes it's not enough; it means some work for UNIQUE constraint. For example, in your table it can be used like this:
CREATE TABLE `prefs` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`firm_id` int(9) NOT NULL,
...
PRIMARY KEY (`id`),
UNIQUE KEY (`firm_id`)
);
(or you can add this constraint to the existing table with ALTER TABLE prefs ADD UNIQUE (firm_id) command)
Then insert/update query will look like...
INSERT INTO prefs(firm_id, header_title, statement, footer_content)
VALUES(17, 'blue', '18', 'some_footer')
ON DUPLICATE KEY UPDATE
header_title = 'blue',
statement = '18',
footer_content = 'some_footer';
I've built a sort of demo in SQL Fiddle. You can play with it some more to better understand that concept. )
For options, you would normally have an options table that has a list of available options (like color, size etc), and then a table that spans both your options table and users table with the users' values.
For example, your options table:
id | name
=========
1 | color
2 | size
Your users table:
id | name
================
1 | Martin Bean
And an options_users join table:
option_id | user_id | value
===========================
1 | 1 | Blue
2 | 1 | Large
With the correct foreign keys set up in your options_users table, you can have redundant values removed when an option or user is removed from your system. Also, when saving a user's preferences, you can first delete their previous answers and insert the new ones.
DELETE FROM `options_users`
WHERE `user_id` = #user_id;
INSERT INTO `options_users` (`option_id`, `user_id`, `value`)
VALUES (1, #user_id, 'Blue'), (2, #user_id, 'Large');
Hope that helps.

Remove duplicates records in a MySQL table with key but not primary key

I need to remove duplicate records (just to keep one copy) from a MySQL table in MyISAM format. I have read many questions in Stackoverflow about similar issues but always the people use an ID field as unique id or similar and I haven't this field because my "Key" could be duplicated. I want to remove rows with the 'Fecha' and 'Equip' duplicated.
CREATE TABLE `pfc` (
`Fecha` datetime NOT NULL,
`Equip` int(10) unsigned NOT NULL,
`Value` double NOT NULL,
KEY `Fecha` (`Fecha`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=21 ROW_FORMAT=FIXED;
An example table data:
Fecha | Equip | Value
06/02/2011 0:00:11 | 22 | 29.0
06/02/2011 0:22:11 | 22 | 45.3
06/02/2011 0:00:11 | 22 | 29.0
The result should be:
Fecha | Equip | Value
06/02/2011 0:00:11 | 22 | 29.0
06/02/2011 0:22:11 | 22 | 45.3
This structure is not possible to change. I cannot use PRIMARY KEY or UNIQUE INDEX solutions. To create a temporal table without duplicates and then rename would be a poor solutions also, because the KEY and another parameters will be lost.
Thanks
ALTER IGNORE TABLE `pfc` ADD UNIQUE(`Fetcha`, `Equip`);
That will keep the first record it finds and remove duplicates from your table.
From MySQL manual:
IGNORE is a MySQL extension to standard SQL. It controls how ALTER
TABLE works if there are duplicates on unique keys in the new table or
if warnings occur when strict mode is enabled. If IGNORE is not
specified, the copy is aborted and rolled back if duplicate-key errors
occur. If IGNORE is specified, only the first row is used of rows with
duplicates on a unique key. The other conflicting rows are deleted.
Incorrect values are truncated to the closest matching acceptable
value.
Edit:
To create an exact copy of your table, use the following:
CREATE TABLE table_copy SELECT * FROM pfc;
That will copy the table structure and the data. After that, run the ALTER command to add the UNIQUE constraint and filter out the records that are duplicated.
Just as a test, try this to see if it is what you want
CREATE TABLE new_pfc AS
SELECT * FROM pfc GROUP BY fecha, equip
DELETE n1 FROM pfc n1, pfc n2 WHERE n1.Fecha = n2.Fecha AND n1.Equip=n2.Equip AND n1.Value=n2.Value