How to find relationships among values in a database - mysql

This is a little difficult for me to explain but I will try my best to explain to you guys in short. Iam designing a search engine for a relational database. I want this to be independant of the structure of the database i.e it can run on any database provided. I want that when the user inserts a string such as two names 'abc xyz' ,it displays all the rows containing both the names 'abc xyz' in them and if there are no such rows then it should display rows with name 'abc' and rows with name 'xyz' and show the relationship between the two. For example 'abc' is friends with 'mno' which in turn is friends with 'jkf' which in turn is friends with 'xyz'. So i want to show this relationship as well.This is just an example of the thing i want my application to do. I want it to search all such relationships , if they exist and display them. I know this example is a bit vague compared to the complexity of the application but any ideas are appreciated.
Note:
I know about neo4j and orientdb Dbms which uses graph databases but i dont wanna use them. I believe a graphical approach for finding such relationships would be required. But I wanted to ask if such a task can be done using sql only. Iam using mysql as my database. please help me out woth any queries or stored procs which are suitable for my platform. from what ive learnt information_schema can come in handy but i dont know how to use it for this purpose. Also if there are any other languages which can do this job , I would like to hear about them as well.
From my perspective. the traversal of the database from point A to point B (point A nd B are words in the string given by the user) would also help me out. All opinions are fully welcomed.

I'm not sure if i got you right, but I hope this will help you anyway.
If you want to search a relation between two rows over several points it's basically a graph search problem, see also Wikipedia | Graph theory. To explain that a little...
You can visualize the relation between every row as a graph, for example the persons who know each other:
A--B
\ /
C
Now a more complex example:
A--B--D
\ / /
C--E--F
In this case A knows E for example via C but also A knows E via B and D
Also B knows F via D and E or via C and E
This works for all records stored in the same table as well as for records in any other table. To access for example all nodes with a direct relation to your search record in the same table use:
SELECT * FROM TABLE WHERE referenced_rec =
(SELECT rec FROM TABLE WHERE value = "abc")
AND value = "xyz"
To access all records stored in tables directly related to this table:
select * from (
select TABLE_NAME
from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where
REFERENCED_TABLE_NAME = 'your_current_table')
where your_current_table.value = "abc"
AND (select REFERENCED_COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME = 'your_current_table') = (select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME = 'your_current_table')
AND (select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME = 'your_current_table') = "xyz"
I'm pretty sure this won't work, but for now I don't have a chance to test. However getting these SQL's right is another topic and you can maybe take a look for this Stack Overflow Question
As soon as you're able to get all the records from this or any related table you can map this to graph as shown above.
You can't solve this using SQL alone as you don't know how many steps will be necessary to resolve it. You can use any shortest way algorithm for this for example a Wikipedia | Djikstra. I suppose you can find information about how to implement this with a short search.
I hope this could help you a little ;-)
Best Regards
Sverre

Related

How to find out which columns are similar in two sql tables based on their values?

I have two tables in MySQL with 100+ columns. I need to figure out the columns in both tables which have some of the same values. I need a way to find out which columns are matching in terms of type and values in them so that I can use them in joins and extract results from them. I can convert the tables in excel sheet and apply VB Script as well. Any kind of help is greatly appreciated.
There's no magical SQL query you can run to determine the logic behind how your database was designed. You can check the table schema to see if there are any foreign keys enabled, but that's about it.
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'my_database_name' AND TABLE_NAME ='my_table';
Based on how you describe the tables, the given design sounds... odd. I hope whoever designed it left you documentation. Your last resort is going to be just dumping the data and looking for patterns.

Structuring database for CakePHP - relationship based on join table

I am designing a database for use with CakePHP 3, but I am having trouble figuring out how to set up and define a particular relationship.
I have 'Contracts' which can have multiple 'Properties', but each Contract<->Property relationship can have multiple 'ContractEvents'. Normally I would join the 'contract_events' table to the 'contracts_properties' table but I can't seem to figure out how to get CakePHP to recognise this or whether this is the correct convention.
Here is a diagram trying to illustrate what I want:
Contracts <- Join Table -> Properties
|
v
ContractEvents
Apologies if this is unclear or a dupe, I wasn't really sure how to phrase it when searching. Please let me know if you need anymore information.
Thanks

MSQL alter table with JOIN

