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

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.

Related

In MySQL WHERE clause, how can I check for each item in a comma separated list against another comma separated list that may be ordered differently

I'm trying to write a query to look-up rows which contain one or more of comma-separated values. Please see scenario below:
Table: Events, target row to lookup is called "courses"
The data in the courses column is a comma separated string of course codes.
ABC123,XYZ345,ABC987
ABC123
ABC123,ABC987
XYZ345,ABC123
Now what I want to do is to do a
Select * from events where courses in ("ABC123","XYZ345");
However this returns no results.
What I want is that the where lookup to get me all rows that CONTAINS ABC123 OR XYZ345.
Could someone please help me do this?
You could use like, the % are wildcards.
select *
from events
where courses like "%ABC123%" or courses like "%XYZ345%"
There are other approaches: https://dev.mysql.com/doc/refman/8.0/en/pattern-matching.html
It might also be worth normalising the data so that each value is stored in its own row in another table rather than in a comma separated string, as using like will start to hurt performance as the table grows.
#user3783243 mentions loose matching which is a good point and just one reason why storing data like this isn't the best approach.
One way around it would be to tweak the query above to something like:
select *
from events
where courses like "%ABC123,%" or courses like "%XYZ345,%"
but this poses another problem, are the comma separated values always split by a single comma (ABC123,XYZ345) or is there any whitespace (ABC123, XYZ345).
Another problem pointed out by #GarethD is that the previous approaches won't match the last value of the comma separated string (unless it does have a trailing comma). One way I can think of is to do something like this, but it starts making the query a bit clunky, and also assumes all values are 6 characters in length, at this point, it might be worth using a regular expression.
select *
from events
where courses like "%ABC123,%" or courses like "%XYZ345,%"
or right(courses, 6) = 'ABC123' or right(courses, 6) = 'XYZ345'
If all values are indeed six characters then it might be worth trying other mysql functions such as locate, substring and regexp to try and simplify the query.
Just use FIND_IN_SET()
SELECT columns FROM events WHERE FIND_IN_SET("ABC123", courses) OR FIND_IN_SET("XYZ345", courses)
Better of course would be a normalized table, since you can't use indexes with the current design.

MySQL Sounds like to ignore 'The,a' etc

I have a table which includes names and each have a unique itemcode field, however I also have another table which we use as the root table for everything, this extra table is an extra I've recently added.
Because the names in my root table differ from the names in this new table, I need a bridge table, which I've created using a query which performs a INSERT..SELECT where the name in one table is equal to another. This is great, however it's limited my results because some names include The or A at the beginning so I'm missing them. So now I've changed my a = b query to a SOUNDS LIKE however that's only included names with differences at the end.
What I'm looking for is a way of ignoring a certain set of words such as:
The
A
Be
And
Etc and use the rest of the name? I can't do a 'LIKE %%' because that would capture too much.
You can remove the words The, A, Be etc by using the like statement. Ensure you have spaces on either side of the search terms so that it matches whole words, and not partial words.
SELECT * FROM namestable where names Like '% The %'

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.

How to find a list of rows that contain any of the given INTs in a column that contains INTs as comma separated values

I have a case where we are maintaining a table containing resources. This table has a varchar column that contains role ids as comma separated values (I know normalizing SHOULD have been the way to go, but can't change a long running working system). E.g. role_ids column contains '1,4,6,9,10' and another row contains '5,10,15'.
Then, for a user in system, I have the associated role ids as a list, e.g. 4,15. Now I need to find 'any in many', i.e. any resource that may have any of the role ids present in resource.role_ids column.
This question is something similar to this one, but the solution expected is not expected in Grails.
I'm looking for a MySQL solution - either a query or a stored procedure. Though finding a set of resources could have been achieved using 'FIND_IN_SET()', but don't want to perform multiple calls to DB with each of user's role_id list.
Use a function like this one, to turn your lists into individual records, then join everything up normally.

Associating extra data with a MySQL column

I have a typical table, e.g.
id(int) name(varchar) address(varchar) date(datetime)
I also have a table that references validation functions for each one, e.g.
id(int) function(varchar) fail_message(varchar)
1 email Please enter a valid email address
2 required This field can not be left blank
I'd like to be able to associate each column from the first table with one or more of these validators.
The only way I can think of doing this is to stuff the ids into the column names e.g. (column name: email;1;2) and keep track of it through PHP, but that seems very messy.
Is there a good way to do this with relational databases? Would a NoSQL implementation suit this problem better?
Similar to what Dan said, a relatively easy way to implement an association in sql would be to do the following:
id(int) function_id(int) col_name(varchar)
1 1 address
2 1 second_address
3 2 address
4 2 name
And then when you want to do the failure check, use the above table to link the error message to the column name (e.g. 'select function_id from above_table where col_name="address"') and then query the failure table. These tables could subsequently be combined using a view with a join so that a single query would suffice.
Hope this helps.
put this in another table that describes the columns for tables oddly this is very much like extending the table that lists table columns with additional columns
let's say if you extend your example with say localized strings that would mean that the fail_message would become a fail_message_id and the table fail_message would have the columns (id, language, message)