How to implement MySQL SET concept with over 64 members? - mysql

What is the best way to replicate the behaviour of a MySQL SET col type, with over 64 members?
I need to do what I would naturally do with a MySQL SET with around 85 different options. (The limit is 64.) What would be the best way to implement this?
I've looked at this question, which suggests a JOIN, but my members are only 6-char strings, is the most efficient way really to create an entire new, 1-column table of these members (I'll call it table 2), and then a third table of 2 cols linking an id from table 1 (where I would have created my SET column) and table 2?

Normalise into a second table that uses an ENUM:
From a single-table design like this:
ID, ..., Set_Col
to these:
Table1: ID, ...
Table2: Table1_ID, Enum_Col
You can then have a zero-or-more relationship from your Table1 PK (ID) to values in your "set", which is now not a set but a normalised ENUM value. You get the space benefits of a SET or ENUM, the multiplicity of a SET, but you overcome the 64 member limit of SET.

Since you already have those 6-char strings, there will be cases in the future when you will have to put them in a result set, so I would put them into a separate table and use the "JOIN + connection table" approach.
If there were no strings given for the elements of set, then I would implement an array of booleans in SQL. There are multiple solutions to do this, check out this SO question.

Related

How to search in parts of entries within a mysql database?

I'm working with a database that contains some "special" columns:
There are "cells" of a table containing a single Name of e.g. a painter like "Turner, William"; some other contain an ID like "ID123" connected with a table of persons.
But some cells contain two or more entries, like: "ID123 ; Turner, William" - they are always separated by ";"
My question is:
Normaly I can use something like "SELECT - FROM - LEFT JOIN" for simple selections with one entry. Is there any possibility for working with more than one entry?
Something like
SELECT artwork.nameid, artwork.artist,
person.fullname
FROM artworks
LEFT JOIN person ON person.id = [Part of String artwork.artist]
One of the important principles of a relational database is that each column contains a single value, not a composite value like you describe. And the values in a given column have the same type, not variable types.
So you should solve your problem by having two columns, one for an ID and the other for a Name. Don't try to store them together in the same column with a semicolon separator.
CREATE TABLE artworks (
...
PersonID VARCHAR(5), -- example: ID123
Name VARCHAR(100), -- example: Turner, William
...
);
That said, you might be able to do what you describe using some MySQL string functions.
For example you can use LOCATE(';' artwork.artst) to detect if there's a semicolon present in a given string. You can use SUBSTRING_INDEX(artwork.artist, ';', 2) to extract the second "field" from a semicolon-separate field.
The expression needed to solve your problem is bound to become terribly complex if you need to handle a variety of cases, like what if a column has the ID first instead of second? What if there are three or more fields separated by semicolons?
Please take the recommendation that it will be far easier to restructure your table so you always have one value in each column.

How do I store nested locations?

