SQL autoincrement in 'string' - mysql

I know about autoincrement, and that I might be better off doing a table of its own for this, but for some specific performance reasons I would prefer not to.
I have a row looking like this:
id,log
1 | 1:345;2:2345;3:234
Is there ANY way where I with a single SQL update can add X to the log column, and automatically a '4' as the log entry's id?

From your example I can't be entirely sure, but it looks like you don't even need the index numbers, i.e.
id | log
1 | 345;234;234
So you can simply add the entry, optionally prefixed with a ;. Later, any code can interpret the log contents by splitting on ;.

how about build a new table like this:
my_log
-------
id
sub_id
val
and populate it with all the proper parsed values -
then query from here to rebuild the string if needed, otherwise throw out the original table completely - terrible design.

Related

How to create a table of wildcards

I have a table called blacklisted_usernames. These are usernames with wildcards in them that aren't allowed to be registered onto my site.
create table blacklisted_usernames (
name varchar(64) not null
);
Some dummy data:
insert into blacklisted_usernames (name) values
('%admin%'),
('king%'),
('bad'),
('%cool');
The % indicates the same thing as the wildcard in the LIKE function in MySQL. I want to create an efficient case insensitive query which tells me if a username is blacklisted or not. For example is the username AdminJohn allowed? The answer would be no, because of %admin% being in the blacklisted_usernames table.
I understand I can do something like
SELECT 1
WHERE 'AdminJohn' LIKE '%admin%'
or 'AdminJohn' LIKE 'king%'
or 'AdminJohn' LIKE 'bad'
or 'AdminJohn' LIKE '%cool'
But I am manually typing out all the LIKE's. I also don't think it would be efficient if I created a loop checking it 1 by 1. Is there a way I can make this into an automatic but efficient way of checking against the names in blacklisted_usernames table and determining if a username is allowed?
select 1 from blacklisted_usernames where 'AdminJohn' like name limit 1
Another approach is to use a REGEXP to test them all in a single test:
WHERE 'AdminJohn' REGEXP 'admin|^king|^bad$|cool$'
(Note how the wildcards go away on some and "anchors" are needed on the others.)
Probably this is faster than the original OR+LIKEs or the JOIN+LIKEs. When checking one name REGEXP will be plenty fast (no table scan).
If you need to check all existing names against the blacklisted patterns
SELECT usernames.name,
blacklisted_usernames.name blacklisted_pattern
FROM usernames
JOIN blacklisted_usernames
ON usernames.name LIKE blacklisted_usernames.name
Pay attention - this is complete tablescan, the indices won't be used, so the query will be slow.
You may need to check all existing names against newly added/altered patterns - in this case add according WHERE by blacklisted_usernames table (for example, by created_at or updated_at column).
If you need to check currently created username against all patterns then use the solution provided by ysth.

Conditional deletion from mySQL database

I have a list of clients containing some numbers. Different clients may share these numbers between each other (one client may "borrow" some of his numbers to the other) but if the "borrower" gets deleted he has to return those numbers.
My table structure looks like that:
id | client | range_num_up | range_num_down | ... | former
What I am trying to achieve here is that:
- if the numbers assigned to the client had no former: delete them from database
- else the numbers must be assigned to the former once again
I am aware of SELECT IF statements in the mySQL but I am not quite sure how to tie it up together with one query.
I already tried something like:
SELECT IF(former is NULL, '', former) former FROM numbers_pool WHERE id = 3
Which returns to me a name of the former owner of the numbers. Now I would like to use that information to handle the query along. What I image is following scenario:
if reply == '' {
DELETE THAT ENTRY
}
else {
UPDATE THE NAME OF THE CLIENT WITH RECEIVED FORMER
}
Any tips and help is appreciated.
#edit
To be precise: I know I can you DELETE but that still does not cover the second scenario in which I would like to update that record. So I am looking for one-query-solution.
You can't do both DELETE and UPDATE in a single statement - they are different types of query. You could write a short routine (e.g. procedure or function, or just a routine in a script file you load and execute) which would execute all the necessary statements in a single operation.
The logic should be fairly simple:
First check the value of former using a SELECT and read the value into a variable. If you get a value, then do the necessary UPDATE. If you get NULL, do the DELETE instead. You don't need to rely on the result of the DELETE to decide what to do with the UPDATE (or vice versa).

Force auto increment to follow another suequence

