Access: DMax and String ID - ms-access

Because the developers of the Oracle database we use are hell-bent on making my life difficult :), they decided to use numbers for the PK for some tables and VARCHAR for the PK for other tables.
For the Access front-end I'm building, I have a form with a textbox which I want to display the last ID used on a table + 1 (so if the last ID was 100, then 101 would display in the box). Naturally, the table I need to do this on as a VARCHAR ID, even though all of the IDs are sequential numbers. Converting the field to numeric, while would fix my purpose, is not going to happen.
So, my question: in my other textbox where the ID is numeric, I am able to use DMAX to find the last number used; however, this isn't working for the string ID. I've read about using the Val() function to convert the string to text, but I can't figure out how to use both. I tried the following:
DMax(Val("[EAUSER_INFORMATION_ITEM]![INFORMATION_ITEM_ID]"),[EAUSER_INFORMATION_ITEM],"")
but this comes back with a #Name? error.
Would someone point me in the right direction?
Thanks!

You should use Val inside of the quotes, not outside of them, else you get this problem. Also, all arguments inside of a domain aggregates need to be strings:
DMax("Val([INFORMATION_ITEM_ID])","[EAUSER_INFORMATION_ITEM]")
You can omit the last argument, the WHERE condition, if you're not using it, and you don't need to specify the tablename if there's only one table.
You probably can't do anything about it, but using ascending numeric strings as primary keys is a major bad practice. Most database engines will sort in ascending order, causing massive fragmentation (because "100" < "2" is True)

Related

How to manage JSON query performance in MySQL DB

