Why 3 rows deleted sql query puzzle? - mysql

can anybody tell me the technical reason for this?
CREATE TABLE test (
id varchar(3) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO test VALUES ('0'), ('1'), ('2'), ('ab'), ('bb');
select * from test;
DELETE FROM test WHERE id=0;
Which Deletes 3 rows from table test.

Because this:
SELECT 0 = 'ab';
+----------+
| 0 = 'ab' |
+----------+
| 1 |
+----------+
To delete exact rows use BINARY operator, it will force byte by byte comparison -
DELETE FROM test WHERE id = BINARY 0;

When you compare numbers to strings, they are compared as float numbers. Any string that does NOT start with a digit is implicitly converted to number 0.

There is Difference Between a Character '0' and an integer 0.. When u Compare a Char with integer the Char string if not an integer returns a false value (i,e) A 0 hence making the condition true and delete the First, 4th and 5th row from ur Table... To Delete the particular row you need to check condition like this...
Delete from test where id = '0'; (A Char 0 not An Integer 0)

Try instead comparing values of the same type e.g.
DELETE FROM test WHERE id = CAST(0 AS VARCHAR(3));

Okay got first i confused when i see this but now i got it
when you're running
select * from test;
DELETE FROM test WHERE id=0;
This query Compares every row as a Integer not string,
So when MySQL comes to ab & bb so MySQL Take it as a 0 and delete it
if you start it with any digit like 1ab so MySQL Take 1ab as 1 and when you fire query for deleting 1 instead of 0 it will delete 1ab
Try
select * from test;
DELETE FROM test WHERE id='0';
This Code compare rows as a string so when he get exact '0' MySQL delete it else nothing.

Related

mysql query message save into table or external file

I have multiple store procedures to do the ETL work in mysql. Normally, it is running on the server for over night.
inside the store procedures there are multiple update statement like
update table1 set column1=3 when column2 = 4
if there any way, I can keep the mysql workbench result like
Rows matched: 100 Changed: 50 Warnings: 0
for each statement I run either into mysql table or external file?
prefer mysql native method. if not, any python I could possible use?
"Rows changed" can be retrieved with ROW_COUNT() function.
"Rows matched" needs in a trick with user-defined variable usage.
CREATE TABLE test (id INT, val INT);
INSERT INTO test VALUES
(1,1), (1,2), (1,3), (2,4);
Now we want to perform UPDATE test SET val = 3 WHERE id = 1; and count the amounts.
UPDATE test
-- add user-defined variable for matched rows counting
CROSS JOIN ( SELECT #matched := 0 ) init_variable
-- increment matched rows counter (this expression is always TRUE)
SET val = CASE WHEN #matched := #matched + 1
-- update the column
THEN 3
END
WHERE id = 1;
SELECT #matched matched, ROW_COUNT() changed;
matched | changed
------: | ------:
3 | 2
db<>fiddle here
If more than one column should be updated in a query then only one expression must be accompanied with the counter increment.

MySQL ROW_COUNT after REPLACE

I'm getting some odd values for ROW_COUNT after a REPLACE. In the example below, the second REPLACE returns 2 not 1. Can anyone explain why? This happens on both MySQL 5.6 and 5.7
create table test(
id int not null primary key,
d int not null unique
);
replace into test(id,d) values(1,1);
select row_count(); -- returns 1
replace into test(id,d) values(1,1);
select row_count(); -- returns 2... why?
Actually the behavior is very well documented:
For REPLACE statements, the affected-rows value is 2 if the new row
replaced an old row, because in this case, one row was inserted after
the duplicate was deleted.

Make unique string of characters/numbers in SQL

I have a table someTable with a column bin of type VARCHAR(4). Whenever I insert to this table, bin should be a unique combination of characters and numbers. Unique in this sense meaning has not appeared before in the table in another row.
bin is in the form of AA00, where A is a character A-F and 0 is a number 0-9.
Say I insert to this table once: it should come up with a bin value which doesn't appear before. Assuming the table was empty, the first bin could be AA11. On second insertion, it should be AA12, and then AA13, etc.
AA00, AA01, ... AA09, AA10, AA11, ... AA99, AB00, AB01, ... AF99, BA00, BA01, ... FF99
It doesn't matter this table can contain only 3,600 possible rows. How do I create this code, specifically finding a bin that doesn't already exist in someTable? It can be in order as I've described or a random bin, as long as it doesn't appear twice.
CREATE TABLE someTable (
bin VARCHAR(4),
someText VARCHAR(32),
PRIMARY KEY(bin)
);
INSERT INTO someTable
VALUES('?', 'a');
INSERT INTO someTable
VALUES('?', 'b');
INSERT INTO someTable
VALUES('?', 'c');
INSERT INTO someTable
VALUES('?', 'd');
Alternatively, I can use the below procedure to insert instead:
CREATE PROCEDURE insert_someTable(tsomeText VARCHAR(32))
BEGIN
DECLARE var (VARCHAR(4) DEFAULT (
-- some code to find unique bin
);
INSERT INTO someTable
VALUES(var, tsomeText);
END
A possible outcome is:
+------+----------+
| bin | someText |
+------+----------+
| AB31 | a |
| FC10 | b |
| BB22 | c |
| AF92 | d |
+------+----------+
As Gordon said, you will have to use a trigger because it is too complex to do as a simple formula in a default. Should be fairly simple, you just get the last value (order by descending, limit 1) and increment it. Writing the incrementor will be somewhat complicated because of the alpha characters. It would be much easier in an application language, but then you run into issues of table locking and the possibility of two users creating the same value.
A better method would be to use a normal auto-increment primary key and translate it to your binary value. Consider your bin value as two base 6 characters followed by two base 10 values. You then take the id generated by MySQL which is guaranteed to be unique and convert to your special number system. Calculate the bin and store it in the bin column.
To calculate the bin:
Step one would be to get the lower 100 value of the decimal number (mod 100) - that gives you the last two digits. Convert to varchar with a leading zero.
Subtract that from the id, and divide by 100 to get the value for the first two digits.
Get the mod 6 value to determine the 3rd (from the right) digit. Convert to A-F by index.
Subtract this from what's left of the ID, and divide by 6 to get the 4th (from the right) digit. Convert to A-F by index.
Concat the three results together to form the value for the bin.
You may need to edit the following to match your table name and column names, but it should so what you are asking. One possible improvement would be to have it cancel any inserts past the 3600 limit. If you insert the 3600th record, it will duplicate previous bin values. Also, it won't insert AA00 (id=1 = 'AA01'), so it's not perfect. Lastly, you could put a unique index on bin, and that would prevent duplicates.
DELIMITER $$
CREATE TRIGGER `fix_bin`
BEFORE INSERT ON `so_temp`
FOR EACH ROW
BEGIN
DECLARE next_id INT;
SET next_id = (SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='so_temp');
SET #id = next_id;
SET #Part1 = MOD(#id,100);
SET #Temp1 = FLOOR((#id - #Part1) / 100);
SET #Part2 = MOD(#Temp1,6);
SET #Temp2 = FLOOR((#Temp1 - #Part2) / 6);
SET #Part3 = MOD(#Temp2,6);
SET #DIGIT12 = RIGHT(CONCAT("00",#Part1),2);
SET #DIGIT3 = SUBSTR("ABCDEF",#Part2 + 1,1);
SET #DIGIT4 = SUBSTR("ABCDEF",#Part3 + 1,1);
SET NEW.`bin` = CONCAT(#DIGIT4,#DIGIT3,#DIGIT12);
END;
$$
DELIMITER ;

SQL Server 2008 Help - Find constant + Primary key

Using a SQL Server 2008 database, I am trying to find rows in column B that don't match a constant piece of data + primary key. Where primary Key is column A
Here's an example where I am looking for a SQL statement that will retrieve row 3 from this table:
Row xxxColumn AColumn B
Row 1 123 od123
Row 2 124 od124
Row 3 125 od789
Row 4 126 od126
Alias the table and compare? Create a view? Is there a way to use concatenate?
Thanks in advance
Replace my variables with whatever column names you are using...
declare #columna varchar(20)
set #columna = '125'
declare #columnb varchar(20)
set #columnb = 'od789'
select len(#columnb) - len(replace(#columnb,#columna,''))
If the result of select len(#columnb) - len(replace(#columnb,#columna,'')) = 0 you can take the result (meaning it does not exist in the string). If however the result > 0 you do not want to pick that up, for example, using your data:
declare #columna varchar(20)
set #columna = '123'
declare #columnb varchar(20)
set #columnb = 'od123'
select len(#columnb) - len(replace(#columnb,#columna,''))
Would return 3.
A more general solution could be:
SELECT <enter your columns that you want to return here>
FROM
YourTable
WHERE
len(columnb) - len(replace(columnb,columna,''))=0
The idea here is if there is no replacement to be done you end up with the length of the original string (column b) subtracted from the original string (again column b, since nothing has changed), this is the data you want returned (WHERE... = 0).
On the other hand if a replacement is made within the string you end up getting a positive length (even if the strings are exact, try it with od123 and od123), this in turn should be discarded from your result set. This is why I filtered in the where condition using = 0.

mysql insert with value equal to primary key + 1

I have an auto increment column ID, and for some situation I wanted the other column to be equal to the primary key + 1 value
ID | other
1 | 2
2 | 3
3 | 4
4 | 123 (some situation, it is not always plus 1)
How can I achieve this?
Here's what I have tried
INSERT INTO table (`ID`,`other`) VALUES ('',(SELECT MAX(ID)+1 FROM table))
But that returns an error
You can't specify target table 'table' for update in FROM clause
Try Below query:
ALTER TABLE dbo.table ADD
Column AS ([ID]+1)
GO
It will definitely work
Using a normal AUTO_INCREMENT column as id, I cannot think of a way to do this in MySQL. Triggers, which otherwise would have been an option, don't work well with AUTO_INCREMENT columns.
The only way I see is to do two commands for an INSERT;
INSERT INTO bop (value) VALUES ('These values should be 1 and 2');
UPDATE bop SET other = id+1 WHERE id = LAST_INSERT_ID();
An SQLfiddle to test with.
The closest I'm getting to what you're looking for is to generate sequences separately from AUTO_INCREMENT using a function, and use that instead to generate the table id;
DELIMITER //
CREATE TABLE bop (
id INT UNIQUE,
other INT,
value VARCHAR(64)
)//
CREATE TABLE bop_seq ( seq INT ) // -- Sequence table
INSERT INTO bop_seq VALUES (1) // -- Start value
CREATE FUNCTION bop_nextval() RETURNS int
BEGIN
SET #tmp = (SELECT seq FROM bop_seq FOR UPDATE);
UPDATE bop_seq SET seq = seq + 1;
RETURN #tmp;
END//
CREATE TRIGGER bop_auto BEFORE INSERT ON bop
FOR EACH ROW
SET NEW.id = bop_nextval(), NEW.other=NEW.id + 1;
//
That'd let you do inserts and have it autonumber like you want. The FOR UPDATE should keep the sequence transaction safe, but I've not load tested so you may want to do that.
Another SQLfiddle.
I solved this by updating 2 times the DB..
I wanted to do +1 from 19 till ..
UPDATE `table` SET `id`=`id`+101 WHERE id <= 19
UPDATE `table` SET `id`=`id`-100 WHERE id <= 119 AND id >= 101