In MySQL is it possible to auto increment in pairs? - mysql

I have match_id which always comes in pairs. Instead of incrementing as follows:
1,2,3,4...
Is it possible to increment like this:
1,1,2,2,3,3,4,4
If not how can I guarantee that I will always have at most two identical match_id. I've tried to implement a Manual solution in code but occasionally I get three at a time if there is a collision.
This is not a primary key. However I want the match_id to come in pairs so that if I look up match 56, it will show the following:
match_id, user_id, score
56, 29, 434
56, 49, 516
Dividing by two is a possible solution although it makes the queries really messy. For example searching for match 56 becomes really convoluted

I'm pretty sure that you cannot autoincrement in pairs like that. However, you can easily treat a column that has 1,2,3,4,... as if it had 1,1,2,2,3,3,4,4,... by using FLOOR((match_id+1)/2) instead of match_id. You can either use that expression in your data retrieval statements or else denormalize your data base and define a column where you insert that value along with the autoincrement value.

Related

MySQL- INDEX(): How to Create a Functional Key Part Using Last nth Characters?

How would I write the INDEX() statement to use the last Nth characters of a functional keypart? I'm brand new to SQL/MySQL, and believe that's the proper verbiage of my question. explanation of what I'm looking for is below.
The MySQL 8.0 Ref Manual explains how to use the first nth characters, showing that the secondary index using col2's first 10 characters, via example:
CREATE TABLE t1 (
col1 VARCHAR(40),
col2 VARCHAR(30),
INDEX (col1, col2(10))
);
However, I would like to know how one could form this using the ending characters? Perhaps something like:
...
INDEX ((RIGHT (col2,3)));
);
However, I think that says to index over a column called 'xyz' instead of "put an index on each column value using the last 3 of 30 potential characters"? That's what I'm really trying to figure out.
For some context, it'd be helpful to index something with smooshed/mixed data and am playing around as to how such a thing could be accomplished. Example of the kind of data I'm talking about, below, is a simplified, adjusted version of exported data from an inventory/billing manager that hails from the 90's that I had to endure some years back...:
Col1
Col2
GP6500012_SALES_FY2023_SBucks_503_Thurs
R-DK_Sumat__SKU-503-20230174
GP6500012_SALES_FY2023_SBucks_607_Mon
R-MD_Columb__SKU-607-2023035
GP6500012_SALES_FY2023_SBucks_627_Mon-pm
R-BLD_House__SKU-503-20230024
GP6500012_SALES_FY2023_SBucks_929_Wed
R-FR_Ethp__SKU-929-20230324
Undoubtedly, better options exist that bypass this question altogether- and I'll presumably learn those techniques with time in my data analytics coursework. For now, I'm just curious if it's possible to somehow index the rows by suffix instead of prefix, and what a code example would look like to accomplish that. TIA.
Proposed solution (INDEX ((RIGHT (col2,3)))):
Not available.
Case 1:
When you need to split apart a column to search it, you have probably designed the schema wrong. In particular, that part of the columns needs to be in its own column. That being said, it is possible to use a 'virtual' (or 'generated') column that is a function of the original column, then INDEX that.
Case 2:
If you are suggesting that the last 3 characters are the most selective and that might speed up any lookup, don't bother. Simply index the entire column.
That data:
I would consider splitting up the stuff that is concatenated together by _. Do it as you INSERT the rows. If it needs to be put back together, do so during subsequent SELECTs.
DATEs:
Do not, on the other hand, split up dates (into year, month, etc). Keep them together. (That's another discussion.) Always go to the effort to convert dates (and datetimes) to the MySQL format (year-first) when storing. That way, you can properly use indexes and use the many date functions.
MySQL's Prefix indexing:
In general it is a "bad idea" to use the INDEX(col(10)) construct. It rarely is of any benefit; it often fails to use the index as much as you would expect. This is especially deceptive: UNIQUE(col(10)) -- It declares that the first 10 chars are unique, not the entire col!
CAST:
If the data is the wrong datatype (string vs int; wrong collation; etc), the I argue that it is a bad schema design. This is a common problem with EAV (Entity-Attribute-Value) schemas. When a number is stored as a string, CAST is needed to sort (ORDER BY) it.
Functional indexes:
Your proposed solution not a "prefix", it is something more complicated. I suspect any expression, even on non-string columns will work. This is when it became available:
---- 2018-10-22 8.0.13 General Availability -- -- -----
MySQL now supports creation of functional index key parts that index
expression values rather than column values. Functional key parts
enable indexing of values that cannot be indexed otherwise, such as
JSON values. For details, see CREATE INDEX Syntax.

Couchbase Multi-Key Get with Composite Keys

I've got a problem with querying a Map/Reduce view in Couchbase for specific keys.
The view maps some documents in Couchbase, emitting a composite key and a value and calls the built-in _stats reduce function. I'm grouping on the 2nd part of the key (group=true&group_level=2) and the results are exactly what I want.
The issue I've got is I need to find the "reduce" result for specific document IDs which aren't necessarily sequential, so I can't use startkey and endkey.
For example, looking up the results for document IDs 2, 5, 8, 18, using &startkey=[2, null]&endkey=[18,"\u0fff"] could potentially return results for documents with IDs 3, 4, 6, 7, 9-17.
I'm looking at using the keys=[] parameter to specify the document IDs to look for, but can't work out how to do this when using a composite key.
Is this possible, and if so, how do I do it?
Turns out I was misunderstanding how this should work, after some reading I've made split different bits of my query out into separate views and it now works as I expect it to.
The reduce view now has a single key, rather than a composite key, which means I can query it via the keys parameter.

MySQL insert between ID's

If I have a database with the following information, how can I setup my next INSERT query so that the ID is filled in? (so that it is 5 in this instance.)
Basically, once it gets to 24, it will continue inserting in order (ex: 30,31,32)
You don't. Not with an auto-incrementing integer anyway.
You could change the column to not be an auto-incrementing integer, but then you'll need to determine the next ID before performing each insert which would make all of your INSERT queries unnecessarily complex and the code more difficult to maintain. Not to mention introducing a significant point of failure if multiple threads try to insert and the operation to find the next ID and insert a record isn't fully atomic.
Why do you even need this? There's no reason for a database-generated primary key integer to be contiguous like that. Its purpose is to be unique, and as long as it serves that purpose it's working. There's no need to "fill in the holes" left by previously deleted records.
You could add a different column to the database and perform the logic for finding the next contiguous number when inserting records on that column. But you'd still run into the same aforementioned problems of race conditions and unnecessary complexity.
Change your filename to something more meaningful than the id.
I think something like files/uploads/20130515_170349.wv (for the first row) makes a lot of sense (assuming you don't have more than one file per second.
This also has the advantage that ordering the file names alphabetically is chronological order, making it easier to see the newer and older files.
You can just give it the I'd field and value
Insert into table (I'd, etc, etc) values (5, etc, etc);
However I don't think you can do it dynamically. If I'd is auto increment then it'll keep on oncrementinf whether or not previous tuples have been deleted etc.

Most efficient way to keep track of a list of numbers selected by users using MySQL?

Let's say users can choose any amount of numbers from a list of 1 - 300, and we need to keep track of each user's choices. Remember, they can choose up to 300 numbers (e.g.if they choose all of them, 1, 2, 3 ... 299, 300), none at all, or something in between (e.g. 4, 17, 87, 113, 189, 251, 289).
What is the best, most efficient way to keep track of each users selection in MySQL?
The two alternatives I can think of are:
1) One row for each user, with a column containing a comma-separated list of their selection. Adding and removing selections requires getting that user's column, adding/removing the selection, and then saving the list back to the column.
and
2) One row for each individual selection, with a column for the user it corresponds to and another column for the individual selection made. Adding and removing selections requires simply doing an INSERT or a DELETE of the row corresponding to that user and selection.
Well, 2) seems to be more "natural" for the DB, but it almost seems inefficient when you have hundreds of thousands of users each making up to 300 selections, which would create a Table with a number of rows equal to the product of those two. Whereas 1) would only contain the number of rows equivalent to the number users.
That said, I'm leaning towards 2) since it's more natural for the DB, but I just wanted to make sure it's the correct option and there is no more efficient way of doing this, since I don't want my site to slow down because of this as it gets bigger and bigger.
Thanks!
Properly indexed #2 is better if anything due to the sparsely populated nature of #1 from a memory/disk perspective. Also, 1 or 300 rows per user means little to indexed lookups where you are performing the search in logrithmic time.
SQL is very efficient at handling rows of data, it is much less efficient at querying data within one column.

