So the situation is that I have some code that uses a database table and I think I can replace that table with a view from another table.
Potentially I would rename/remove the existing table and then somehow create a view that replicates the table so that the php code thinks it is working with the table.
Perhaps what I should do is create the view and then simply find and replace all instances of the table name in the code?
What is the best way to mimic or ghost a table?
Rename the table with
RENAME TABLE <table_name> TO <new_table_name>;
Then create the view with the same name as the original table_name. Your PHP code will continue to work fine without further ado when it's reading from the table. If your code also has to update, delete or insert into that view, there are certain restrictions.
There must be a one-to-one relationship between the rows in the view
and the rows in the underlying table. There are also certain other
constructs that make a view nonupdatable. To be more specific, a view
is not updatable if it contains any of the following:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
UNION or UNION ALL
Subquery in the select list
Certain joins (see additional join discussion later in this section)
Reference to nonupdatable view in the FROM clause
Subquery in the WHERE clause that refers to a table in the FROM clause
Refers only to literal values (in this case, there is no underlying table to update)
ALGORITHM = TEMPTABLE (use of a temporary table always makes a view nonupdatable)
Multiple references to any column of a base table
Read more about it in the manual.
Related
I am creating a view to show the user his/her data, but I also want the user to be able to make changes in some of the fields in those views. Are the changes made in a view reflected in the base table as well?
Also, would I be able to update a view that is made up of more than one base table?
As documented under Updatable and Insertable Views:
Some views are updatable. That is, you can use them in statements such as UPDATE, DELETE, or INSERT to update the contents of the underlying table. For a view to be updatable, there must be a one-to-one relationship between the rows in the view and the rows in the underlying table. There are also certain other constructs that make a view nonupdatable. To be more specific, a view is not updatable if it contains any of the following:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
UNION or UNION ALL
Subquery in the select list
Certain joins (see additional join discussion later in this section)
Nonupdatable view in the FROM clause
A subquery in the WHERE clause that refers to a table in the FROM clause
Refers only to literal values (in this case, there is no underlying table to update)
Uses ALGORITHM = TEMPTABLE (use of a temporary table always makes a view nonupdatable)
Multiple references to any column of a base table.
[ deletia ]
It is sometimes possible for a multiple-table view to be updatable, assuming that it can be processed with the MERGE algorithm. For this to work, the view must use an inner join (not an outer join or a UNION). Also, only a single table in the view definition can be updated, so the SET clause must name only columns from one of the tables in the view. Views that use UNION ALL are not permitted even though they might be theoretically updatable, because the implementation uses temporary tables to process them.
Can I create a generated column in table A which sums up a column in table B with a tableA_id of the row in table A?
Suppose I have a table of of families, and a table of children. I want a sum of the ages of the children for each family.
ALTER TABLE people.families
ADD COLUMN sumofages DECIMAL(10,2) GENERATED ALWAYS AS
(SELECT SUM(age) FROM people.children WHERE family_id = people.families.id) STORED;
ERROR 3102: Expression of generated column 'sumofages' contains a disallowed function.
I can't save it as type VIRTUAL either. What am I doing wrong here?
ALTER TABLE people.families
ADD COLUMN sumofages DECIMAL(10,2) GENERATED ALWAYS AS
(SELECT SUM(age) FROM people.children WHERE family_id = people.families.id) VIRTUAL;
ERROR 3102: Expression of generated column 'sumofages' contains a disallowed function.
I don't know which function is disallowed. SUM doesn't seem to be it. Maybe SELECT?
https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
Generated column expressions must adhere to the following rules. An
error occurs if an expression contains disallowed constructs.
Subqueries, parameters, variables, stored functions, and user-defined
functions are not permitted.
It's reasonable that the expression for a generated column can reference only columns within the same row. The generated column cannot use subqueries, or reference other tables, or functions with non-deterministic output.
Suppose generated columns did support cross-table references. Particularly consider the case of STORED generated columns.
If you update a table, MySQL would also have to update any references in generated columns elsewhere in the database, if they reference the row you updated. It would be complex and expensive for MySQL to track down all those references.
Then consider add indirect references through stored functions.
Then consider that your update is to an InnoDB table in a transaction, but the generated column may be in a non-transaction (MyISAM, MEMORY, ARCHIVE, etc.) table. Should your update be reflected in those generated columns when you make it? What if you roll back? Should your update be reflected at the time you commit? Then how should MySQL "queue up" changes to apply to those tables? What if multiple transactions commit updates that affect the generated column reference? Which one should win, the one that applied the change last or the one that committed last?
For these reasons, it's not practical or efficient to allow generated columns to reference anything other than the columns of the same row in the same table.
The idea of a computed column is to derive data from the other columns in the record, e.g. combine the country code with the zip code, so you'd store DE and 12345 and you'd get DE-12345 which you could use in an address.
What you are trying to do, however, is something completely different. You are accessing data from another table. But that table's data may change, so when accessing the same record you might suddenly get a completely different result. Computed columns should contain deterministic values, so they don't change as long as your record's data doesn't change. I don't know about MySQL in this regard, but it probably forbids non-deterministic data, such as your subquery.
What you are actually looking for is a view. A view can combine selects from different tables, just as you want it to happen. So use
create view familydata as
(
select f.*, sum(c.age) as sumofages
from families f
join children c on c.family_id = f.id
group by f.id
);
or
create view familydata as
(
select f.*,
(
select sum(age)
from children c
where c.family_id = f.id
) as sumofages
from families f
);
I hope I got the syntax right.
I've got: a view which I create by joining two tables
CREATE VIEW my_view AS
SELECT t1.id as id, t2.field, [another fields]
FROM table1 t1 JOIN table2 t2
JOIN t1.id = t2.table1_id
Moreover, table1 and table2 are referenced from many other tables.
I want: DELETE FROM my_view WHERE id = #id;
Problem: Can not delete from join view 'my_view' message
Questions:
Can I delete row from my_view without deleting related rows from table1 and table2?
Can I delete row from my_view with deleting related row from table1 but not deleting related row from table12?
1) Can I delete row from my_view without deleting related rows from table1 and table2?
No, a view doesn't remember anything by itself, it can be seen as a saved query against table1 and table2. If you want to delete a value from the view, it must also be deleted (or otherwise marked as not showing up in the view query) in the underlying tables.
2) Can I delete row from my_view with deleting related row from table1 but not deleting related row from table12?
You cannot do that through the view (DELETE against multi-table updatable views is not supported in MySQL), but you can of course delete the data directly in table1 and the view will reflect the changes immediately.
The value that a view name means in an expression is calculated according to the view definition expression. (Unless it is a "materialized view", which is not a "view".) So updating it is taken to mean doing something to the tables used to define it.
Some views lose information: different inputs could give the same output. So if you try to give a new value that you want it to evaluate to with the idea that the tables defining it be set by the DBMS to appropriate new values then it might be ambiguous what new table values would give the new view value.
Some views are updatable in that sense, especially taking keys (and unique subrows) and foreign keys into account, not to mention other constraints. And a DBMS can easily figure out some of those, and a really smart DBMS more, but in mostly it can't be figured out and/or it's ambiguous. But you can set the tables individually.
Also, a DBMS can just say how it's going to update the inputs underlying certain views in terms of the old input values and the view expression and the update command argument. Maybe it picks certain values for the tables forming the view even when more than one possibility is consistent with the new value. Maybe it just sets those tables to some new values based on the old values and the update arguments and when you re-calculate the view from them it doesn't even get the value it would have if you had done that update to a base table. If that kind of arbitrary disambiguating choice gives you the update you need, you can request it; otherwise update the tables mentioned in the view separately.
The SQL standard actually requires that the DBMS update some views, and (obscurely) defines various categories of updatable view. Various effects of view update described by the standard are as described above. Also there are views that a DBMS can easily see to be updatable that aren't required to be by SQL.
Vendors will make their own choices. Eg mysql. (Which you, too, could have googled.) Read it. In particular, "there must be a one-to-one relationship between the rows in the view and the rows in the underlying table". So Q1: No, you can't update the view only; the view name will give the value from re-evaluating its expression. And Q2: No you can't update a multi-table view.
However, you can always update a view by updating the underlying tables.
I am creating a view to show the user his/her data, but I also want the user to be able to make changes in some of the fields in those views. Are the changes made in a view reflected in the base table as well?
Also, would I be able to update a view that is made up of more than one base table?
As documented under Updatable and Insertable Views:
Some views are updatable. That is, you can use them in statements such as UPDATE, DELETE, or INSERT to update the contents of the underlying table. For a view to be updatable, there must be a one-to-one relationship between the rows in the view and the rows in the underlying table. There are also certain other constructs that make a view nonupdatable. To be more specific, a view is not updatable if it contains any of the following:
Aggregate functions (SUM(), MIN(), MAX(), COUNT(), and so forth)
DISTINCT
GROUP BY
HAVING
UNION or UNION ALL
Subquery in the select list
Certain joins (see additional join discussion later in this section)
Nonupdatable view in the FROM clause
A subquery in the WHERE clause that refers to a table in the FROM clause
Refers only to literal values (in this case, there is no underlying table to update)
Uses ALGORITHM = TEMPTABLE (use of a temporary table always makes a view nonupdatable)
Multiple references to any column of a base table.
[ deletia ]
It is sometimes possible for a multiple-table view to be updatable, assuming that it can be processed with the MERGE algorithm. For this to work, the view must use an inner join (not an outer join or a UNION). Also, only a single table in the view definition can be updated, so the SET clause must name only columns from one of the tables in the view. Views that use UNION ALL are not permitted even though they might be theoretically updatable, because the implementation uses temporary tables to process them.
http://www.mysqltutorial.org/create-sql-updatable-views.aspx
This article above states the following:
SELECT statement must not reference
to more than one table. It means it
must not contain more than one table
in FROM clause, other tables in JOIN
statement, or UNION with other tables.
Is this true and why?
How would you query two related tables like it was one (through a view), without using joins in every query string?
That page is about updatable views, and the condition of being able to update the underlying table via the view means you have to place some more restrictions on the contents of the view, in order for mysql to be able to map your update back to the underlying table.
If you just want to read from a view without the need to update the underlying table using it, you can select from more than one table using joins, UNIONs, etc, in a view definition.
It is only true for updateable views. If you couldn't link up more than 1 table in a view, then the whole point of a view would be meaningless :)
When you create a view you are already combining the tables. What they are trying to say is that you should not have a SELECT statement, in general, that JOINs a View and a Table. Although you CAN do this, it is not the best practice. The point of a View is to create a Table that has Fields from multiple Tables that you constantly call on a regular basis. A View is more efficient than JOINing Tables on every SELECT statement for those multiple tables.