Interpreting mysql errors in php - php

I have a use case where I have to execute a set of alter table queries on my DB and all the queries are to do with adding foreign key constraints.
Let's say there are 2 tables A and B, A.id references B.id, but some A.id are not present in B.id which I can just delete as I'm not interested in such records.
But I can't just delete them since there are few tables that are referencing table A's columns.
This dependency grows like a tree. Now I want to resolve this dependency programmatically.
Is there any existing library I can use for this (preferably php)?
I should be able to interpret the SQL errors and construct the appropriate query based on the errors and execute them.
We can safely assume that all these errors are foreign key constraints which are conflicting.

Related

Why to use Foreign Key Constraints?

I am working on a PHP application which Db design was created by another guy who added FK constraints(On Cascade delete etc) between tables. So far what I am used to do is to put a FK in another table. For instance we have two tables:
Users
ID
Name
CountryID
Countries
ID
Name
At application Level I will create two Separate INSERTs calls. If FK is present, then what change do I need to make at my application level?
You need to make sure that the row you reference with the FK exists before you create the row in the other table.
… but you are probably doing this already as that is the logical order to create the rows.
Foreign keys enforce referential integrity.
These constraints guarantee that a row in a table order_details with a field order_id referencing an orders table will never have an order_id value that doesn't exist in the orders table.
Foreign keys aren't required to have a working relational database (in fact MySQL's default storage engine doesn't support FKs), but they are definitely essential to avoid broken relationships and orphan rows (ie. referential integrity). The ability to enforce referential integrity at the database level is required for the C in ACID to stand.

Invalid Doctrine Entity being created

I'm working on a web project that contains a mixture of Doctrine and traditional inline SQL for database access. We're migrating from the latter to the former over time.
One of the database tables (Table A) has an informal foreign key (i.e. there are no actual constraints in the SQL table definition) column. The value in this column is nullable, but sometimes the value in this column refers to a another table's (Table B) primary key that has since been deleted.
Table A's relationship with Table B is formalised in Table A's entity definition in Doctrine. When I create an instance of an entity from an existing row in Table A and the informal foreign key column has a value that is no longer in Table B, then it seems an invalid Table B entity is created. I.e. the object is set, and I can query it's id through the TableB->getId() method we have authored, but any other TableB->getProperty() fails and throws an error.
Since I'm already working with historic data, I need a run-time solution to this. I need to identify via a check if the Table B entity is valid.
I could put it in a try-catch loop, but this is not a common pattern in our code base and does not seem very elegant.
Is there a canonical method for checking the validatity of a Doctrine entity to solve this problem?
Thank you
As I see it, there are 2 things you should do.
First fix your data corruption, this is a must. If A points to a non-existing B, then A should not be pointing at all. SELECT a.id FROM table_a a LEFT JOIN table_b b ON b.id = a.table_b_id WHERE b.id IS NULL. This query will select all FK that are not existing anymore, you can simply update the a.table_b_id to NULL with that list.
Second, you should (not in your getter) take care of the relation issue in your code. I'm not sure if Doctrine throws an EntityNotFoundException or only does this with find($pk), but I'm sure you can check if the return of your getter is null or catch that exception.

Keep updated mysql data between multiple mysql tables