I am trying to update a table with a column from another table. I dont want to view the join, I want to alter the table.
However, this is faiing:
UPDATE
a_dataset
SET
a_dataset.lang_flag = b_dataset.language
FROM
a_dataset
INNER JOIN
b_dataset
ON
a_dataset.ID = b_dataset.ID
However, I keep getting a syntax error, and cannot locate what I am missing?
I am guessing that you mean to update your records when you say alter the table. If so, you can simply rewrite your update statement with join like this:
UPDATE a_dataset a
JOIN b_dataset b ON a.ID = b.ID
SET a.lang_flag = b.[LANGUAGE]
As Uueerdo and myself said: Starting table names with numbers is a bad[TM] idea. The same is for letters, which you now chose to use. a is no better than 1 in this regard. Also calling tables just "dataset" isn't really helpful either. What is the table storing? Users? Then call it users. Articles on a news web site? Then call it articles. And so on. Everything in a database is dataset, no need to tell that anyone.
I guess you're new to SQL, am I right? Because another issue is: Unless you're going to drop table b_dataset after this command, you're probably doing something you're not supposed to do in relational data bases. The whole idea is to store all data only once. If you can automagically copy the column from b to a, then you could also select join if from a and b when you need it instead of copying it.
For learning SQL (or anything else), Stack Overflow is probably a bad place (it's good for asking questions in the process, though), so I recommend that you go get someone who has some experience in SQL to teach you, or get some book / tutorial on SQL. From first glance, this seems to be a good on-line book: http://sql.learncodethehardway.org/ - but I didn't read it.

MySQL CONCAT '*' symbol toasts the database

I have a table used for lookups which stores the human-readable value in one column and a the same text stripped of special characters and spaces in another. e.g., the value "Children's Shows" would appear in the lookup column as "childrens-shows".
Unfortunately the corresponding main table isn't quite that simple - for historical reasons I didn't create myself and now would be difficult to undo, the lookup value is actually stored with surrounding asterisks, e.g. '*childrens-shows*'.
So, while trying to join the lookup table sans-asterisks with the main table that has asterisks, I figured CONCAT would help me add them on-the-fly, e.g.;
SELECT *
FROM main_table m
INNER JOIN lookup_table l
ON l.value = CONCAT('*',m.value,'*')
... and then the table was toast. Not sure if I created an infinite loop or really screwed the data, but it required an ISP backup to get the table responding again. I suspect it's because the '*' symbol is probably reserved, like a wildcard, and I've asked the database to do the equivalent of licking its own elbow. Either way, I'm hesitant to 'experiment' to find the answer given the spectacular way it managed to kill the database.
Thanks in advance to anyone who can (a) tell me what the above actually did to the database, and (b) how I should actually join the tables?
When using CONCAT, mysql won't use the index. Use EXPLAIN to check this, but a recent problem I had was that on a large table, the indexed column was there, but the key was not used. This should not bork the whole table however, just make it slow. Possibly it ran out of memory, started to swap and then crashed halfway, but you'd need to check the logs to find out.
However, the root cause is clearly bad table design and that's where the solution lies. Any answer you get that allows you to work around this can only be temporary at best.
Best solution is to move this data into a separate table. 'Childrens shows' sounds like a category and therefore repeated data in many rows. This should really be an id for a 'categories' table, which would prevent the DB from having to run CONCAT on every single row in the table, as you could do this:
SELECT *
FROM main_table m
INNER JOIN lookup_table l
ON l.value = m.value
/* and optionally */
INNER JOIN categories cat
ON l.value = cat.id
WHERE cat.name = 'whatever'
I know this is not something you may be able to do given the information you supplied in your question, but really the reason for not being able to make such a change to a badly normalised DB is more important than the code here. Without either the resources or political backing to do things the right way, you will end up with even more headaches like this, which will end up costing more in the long term. Time for a word with the boss perhaps :)

Mysql "magic" catch all column for select statement

Is there a way that I can do a select as such
select * from attributes where product_id = 500
would return
id name description
1 wheel round and black
2 horn makes loud noise
3 window solid object you can see through
and the query
select * from attributes where product_id = 234
would return the same results as would any query to this table.
Now obviously I could just remove the where clause and go about my day. But this involves editing code that I don't really want to modify so i'm trying to fix this at the database level.
So is there a "magical" way to ignore what is in the where clause and return whatever I want using a view or something ?
Even if it was possible, I doubt it would work. Both of those WHERE clauses expect one thing to be returned, therefore the code would probably just use the first row returned, not all of them.
It would also give the database a behaviour that would make future developers pull their hair out trying to understand.
Do it properly and fix the code.
or you could pass "product_id" instead of an integer, if there's no code checking for that...so the query would become:
select * from attributes where product_id = product_id;
this would give you every row in the table.
If you can't edit the query, maybe you can append to it? You could stick
OR 1=1
on the end.
You may be able to use result set metadata to get what you want, but a result set won't have descriptions of fields. The specific API to get result set metadata from a prepared query varies by programming language, and you haven't said what language you're using.
You can query the INFORMATION_SCHEMA for the products table.
SELECT ordinal_position, column_name, column_comment
FROM INFORMATION_SCHEMA.columns
WHERE table_name = 'products' AND schema_name = 'mydatabase';
You can restructure the database into an Entity-Attribute-Value design, but that's a much more ambitious change than fixing your code.
Or you can abandon SQL databases altogether, and use a semantic data store like RDF, which allows you to query metadata of an entity in the same way you query data.
As far out as this idea seems I'm always interested in crazy ways to do things.
I think the best solution I could come up with is to use a view that uses the products table to get all the products then the attributes table to get the attributes, so every possible product is accounted for and all will get the same result