MySQL Insert with functionality similar to Window's default file naming - mysql

I have a table with a name column. Initially a name is not added to the table but I would like to add a default name when a new row is inserted, much like window's functionally when creating a new file. I'm trying to figure out how to query the number which is suppose to be next in the sequence.
For example, if my table looks like this:
id | name
==========
1 | New Name (1)
2 | real name
3 | New Name
The next inserted row's name should be "New Name (2)". If my table looks like this:
id | name
==========
1 | New Name (2)
2 | real name
or this:
id | name
==========
1 | another name
2 | real name
The next inserted row's name should be "New Name". If my table looks like this:
id | name
==========
1 | New Name (2)
2 | real name
3 | New Name
4 | New Name (3)
The next inserted row's name should be "New Name (1)". Thus far I was able to create the query to get the existing numbers ("New Name" = 0)
SELECT SUBSTRING_INDEX(SUBSTR(d.name,INSTR(d.name,'(') + 1), ')', 1)
FROM data d
WHERE d.widget_name REGEXP '^New[[:space:]]Name[[:space:]]\\([[:digit:]]\\)$'
UNION
SELECT 0
FROM data d
WHERE d.name REGEXP '^New[[:space:]]Name$'
Now I need a way to to turn that list of numbers to a single number which will indicate whats the next default name enumeration. I've tried using NOT EXISTS from this question but I couldn't figure out how to use the code above both in FROM and the WHERE.
I also tried to do this by creating a row_num functionality using a_horse_with_no_name's answer in this question. Assuming num_data is the result of the query(trying to keep it clean) table and it's column name is name_num:
SELECT IFNULL(row_number, (SELECT IFNULL(MAX(name_num),0)
FROM num_data))
FROM (SELECT #rownum:=#rownum + 1 AS row_number, t.*
FROM (num_data) t,
(SELECT #rownum := 0) r) gap_table
WHERE gap_table.row_number <> gap_table.widget_num
ORDER by row_number
LIMIT 1;
But that didn't seem to get it right too.

If you want the next name for a given name, I would expect the query to look like this:
select (case when count(*) = 0 then $name
else concat($name, '(',
max(substring_index(name, ' (', -1) + 0) + 1,
')')
end)
from num_data
where name rlike concat($name, ' [(][0-9]+[)]' or
name = $name;
Here is a SQL Fiddle demonstrating it.
This assumes that name being tested is provided by a parameter called $name.
Note: The above query generates the new name. It should be obvious how to get the next number in sequence.

This did the trick, thanks to #GorodonLinoff's answer:
select (case when count(*) = 0 then '$name'
when max(name = '$name') = 0 then '$name'
when max(name = '$name(1)') = 0 then '$name(1)'
else concat('$name', '(', max(substring_index(name, '(', -1) + 0) + 1, ')')
end)
from data
where name rlike concat('$name', '[(][0-9]+[)]') or
name = '$name';

Related

Query which Find string and increment the count

I have table like that,
id name count
1 rrr 2
2 www 3
3 qqq 4
4 aaa 5
5 gyhhh 4
6 dfgdfg 5
I want to write the query which find the name in table and if it find then increment the count in count column for that name. The count maintain the no of time name used by the user.If user used the name , then I am check the name in db , if it found then I want to update row with increment in count.
A simple update query required:
If you want to increase count only if the input parameter exactly matches the name then use this:
UPDATE your_table
SET `count` = `count` + 1
WHERE `name` = ?
And if you want to increase count if the input parameter is a substring of name then you can use LIKE
UPDATE your_table
SET `count` = `count` + 1
WHERE `name` LIKE CONCAT('%',?,'%')
Note: Replace the question mark (?) by your input parameter.
Try this:
select id,name, id + 1 from
(Select id,name from table_name where name in('sa','da','ba','ca')) as a;
hope it helps..

Append string to a record's specified column after SELECT command

I have an sql command that returns me a list of duplicated items (in my MySQL database), only two columns, one for the duplicated value and one for the count of duplicated records.
SELECT title, COUNT(*) c FROM posts GROUP BY title HAVING c > 1
title c
---------------
title_1 2
title_a 2
title_b 2
I assume one result looks like this:(and it's an array of arrays)
objId title
------------
1 title_1
2 title_1
So my goal is to append a string to the second item of a result in the array of the duplicated record's like this:
objId title
------------
1 title_1
2 title_1_2
I've found a solution to update the record, but I don't have an idea how could I loop through the results that I get after the first sql command so I can't utilize it in practice.
UPDATE posts SET title = CONCAT(IFNULL(title,''), ' 2');
In pseudo code I would do something like this to create the new string for the title:
result[1].title = (oldTitleString," 2");
save result[1];
I'm new in sql and don't really know about the possibilities, maybe there would be an easier way to do it, so I would really appreciate if somebody could show me how can I get the second record from the duplicated item and extend it with another string.
My solution:
SELECT `objId`,`title`,
(SELECT CONCAT(`title`, '_', `po`.`objId`)
FROM `posts` `p`
WHERE `title` = `po`.`title` && `p`.`objId` < `po`.`objId` LIMIT 1) AS `title_custom`
FROM `posts` `po`
Here is sample fiddle:
http://sqlfiddle.com/#!9/a4164/8
Query looks like this:
select id, title,
concat(title,'_',
(select count(*) from posts p2 where p2.title = p1.title and p2.id <= p1.id)),
title,
count(*) c
from posts p1
group by title
having c > 1

how can extract part of a text from a field in mysql?

I have fields like this:
-----------------
id | name
-----------------
1 | name123
-----------------
2 | name
-----------------
3 | name456
-----------------
4 | name
I want to extract rows which have digit in name and a field that contains the number like this
------------------------------
id | name | number
-----------------------------
1 | name123 | 123
-----------------------------
3 | name456 | 456
how can we find the records that have digit and extract digit as a new field?
Here is another way to do with mysql
SELECT
id,
name,
SUBSTRING(
name,LEAST (
if (Locate('0',name) >0,Locate('0',name),999),
if (Locate('1',name) >0,Locate('1',name),999),
if (Locate('2',name) >0,Locate('2',name),999),
if (Locate('3',name) >0,Locate('3',name),999),
if (Locate('4',name) >0,Locate('4',name),999),
if (Locate('5',name) >0,Locate('5',name),999),
if (Locate('6',name) >0,Locate('6',name),999),
if (Locate('7',name) >0,Locate('7',name),999),
if (Locate('8',name) >0,Locate('8',name),999),
if (Locate('9',name) >0,Locate('9',name),999)
),LENGTH(name)
) as number
from users
having number <> '' ;
you can use MySQL's string conversion on an int to strip out the name like so
SELECT
t.id,
t.name,
REVERSE(REVERSE(t.name)+ 0) AS num,
REPLACE(t.name,REVERSE(REVERSE(t.name)+ 0),'') AS actualname
FROM foobar t
HAVING num <> 0
the trick with this is by adding a 0 mysql is comparing the numeric value in the name... however the name has to start with a number... so I reverse it do the calculation and then reverse again... NOTE all of your names have to start with the name and end with a number for this to work for all of them
FIDDLE DEMO
EDIT:
since you say that some can start with a number and others end with a number.. then try this
SELECT
t.id,
t.name,
REVERSE(REVERSE(t.name)+ 0) AS num,
REPLACE(t.name,REVERSE(REVERSE(t.name)+ 0),'') AS actualname
FROM foobar t
HAVING num <> 0
UNION ALL
SELECT
t.id,
t.name,
t.name + 0 AS num,
REPLACE(t.name,t.name + 0,'') AS actualname
FROM foobar t
HAVING num <> 0
ANOTHER DEMO
Another way, assuming the number you want is at the end of the string. REVERSE() to put the number part in front, then CONVERT() to make it a number and strip off the text, then REVERSE() again WHERE name ends in a number. Feels like a kludge though:
select id, name, reverse(convert(reverse(name),signed ))
from tbl
where name REGEXP '[0-9]+$';
SQL Fiddle Example

Trying to write a query to look at business and address information

I have 1 input field for a user to type in either a business name, city and state, or zip code. I want to be able to pull back the correct data, but right now i'm getting incorrect results.
For example, if someone searches for "ERICS", it returns fine, but if someone searches for "ERICS ROCHESTER MN", it returns all of the results from ROCHESTER, MN. I want it to return no results in that case.
By the way, I am parsing out the data so i'm passing in up to 4 values in my query. business name, city, state, zip.
How can I modify my query so that it will give me the correct results? Can I somehow check in the query which variables are not null?
Schema
Business
business_id | name | city | state | zip
1 TOMS ROCHESTER MN 55906
2 BILLYs MINNEAPOLIS MN 55555
3 ERICS LAX WI 11111
Rating
rating_id | rating
1 GOOD
2 BAD
business_rating
br_id | business_id | rating_id
1 1 1
2 1 2
select b.business_id,
b.name,
b.city,
b.state,
b.zip
count(br.business_id) num_ratings,
round(avg(br.quality_id),2) quality_rating,
round(avg(br.friendly_id),2) friendly_rating,
round(avg(br.professional_id),2) professional_rating
from business b
Left Join business_rating br
On br.business_id = b.business_id
Left Join rating r
On r.rating_id = br.quality_id
And r.rating_id = br.friendly_id
where (upper(b.business_name) like '%ERICS%'
and upper(b.city) like '%ROCHESTER%'
and upper(b.state) like '%MN%'
and upper(b.zip) like '')
or (upper(b.city) like '%ROCHESTER%'
and upper(b.state) like '%MN%'
and upper(b.zip) like '')
or (upper(b.city) like '%ROCHESTER%'
and upper(b.state) like '%MN%')
or (upper(b.zip) like '')
group by id
Notice your WHERE clause - you're asking for a four-part match OR a three-part match, etc. That's why a three-part match (city, state, zip) is being returned.
The best way to handle this is to ship it out to a real search engine, e.g. solr.
Since you didn't ask for the best way, here's my answer to your question:
Write 4 queries.
One query for one-part requests, one query for two-part requests, etc. Have your code branch (or overload) based on how many parameters were provided.
This is assuming that, if there were no "ERICS", you would want to return no results, rather than showing some other bar in Rochester.
Oh, and don't apply functions (e.g. UPPER) to your columns - the engine will not be able to use your indexes to satisfy the query. Of course, using unanchored LIKE patterns will also preclude the use of indexes. Really, seriously, try solr.
Or, try this...
This query creates a *max_score* based on the number of fields that you've provided as non-null.
It calculates the number of columns that match the input, which is the score.
Then it only shows those rows whose score is the max.
set #NAME = "erics";
set #CITY = "rochester";
set #STATE = "MN";
select id,
case when #NAME is not null then 1 else 0 end +
case when #CITY is not null then 1 else 0 end +
case when #STATE is not null then 1 else 0 end +
case when #ZIP is not null then 1 else 0 end as max_score,
case when #name is not null and name like concat("%", #NAME, "%") then 1 else 0 end +
case when #city is not null and city like concat("%", #CITY, "%") then 1 else 0 end +
case when #STATE is not null and state like concat("%", #STATE, "%") then 1 else 0 end +
case when #ZIP is not null and zip like concat("%", zip, "%") then 1 else 0 end as score
from business
having score = max_score;
Now, please go install solr.

Change results in mysql query

I would like to manipulate the result I get from a query.
I have a set of 2.5m rows and there are 10 different ID's for a status. These statusses are not mapped in another table but I would like to manipulate the result I get in SQLyog.
What I would like to do is:
Count(Id) | Status
------------------
500.000 | 1
750.000 | 2
convert into a result
Count(Id) | Status
-------------------
500.000 | Initial order
750.000 | Cancelled
Can this be done in the query? Note that I'm not using PHP or a browser to display the results.
select
count(*) as TotalRecs,
case status
when 1 then "Initial Order"
when 2 then "Cancelled "
when 3 then "whatever "
else "all others "
end case as WordStatus
from
YourTable
group by
2
You can either inline it in a case statement
select COUNT(id),
case status
when 1 then 'initial order'
when 2 then 'cancelled'
# without an else, the rest go to NULL
end status
from tbl
group by status # yes, just on status
Or I would strongly encourage you to create a reference table for this
Tbl Status contains 2 columns ID and Description
select COUNT(tbl.id), status.description
from tbl
LEFT join status on status.id = tbl.status
group by status.description