I have two tables in mysql. When I insert/delete values in the first table I want that the values get duplicated in table 2 to keep them "aligned".
table1:
id - username
1 - test_user
table2:
Same id as table1 and username as table1 (on insert/delete)
I want to keep the data between the tables aligned without doing multiple queries. I've read about triggers not sure if it's the correct road, i am a beninner.
I said two tables but i will need to do this in multiple tables.
You can use Mysql triggers. This way you can auto insert/update/delete datas from second table.
MySql Using Triggers
When you INSERT new records, given that you don't want to do two inserts for some reason, using a trigger to insert into the second table will work. For UPDATE and DELETE you might want to look at the CASCADE option with foreign keys. If all you are doing is keeping the data consistent between tables, that's exactly what cascade is for.
When you create table2 you just add a foreign key like this:
FOREIGN KEY (id, username)
REFERENCES table1(id, username) ON UPDATE CASCADE ON DELETE CASCADE
Then whenever you alter table1 the changes will automatically get pushed through to table2.
Couple prerequisites for this to work:
You have to use a storage engine that supports foreign keys, something like InnoDB and not MyISAM
You need to have an index on (id,username) in table1; the foriegn key needs to match a key in the parent table
You should read the doc page for foreign keys. There are a couple other ways you can tweak them, and you should figure out what works best for your purposes.
You can certainly put triggers on your table1 to make parallel changes to your other tables as your application changes table1.
See here for the documentation: http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
But, you should think over your design. It will take multiple queries to do your inserts and updates; they'll just be done "behind your back" on the server. They'll still take time. Triggers can really slow things down.
Also, triggers are a little bit fragile. If you add a column to a table, you'll have to rework your triggers. Triggers are generally a pain in the neck to keep in a source-control system and a huge pain in the neck to test, so using them will make your application more troublesome to maintain.
Could you think of another approach to handling this need for duplication? Could you, for example, use a view or a join to present the data you need to your application program without actually duplicating tables and the rows in them? If you figure out how to do that you'll be much happier in the long run.
CREATE VIEW table2 AS
SELECT *
FROM table1;
will produce a "fake" table2 with the contents of table1.
Or if you're hoping to view only the test users in a second table, a view can do that for you too, for example:
CREATE VIEW table3 AS
SELECT *
FROM table1
WHERE usertype = 'test_user' ;
If you're using duplicate tables for "backup," that's a bad way to make sure your information is safe. Instead, you need to back up your MySQL server instance.
Formal relational database design principles teach us to duplicating data, but instead use view and joins to structure the data the way applications need to see it.

PHP MySQL query against changing database

I am developing a PHP web based data entry tool with MySQL as the database. However the database will undoubtedly change whilst the data entry is going on (there is a lot of it to be done so we have started it so that it runs in parallel to the other development).
I have constructed the SQL queries so that the php can automatically:
Determine what tables are in the database
List tables with a certain prefix so that only ones that data entry should use are listed
However, what I cant figure out (despite checking php, sql and mysql manuals and tutorials) is how to automatically pull tables that are connected by foreign key, so that data entry have a list of items to choose from for the given table. So in short, how do I - using php - determine:
Any foreign keys for the given table
The table name that the foreign key points to
WITHOUT hard-coding any table names into the SQL queries?
A quick way to list your Foreign Key references using the KEY_COLUMN_USAGE view:
SELECT CONCAT( table_name, '.',
column_name, ' -> ',
referenced_table_name, '.',
referenced_column_name ) AS list_of_fks
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_SCHEMA = (your schema name here)
AND REFERENCED_TABLE_NAME is not null
ORDER BY TABLE_NAME, COLUMN_NAME;
This query does assume that the constraints and all referenced and referencing tables are in the same schema.
For InnoDB tables, using the Comment field of SHOW TABLE STATUS is useful for extracting foreign key information for older versions of MySQL.
I am unaware of any other way than the above 2 methods.
Happy coding!

Linking multi-database information

What are your methods of linking data spread over multiple databases architectures (think MySQL vs PostgreSQL etc), into a single application?
Would you create giant hashtables/arrays to match content against one another? Are there other, more effective and less memory-consuming options for doing this?
If you were to use data both from a MySQL & PostgreSQL source, with no way of converting one DB to the other (application constraints, lack of time, lack of knowledge, ... ), how would you go about it?
SQL Relay or another sql proxy.
http://sqlrelay.sourceforge.net/
At least in the case of MySQL, you can use data from multiple databases in a single query anyway, provided the databases are hosted by the same MySQL Server instance. You can distinguish tables from different databases by qualifying the table with a schema name:
CREATE TABLE test.foo (id SERIAL PRIMARY KEY) TYPE=InnoDB;
CREATE DATABASE test2;
CREATE TABLE test2.bar (foo_id BIGINT UNSIGNED,
FOREIGN KEY (foo_id) REFERENCES test.foo(id)) TYPE=InnoDB;
SELECT * FROM test.foo f JOIN test2.bar b ON (f.id = b.foo_id);
In PostgreSQL, you can also qualify table references with a schema name. I'm not sure if you can create foreign key constraints across databases, though.
If you're looking to create constraints across RDBMSes - you can't.
I'm facing the same issue with running part of an application off PostgreSQL for where it will benefit, and the rest of MySQL where it's better.
I'm doing multiple inserts keyed off the same format of primary information (in my case a generic user ID), so I'm letting the application handle the logic of making sure to ask for the same ID from both DBs.
There's not really a clean way to do this outside of abstracting it to a class or utility function, though, that I've found.

Categories