Increase Alphanumeric VARCHAR Entry by Value 1? - mysql

On an old project because of not thought through design I have a column which actually should be set to auto_increment, though it cannot be because it are alphanumeric entries as follows:
c01
c02
c03
(c99 would continue to c100 and more), the letter happened in the past and it would require to overhaul the system to take it out, thus I rather prefer this workaround.
Now I need a way to imitate the auto_increment functionality with the SQL statement myself, my own attempt has gotten as far as the following:
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id, creation_date, last_edited) VALUES (SELECT(MAX(tag_id)+1),
'Love', 'All about love', 7, now(), 0);
This one does not work as is, though the idea was to select the highest entry in the column "tag_id" and then simply increase it by the value 1.
Any ideas how to accomplish this?
By the way I am also not sure if you simply can increase an alphanumeric entry through this way, though I know it can be done, I just don't know how.

If you want to safely get the largest integer value of a tag id of the form c##.., you could use the following expression:
max( convert( substring(tag_id, 2) , unsigned integer) )
^^^ largest ^^^^^^^^^ after 'c' ^^^^^^^^^^^^^^^^ convert to positive number
Then your insert statement would look something like this:
set #newid = convert(
(select
max(convert( (substring(tag_id, 2)) , unsigned integer))+1
from tags), char(10)
);
set #newid = if(length(#newid) = 1, concat('0', #newid), #newid);
set #newid = concat('c', #newid);
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id,
creation_date, last_edited)
VALUES (#newid, 'Love', 'All about love', 7, now(), '2012-04-15');
Demo: http://www.sqlfiddle.com/#!2/0bd9f/1

this will increase from c01 to c02 to c03 ... to c99 to c100 to c101 ... to c999 to c1000 etc.
set #nextID = (SELECT CONCAT(SUBSTRING(`tag_id`, 1, 1), IF(CHAR_LENGTH(CAST(SUBSTRING(`tag_id`, 2)
AS UNSIGNED)) < 2, LPAD(CAST(CAST(SUBSTRING(`tag_id`, 2) AS UNSIGNED) + 1 AS CHAR), 2,
'0'), CAST(CAST(SUBSTRING(`tag_id`, 2) AS UNSIGNED) + 1 AS CHAR))) FROM `tags` ORDER BY
`tag_id` DESC LIMIT 1);
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id,
creation_date, last_edited) VALUES (#nextID, 'Love', 'All about love', 7, NOW(), null);

Related

SQL IF exist date by day do increment update else insert data

How can I express the below statement as a SQL query ?
IF EXISTS (SELECT * FROM expense_history
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date , '%Y-%m-%d') = '2018-06-02'
AND camp_id='80')
UPDATE expense_history
SET clicks = clicks + 1,
amount = amount + 1
WHERE user_id = 40
AND DATE_FORMAT(expense_history.created_date, '%Y-%m-%d') = '2018-06-02'
AND camp_id = '80'
ELSE
INSERT INTO expense_history (camp_id, created_date, amount, user_id)
VALUES ('80', '2018-06-02 12:12:12', '1', '40')
END IF;
I just want to do increment clicks and amount if is set by day, else I want to add new row.
This is very tricky in MySQL. You are storing a datetime but you want the date part to be unique.
Starting in MySQL 5.7.?, you can use computed columns for the unique constraint. Here is an example:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime datetime, -- note I changed the name
created_date date generated always as (date(created_datetime)),
unique (user_id, camp_id, created_datetime)
);
You can then do the work as:
INSERT INTO expense_history (camp_id, created_datetime, amount, user_id)
VALUES (80, '2018-06-02 12:12:12', 1, 40)
ON DUPLICATE KEY UPDATE
amount = COALESCE(amount + 1, 1),
clicks = COALESCE(clicks + 1, 1);
Earlier versions of MySQL don't support generated columns. Nor do they support functions on unique. But you can use a trick on a prefix index on a varchar to do what you want:
create table expense_history (
user_id int,
camp_id int,
amount int default 0,
clicks int default 1,
. . .
created_datetime varchar(19),
unique (created_datetime(10))
);
This has the same effect.
Another alternative is to store the date and the time in separate columns.
I presumed your database is mysql, because of DATE_FORMAT() function(and edited your question as to be).
So, by using such a mechanism below, you can do what you want,
provided that a COMPOSITE PRIMARY KEY for camp_id, amount, user_id columns :
SET #camp_id = 80,
#amount = 1,
#user_id = 40,
#created_date = sysdate();
INSERT INTO expense_history(camp_id,created_date,amount,user_id,clicks)
VALUES(#camp_id,#created_date,#amount,#user_id,ifnull(clicks,1))
ON DUPLICATE KEY UPDATE
amount = #amount + 1,
clicks = ifnull(clicks,0)+1;
SQL Fiddle Demo

How to assign variables without displaying?

Below is a really scaled down version of my SELECT statement.
SELECT
start_date,
IFNULL(#stop_date := HAIRY_CALCULATION(this_date, that_date)), '') as stop_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days
FROM mytable
I'd like to put the elapsed_days as the second column, but it depends on the existence of the #stop_date variable.
How could I do something like below where I'm assigning the variable without displaying so I can use the variable later in the column calculations?
SELECT
DO_NOT_DISPLAY(#stop_date := IFNULL(HAIRY_CALCULATION(this_date, that_date), '')),
start_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days,
#stop_date as stop_date
FROM mytable
You can always SELECT from a SELECT to narrow down what data you want to propagate:
SELECT stop_date, elapsed_days FROM
(SELECT
start_date,
IFNULL(#stop_date := HAIRY_CALCULATION(this_date, that_date)), '') as stop_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days
FROM mytable) as subset
Note nothing is ever "displayed" except by your client. You're talking about manipulating what ends up in your result sets.
If this is something you're doing frequently and the logic behind it is unlikely to change arbitrarily you might want to wrap this up in a view so you can do something like:
SELECT stop_date, elapsed_days FROM mytable_hairy_view
Edit: Here's a possible two-pass approach:
SELECT
start_date,
IF(stop_date = '', 0, DATEDIFF(stop_date, start_date)) AS elapsed_days
FROM
(SELECT
start_date,
HAIRY_CALCULATION(this_date, that_date) AS stop_date
FROM mytable) as stop_dates
I found one work around. Maybe not the best, but:
SELECT
CONCAT(
-- -------- The following are just variable assignments for later use; they're not displayed in this column.
SUBSTRING(
(#stop_date := IFNULL(HAIRY_CALCULATION(this_date, that_date), '')),
0
),
-- -------- end of variable assignments for later use
start_date
) as start_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days,
#stop_date as stop_date
FROM mytable

mysql: write query with if in where part

i have this table:
(`id`, `name`, `type`, `price`)
(1, 'cats', 1, 12.25),
(2, 'dogs', 0, 11.35),
(3, 'house', 1, 7.25),
(4, 'cats2', 2, 5.26);
I need select all data, but if type is 1, i need get items witch price is more than 10.
I create this query:
SELECT *
FROM `items`
WHERE IF(TYPE = "1", price > 10, 1 = 1)
Works well, but maybe possible write much smarter or in other way?
Maybe don't need "1 = 1"?.
I would like to know your advice, thanks
Your 1=1 is senseless, but your IF is not. You can use just 1:
SELECT *
FROM `items`
WHERE IF(TYPE = "1", price > 10, 1)
-since MySQL evaluates expression as bool (actually, int) - and so 1 means 'true'.
But on the other hand, there's logic equivalent for your condition:
SELECT *
FROM `items`
WHERE `price`>10 OR `type`!="1"
However, I've faced such case in another question and, after some researching, I've discovered that IF is faster, even if it looks more complicated.

Mysql substring string and attach chars such as ... to result command

My subject field is (maybe) bigger than 100 characters. I want to use LENGTH if subject length is bigger that 100 char in below mysql command and attach ... to end of SUBSTR subject.
SELECT id ,
IF LENGTH(`subject`) <=100 then SUBSTR( `subject`, 1, 100 ) AS subject
ELSE `subject`
END IF
FROM `contents`
You might be looking for CONCAT function in MySQL.
SELECT id ,
CASE WHEN LENGTH(`subject`) >=100 then CONCAT(SUBSTR( `subject`, 1, 100 ),'...')
ELSE `subject`
END AS `subject`
FROM `contents`
Sample fiddle
Have a look here as well.
Rather another simpler way could be you can fetch the subject using your simple mysql query. and can display your subject this way!!
For ex: $subject = substr($data['subject'], 1, 100)

Is it possible to search for a value, optionally looking at the trailing 0's in decimal values

So what I'm after is searching for "1.00" needs to find matches on 1, 1.0, 1.00, 1.000, 11, 11.00, etc
So what I'm after is a simple search, but with the trailing decimal places are optional, as they may or may not be added by the users to the database.
Currently I have this, which obviously won't do the trick
SELECT *
FROM `prices`
WHERE `price` = '%1.00';
Doing the following will work, but I'd like something more concise, as the
SELECT *
FROM `prices`
WHERE `price` = '1.00'
OR `price` = '1.0'
OR `price` = '1';
# NOTE THE LACK OF DECIMAL PLACE
What you're really trying to do is to compare these strings as numbers, right? If that's true, then convert price to a number using addition.
Try this:
SELECT *
FROM `prices`
WHERE (0 + `price`) = 1;
If it's a decimal, you could do this:
SELECT *
FROM `prices`
WHERE ROUND( 0 + `price` , 2 ) = 0.99;
Looks like I can achieve this using the TRIM() function, as in
SELECT TRIM(TRAILING '0' FROM `price`) as trimmed
FROM `prices`
WHERE trimmed = '1'
https://stackoverflow.com/a/7968606/1613391