I have a table containing invoices. Those invoices are inserted via a VB.NET program I have written. Using auto increment my invoices get their invoiceid.
I now have invoiceid's like
1055
1056
1057
...
I also have another database (from another bought software program) that generate invoices, and I use a cron job to import certain invoices into my main table, but they get the prefix 99. Those invoices do not have the same sequence. I do not use auto increment to number them, but I use the original ID (from the other database) + the 99 prefix. In my main table I have invoiceid's from the secondary database like this:
992013055
992013064
992013078
So, this makes that my main table looks like this:
992013055
1055
1056
992013064
1057
992013078
...
Now the thing is, I want the auto increment only follow the 'main' sequence. So in the example above, the next auto increment value should be 1058, but using normal auto increment it would be 992013079.
Is there a way to force this? Or should I "reset" the auto increment value after the cron job, something like "ALTER TABLE invoices AUTO_INCREMENT=bla +1". I guess 'bla' should be a new select to get the highest value in the column that does not start with 99, not sure how to do this. Off course when I get to invoice 9900, this would be a problem.
Thank you
i would create another column or table that links in this external id and do not try to layer them in to your id column like you are attempting.
for instance add a column called external_id and simply populate that one with the 99 values - and keep your autoincrement value chugging along properly with your regular numbers.
No you can't. Even if you tried the ALTER TABLE invoices AUTO_INCREMENT=bla +1 command, it would not work, as MySQL makes sure the value of AUTO_INCREMENT is higher than the highest value in the column.
Basically you shouldn't use the value in your autoincremented column for anything else than primary key, so that you don't really need to care about what these values are and what sequence they follow. After all nobody sees them and they're only used by computer.
If however you used these values for something that's visible for the end user... well your users will just need to adjust to the fact, that their invoces start from 99 now. Either that, or you need to renumber them, which is hell of a work and likely to introduce errors to your data.

Storing array with values in database

I have the following data which I want to save in my DB (this is used for sending text messages via a 3rd party API)
text_id, text_message, text_time, (array)text_contacts
text_contacts contains a normal array with all the contact_id's
How should I properly store the data in a MySQL database?
I was thinking myself either on 2 ways:
Make the array with contact_id's in a json_encoded (no need for serializing since it's not multi-dimensional) string, and store it in a text field in the DB
Make a second table with the text_id and all contact_id's on a new row..
note: The data stored in the text_contacts array does not need to be changed at any time.
note2: The data is used as individual contact_id to get the phone number from the contact, and check whether the text message has actually been sent.. (with a combination of text_id, and phonenumber)
What is more efficiƫnt, and why?
This is completely dependent upon your expected usage characteristics. If you will have a near-term need to query based upon the contact_ids, then store them independently as in your second solution. If you're storing them for archival purposes, and don't expect them to be used dynamically, you're as well off saving the time and storing them in a JSON string. It's all about the usage.
IMO, go with the second table, mapping text-ids to contact-ids. Will be easier to manipulate than storing all the contacts in one field
This topic will bring in quite a few opinions, but my belief: second table, by all means.
If you ever have a case where you actually need to search by that data, it will not require you to parse it before using it.
It is a heck of a lot easier to debug (for the same reason)
json_encode and json_decode (or equivalent) take far more time than a join does.
Lazy loading is easier, even if not necessary in most cases.
Others will find it more readable and, with a good schema definition, easier to conceptualize and maintain.
Almost all implementations would use one table for storing each text_contacts, and then a second table would use a foreign key to reference the text_contacts table. So, if say you had a table text_contacts that looked like this:
contact_id | name
1 | someone
2 | someone_else
And a text message table that looked like this:
text_id | text_message | text_time | text_contact
1 | "Hey" | 12:48 | 1
2 | "Hey" | 12:48 | 2
Each contact that has been sent a message would have a new entry in the text message table, with the last column referencing the contact_id field of the text_contacts table. This way makes it much easier to retrieve messages by contact, because you can say "select * from text_messages where text_contact = 1" instead of searching through each of the arrays on the single table to find the messages sent by a specific user.

how to convert multiple mysql column string to date

please i have a modified_by column in mysql table with string like this "40,1280825613|40,1280825617". the "40" is the id of the user that made changes to the record and "1280825613" is the date string. The | separates different periods of change.
How do i change the entire column to a readable date without affecting the user id. either mysql or php solution is welcome. Thank you so much.
I'd recommend a PHP script. You'll need to make two columns modified_by to retain the user id and modified for the timestamp. If there are multiple modified_by for each record you'll probably want to make a separate table, i.e. revisions. This would be the best way to store the data relationship. I'd also recommend not storing formatted data. You should already see why that's not a good idea. The database is the raw data, use PHP to format it.
Once you have that setup, just:
Select the data from the old table.
Loop over the records
explode() the column on |
Loop over the array
explode() the element on ,
Insert into new columns/table
Forgive me, but I'd rather teach you how to fish.