Reassigning the values of a table PK randomly

Which is the easiest way to perform the following in MySQL 5.1?
I have a table with a primary key as an integer, currently running from 1 to 220. The PK runs sequentially depending on the order in which the rows were written to the table.
I want to be able to randomly reassign this primary key value, so that, for example, row 1 (with a PK of 1 currently) becomes 19 (for example), row 2 becomes 142 (for example), row 3 becomes 99 (for example), etc. and so forth so that all numbers between 1 and 220 will be reassigned to the PK.
Is there a simple way of doing this?
Thanks,
Tim
There is no simple way to do it entirely within SQL. (There is most likely a complex way that isn't worth it.) I recommend you make it the responsibility of application-level logic.
I also recommend that if this is for some kind of 'card-shuffling' type purpose, you use a secondary unique key instead of the primary key.
Thanks for your answers. However, I found a reply to a post which does exactly what I required. It is here:
MySQL query to assign a unique random number to each row
Update the primary key field with the Rand Function. To get an integer, you'd have to multiply it by 100, 1000, etc (depending on how big of a number you wanted) and then truncate the remaining decimal.
Your script, which I'd presume you'd write to do this, would need to ensure that a duplicate number wasn't generated and thus a failed attempt to update was made. I'd do this via a loop, an single update statement wouldn't work because of how Rand works. (At least for other RDBMS)
Is it important for us to know the reason for your doing this? The reason might change my answer...
You'd want to assign a random value to the ID column, then sort by it and reassign the ID based on position in the sorted rows.