In my project I have locations of the product, which may look like this:
- Location 1
-- SubLocation 1
-- SubLocation 2
- Location 2
-- SubLocation 3
-- SubLocation 4
Imagine a zones with subzones in the facilty.
I need to store that in DB and then retrive sometime later, like this: SubLocation 1 at Location 1.
My first guess is to have two tables with one to many ralationship, but that won't scale, it later I'll need to have something like this:
- Location 2
-- SubLocation 3
-- SubLocation 4
---- SubLocation 5
---- SubLocation 6
So my question is what's the best way to store such structure in relational database?
You can define parent_id reference FK to another record with id (roots have null parent_id).
To define hierarhy and retrieve all subtree in one query you can define an additional field path (VARCHAR). The field should have full path of ids separated with '_'
In your case SubLocation 5 has the path="2_4_5"
To retrieve all the children of SubLocation 4 you can use
select *
from myTable
where path like '2_4%';
There is level depth restriction (size of the path in fact) but for most cases it should work.
Dealing with hierarchical data is difficult in MySQL. So, although you might store the data in recursive tables, querying the data is (in general) not easy.
If you have a fixed set of hierarchies, such as three (I'm thinking "city", "state", "country"), then you can have a separate table for each entity. This works and is particularly useful in situations where the elements can change over time.
Alternatively, you can have a single table that flattens out the dimensions. So, "city", "state", and "country" are all stored on a single row. This flattens out the data, so it is no longer normalized. Updates become tedious. But if the data is rarely updated, then that is not an issue. This form is a "dimensional" form and used for OLAP solutions.
There are hybrid approaches, where you store each element in a single table, in a recursive form. However, the table also contains the "full path" to the top. For instance in your last example:
/location2/sublocation3
/location2/sublocation4
/location2/sublocation4/sublocation5
/location2/sublocation4/sublocation6
This facilitates querying the data. But it comes at the cost of maintenance. Changing a something such as sublocation4 requires changing many rows. Think triggers.
The easiest solution is to use different tables for different entities, if you can.
You can store it in one tabel and retreive sublocations using self join.

Problems with division using a constant in another table

I am displaying recorded values of pressure.
I always store pressure as PSI in my database, knowing that I can convert it to BAR by dividing by 14.5
So, I have a table called configuration and one called measurements and I want so say
SELECT pressure DIV my_db.configuration.conversion_factor AS pressure FROM my_db.measurements WHERE ... and my front-end s/w will set my_db.configuration.conversion_factor to either 1 or 14.5 as appropriate.
But I am getting an error unknown column 'my_db.configuration.conversion_factor' in 'filed list'.
Since I am cut/pasting, I doubt that it is a spelling error - so what is wrong with my query?
[Update]
#JimGarrison set me on the correct path. What I needed was
SELECT pressure DIV (SELECT conversion_factor FROM my_db.configuration WHERE 1) AS pressure FROM my_db.measurements WHERE ...
Note: I add that WHERE 1 for anyone reading this question in future; I only have a single row in the configuration table, so I don't need a WHERE - but you might ..
Thanks, Jim
You can't refer to a field in a second table like that. my_db.configuration is a table with rows and columns. How does SQL know which row you want to use?
What I think you're looking for is
select pressure div (select conversion_factor from my_db.configuration where <???>=<???>) ...
where <???> is where you'd put the key column name and value for the entry you want to use from the conversion_factor table.
You have to list all the tables you want to reference in a FROM clause — in this case, the FROM clause.
SELECT pressure DIV my_db.configuration.conversion_factor AS pressure
FROM my_db.measurements
CROSS JOIN my_db.configuration
WHERE ...
The CROSS JOIN is used assuming there's just one row in your configuration table. It doesn't require a join condition.
Or you can use a sub-select as Jim Garrison suggests in his answer. It's probably cleaner. But note that he referenced the configuration table in a FROM clause.

How to get the fifth field of the second register of a table?

I have an automatically generated SQL database.
I don't know the name of the fields, and I don't know the value of the fields; I just know which number of register I need to get and with number of field of that register.
For example, if I need to obtain the fifth field of the second register of the table "Table1" of the database, which SQL query should I do?
Rows in a table in a database are formally unordered, though they are, of course, stored in some order. There's no way in SQL to refer to columns in a table by position; you must know the name of the column.
Since you know the table name, you can interrogate the system catalog to learn the columns in the table, and therefore the second column name in the table (assuming it isn't a single-column table).
However, if you don't know the schema of the tables, you can't do anything meaningful in the way of querying the data. You have to know what the columns mean to know what the query is going to do.
Clearly you can run some query on the table (once you know the column name you're after) and then collect two rows of data; the second row is the one you're after.
...
There's a half-cheat that you can use which will work if your database access language returns you rows with the values for each row in an array - as in Perl with DBI, or PHP, or ...
SELECT * FROM Table1;
This will collect all the data (including column 5, assuming there are that many columns), and your fetch operation may return the values represented by * into an array, and you can then look at the value in the fifth element of the array for the second row to see the data. In many SQL DBMS (I don't know about MySQL specifically), you can even use an obsolescent notation to order by the fifth column:
SELECT * FROM Table1 ORDER BY 5;
The 5 here refers to the fifth column in the result set which, given that this is selecting all columns from a single table, means the fifth column of the table.
However, running blind like that is a ridiculous proposition for the long term. You must understand the schema and its interpretation to be able to use a database sensibly.
You could try:
SELECT *
FROM information_schema.COLUMNS
WHERE information_schema.COLUMNS.TABLE_SCHEMA = '<DATABASENAME>'
AND information_schema.COLUMNS.TABLE_NAME = '<TABLENAME>'
ORDER BY information_schema.COLUMNS.ORDINAL_POSITION ASC
This would give you the table metadata, including column names and types.
can you not do it thru PHP (or your choice):
$i=1;
while($row = mysql_fetch_row($res))
{
if ($i == 2)
{
echo $row[4];
}
$i++;
}
Presumably you have access to the database?
Can't you do:
SHOW CREATE TABLE Table1;
The order of the columns returned should give you the names of the fields which you can then use in a query.

MYSQL: How to refer to the 1st column

SELECT first_name FROM user WHERE FIRST_COLUMN = '10'
What I need to know is how to reference "FIRST_COLUMN" in MYSQL syntax. The first column can be any name and so I need to make it flexible as long it should get the 1st column of any table. thanks
The short answer is : you can't. (in a portable way, there are 'tricks' to look up the name of the first column and similar workarounds)
Many projects use as convention to name the first column ID and use that as the primary key.
By the query it looks like you are uing it as a primary key.
I recommend reading an introduction to relational databases as this is a rather strange request in the context of a relational database.
The relational model does not care one tiny little bit what order columns are in within a table, nor (without an ordering clause) what order rows are returned.
Your requirement makes little sense. What if the first column were a varchar or a date?
The whole point of having named columns is that you reference them by name.
Now DBMS' often contain metadata in system tables, like DB2's sysibm.systables and sysibm.syscolumns, but you need to extract not just the names but all the other metadata as well (column type, size, nullable, and so on) in order to use them properly. We'd probably understand better what you were after if you told us the reason behind doing this.
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_NAME = 'tablename'
AND ORDINAL_POSITION =1