I have a Mysql8 DB which contains JSON data. Unfortunately, the content is not always the same. To make it simple, the hierarchy is always the same, but sometimes part of the "tree" is missing or slightly different. For instance:
$.bilan.victimes.*.preview.TAGSAU (I use a star, since sometimes, it's '1', '2', etc... and sometimes it is only '$.bilan.victimes' (without further subkeys)
Now, I am using queries to lookup information in the JSON like:
SELECT
COUNT(fiche_id) AS USAGE_DSA,
JSON_VALUE(content, '$.bilan.victimes.*.preview.DSA') AS DSA
FROM bilan_json
WHERE STR_TO_DATE(JSON_VALUE(content, '$.bilan.victimes.*.preview.TAGSAU'),'%e/%c/%Y %H%#%i') >= '2021-01-01'
GROUP BY DSA;
This is working fine, but since there is a lot of records, and JSON could be very long, it takes an awful bunch of time to display the result. In this example, this is only key... I am supposed to retrieve multiples values from the JSON, sometimes in a single query.
I've read about virtual columns (https://stackoverflow.com/questions/68118107/how-to-create-a-virtual-column-to-index-json-column-in-mysql#:~:text=if%20table%20is%20already%20created%20and%20you%20want,%60jval%60%3B%20Dont%20forget%20to%20index%20the%20Generated%20Columns) and also improving performance for JSON object (https://blogit.create.pt/goncalomelo/2018/12/20/query-performance-for-json-objects-inside-sql-server/) but I can't really figure out if I should create a virtual column per key ? And, how can I create a virtual column with a transform ? In above case, I would create something like :
ALTER TABLE bilan_json
ADD COLUMN tagsau DATETIME
GENERATED ALWAYS AS STR_TO_DATE(JSON_VALUE(content, '$.bilan.victimes.*.preview.TAGSAU'),'%e/%c/%Y %H%#%i')
AFTER content;
What would be your advice ?
Simply put, If you expect to need a field in JSON for a WHERE or ORDER BY clause, that field should be in its own column.
3 approaches:
Redundantly store it in a column as you INSERT the rows.
Use a Virtual ("Generated") column (as you suggest).
Remove it from JSON as you put it in its own column.
Once it is in a column, it can be indexed. (It is unclear how useful an index would be for the SELECT you show.)
Did you try that ALTER? Did it work? We need SHOW CREATE TABLE in order to advise further.

How to use Key-Value pair in Relational database(MySql)?

I wanted to use a relational database(MySql) to store my data as key-value pair.
I would be getting no. of key-value pairs dynamically.
I can create a simple table to store them in separate columns.
Values can be of type- int, varchar, text or date.
The problem which I am facing is:
When I need to run a query on key whose value should be an integer and I need to use and greater than or less than query with it. Same case when I need to use between query with date fields.
How can I achieve it?
------------------------------------------------Edit---------------------------------------------------
For greater clarity, I am providing the background for this question which I have divided into three parts:
1. Data 2: Use Case 3. Possible Designs
1. Data
Suppose I'm creating data store for census of a country**(Just an example)**. Fields for storing data would be different for male, female, boy or girl and also it will vary according to the person's profession. The number of fields depends on the requirement which can increase up to 500 or more.
2. Use Case
Show a paginated list of persons whose monthly income is between $7000 to $10000. User can click on any page number and the database should directly fetch the data for that page number. For example, if we are showing 10 results in a page and user clicks on the 5th page then we should show him the list of the person's from 40 to 50.
Some of the values belonging to a particular group store description which can have large data. So they should be stored as TEXT.
3. Possible Designs
I can create a separate table for each different type and store their data in respective fields. But the problem I'm thinking about this approach is that MySQL table has a maximum row size limit of 65,535 bytes. Going by this approach and storing all data horizontally might cross the max size limit. As the number of fields are not fixed and can change as per requirement.
Instead of storing data horizontally I can store them vertically using Entity Attribute Value design(key-value pair). For now, the increase in the number of rows due to this design is not a problem. Using this I can store data of all male, female or child in the same table. But the problem with this approach is:
I will lose the Datatype of certain important fields. I can not query and get the list of persons whose income is more than 1000.
For storing data or all fields in single Value type, I need to make it varchar. But some fields store large data which requires TEXT as the type.
Considering the above problem, I thought that instead of creating only one value field, I will create multiple value fields like value_int, value_varchar, value_date or value_text.
DB structure
For this problem, I will be using MySQL and cannot change the DB due to certain restrictions. So I am looking for a design with MySQL only.
Going by key-value approach is a good idea or not? Or any other possible design which can be used?
In very general terms, if you know the entities and attributes of your problem domain, and the data is relational, I'd use a relational schema (your "possible design 1"). If you actually encounter problems with maximum row width, your problem domain might contain logical subgroupings of attributes, so you can split them into separate table.
For instance:
Person (id, name, ...)
Person_demographics (person_id, age, location, ...)
Person_finance (person_id, income, wealth...)
If you don't know the entities and attributes in advance, I recommend using MySQL's JSON support. or XML support. This gives you access to much better query options than EAV.
The problem with EAV-like solutions in your scenario is that any non-trivial queries end up being incredibly complicated - "find all responses where salary is between x and y, and the age is z, in locations (a, b, c)" turns into a horrible mess of SQL, but with XPath this is pretty straightforward.

How can I pull an ID from a varchar field and JOIN another table?

I have a field called 'click_target' that stores a string of data similar to this:
http://domain.com/deals/244?utm_source=sendgrid.com&utm_medium=email&utm_campaign=website
Using a MySQL query, is it possible to pull the ID (244) from the string and use it to join another table?
You can certainly play games with expressions to pull the ID out of this string but I have a bigger worry - you're burning a dependency on the URL format into a query in the database. That's not really a good idea becuase when (I don't say IF) the URL's change your queries will suddenly fail silently - no errors, just empty (if you're lucky) or nonsensical results.
It's an ugly hack, but I believe this line will extract your ID for you in the above url.
REVERSE(LEFT(LOCATE('/', REVERSE(LEFT(click_target, LOCATE('?', click_target)-1)))-1))
Basically, I am getting the text between the first '?' and the last '/'. From there you can join on whatever table you want with that value, though I recommend aliasing it or storing it in a variable so that it is not recalculated frequently.
If you need the id, fix your database to store it porperly in a separate field.

mysql: most efficient method to store parameters with unknown type (string/int) to the db

I have a messaging system that contains default templates. for example:
you won X coins
friend X wants to share the url Y with you
so the number of parameters varies in each message/template type.
I thought of 4 types of solutions to resolve the issue:
creating a parameters table and represent each parameter type as a string.
the problem here that user_ids will be represented as strings so probably joins will be slower. e
creating a parameters table that each row contains the following a boolean that tells if the parameter is an int or a string, and 2 other columns one type text and the other type INT. so here we're kind of wasting space because whenever we use an int parameter the row contains an unused string cell.
not to create a parameters table at all, each notification contains a parameters string that contains each needed parameter with a seperator ;. this one may be the slowest solution.
creating two different tables for each time of parameters: notification_param_int and notification_param_string and a table that contains each parameter in the notification to the relevant table. this solution may be slower then solution 2 because i need to check from which table to fetch the information first.
are there any other options I did not think about ?
if I don't care about space, only about speed, which method should I take ?
I'm not a MySQL expert so the conclusion of each method may be wrong.
Any information would be greatly appreciated.
thanks you!
Often, when having a open-ended property table as you describe, you'll discover that some of the properties are more important (either they need to always be there, or they need to be fast). In that case, promote those to fields in the main record.
I could imagine UID being that. It would be a problem later if you needed to have a list of UID (friends), but then you could also promote friends to its own table.
In your case, I'd just opt for #1 or #2 and think about promoting important properties if the need arises.

Generating a unique MySQL field based on the contents of other fields

In creating unique custom reference codes (i.e. JOB1293XYZ) for a while I have been generating custom reference/hashes in PHP then checking my database to see if it already exists and if so generating another.
I'm curious if in MySQL it is possible to to generate the contents of a field based on the other fields in that row, i would be a handy shortcut. For Example...
Table: Employees
employeeId
firstName
lastName
jobTitle
DOB
employeeCode
So for employeeCode can I perhaps use a MySQL Custom Function (which I know very little about) to generate the contents of the field. perhaps by taking the first letter of the firstname, first letter of the second name, the str length of the job title and the last two digits of the DOB? This is purely an example.
If this is possible and anyone can point me to any reference material that would be great, have been wading through the heavy MySQL documentation and will continue to do so for the time being.
Thanks in advance!
You could concatenate all of the fields together and do an MD5 on the resulting string.
UPDATE Employees SET md5str=MD5(CONCAT(field1, field2, field3))...
I wouldn't recommend this approach because then the question of what to do if you had a hash collision would be very difficult if not impossible to answer.
The above idea is not mine: I spotted this in the maatkit code.