CREATE OR REPLACE VIEW Vs Checking view existing or not? - mysql

I am using Maria DB 5.5 version and it does not allow clause ‘CREATE VIEW IF NOT EXISTS’ while view creation. As requirement, I need to check whether view existing or not while creation.
Here I have 2 approach for this problem …
Do SQL using INFORMATION_SCHEMA.TABLES and create the view only if view is not present
Use ‘CREATE OR REPLACE VIEW’ so that no error/warning should throw if view is already present if view might have to handle more than 50k records.
Out of these 2 options, which options is better & recommended approach?

If you must know whether the view existed before your operation, using the information schema is helpful.
Otherwise, CREATE OR REPLACE is much simpler. Your view definition can stand alone as a DDL statement.
The first option requires the server to process several queries, so it will take slightly longer than the second option. But view creation (in MySQL and MariaDB) is very fast: no actual data is retrieved until you use the view in a query.

So the VIEW contains an ever-growing UNION across many databases. So, the only way the VIEW would not exist is when two new users are updating the view 'simultaneously'.
Suggested workaround:
SELECT GET_LOCK('update_view');
DROP VIEW ...;
CREATE VIEW ...;
SELECT RELEASE_LOCK('update_view');
This avoids the need for OR REPLACE (etc), except for the very first time -- when the DROP VIEW will complain that the VIEW does not exist. That can be solved by creating a dummy VIEW when the machine is first configured.
(Study the parameters on GET_LOCK.)

Related

Save MySql 'Show' result in db

So I'm kind of stumped.
I have a MySql project that involves a database table that is being manipulated and altered by scripts on a regular basis. This isn't so unusual, but I need to automate a script to run (after hours, when changes aren't happening) that would save the result of the following:
SHOW CREATE TABLE [table-name];
This command generates the ready-to-run script that would create the (empty) table in it's current state.
In SqlWorkbench and Navicat it displays the result of this SHOW command in a field in a result set, as if it was the result of a SELECT statement.
Ideally, I want to take into a variable in a procedure, and change the table name; adding a '-mm-dd-yyyy' to end of it, so I could show the day-to-day changes in the table schema on an active server.
However, I can't seem to be able to do that. Unlike a Select result set, I can't use it like that. I can't get it in a variable, or save it to a temporary, or physical table or anything. I even tried to return this as a value in a function, from which I got the error that a function cannot return a result set - which explains why it's displayed like one in the db clients.
I suspect that this is a security thing in MySql? If so, I can totally understand why and see the dangers exposed to a hacker, but this isn't a public-facing box at all, and I have full root/admin access to it. Hopefully somebody has already tackled this problem before.
This is on MySql 8, btw.
[Edit] After my first initial comments, I need to add; I'm not concerned about the data with this question whatsoever, but rather just these schema changes.
What I'd really -like- to do is this:
SELECT `Create Table` FROM ( SHOW CREATE TABLE carts )
But this seems to be mixing apples and oranges, as SHOW and SELECT aren't created equal, although they both seem to return the same sort of object
You cannot do it in the MySQL stored procedure language.
https://dev.mysql.com/doc/refman/8.0/en/show.html says:
Many MySQL APIs (such as PHP) enable you to treat the result returned from a SHOW statement as you would a result set from a SELECT; see Chapter 29, Connectors and APIs, or your API documentation for more information. In addition, you can work in SQL with results from queries on tables in the INFORMATION_SCHEMA database, which you cannot easily do with results from SHOW statements. See Chapter 26, INFORMATION_SCHEMA Tables.
What is absent from this paragraph is any mention of treating the results of SHOW commands like the results of SELECT queries in other contexts. There is no support for setting a variable to the result of a SHOW command, or using INTO, or running SHOW in a subquery.
So you can capture the result returned by a SHOW command in a client programming language (Java, Python, PHP, etc.), and I suggest you do this.
In theory, all the information used by SHOW CREATE TABLE is accessible in the INFORMATION_SCHEMA tables (mostly TABLES and COLUMNS), but formatting a complete CREATE TABLE statement is a non-trivial exercise, and I wouldn't attempt it. For one thing, there are new features in every release of MySQL, e.g. new data types and table options, etc. So even if you could come up with the right query to produce this output, in a couple of years it would be out of date and it would be a thankless code maintenance chore to update it.
The closest solution I can think of, in pure MySQL, is to regularly clone the table structure (no data), like so:
CREATE TABLE backup_20220618 LIKE my_table;
As far as I know, to get your hands on the full explicit CREATE TABLE statement, as a string, would require the use of an external tool like mysqldump which was designed specifically for that purpose.

Getting SHOW CREATE TABLE from a view, as if it were a table

I have access to a remote database, and I would like to dump the schema and data of several views onto my local machine and load this into my local database as tables in a quick and easy way.
I lack the user privileges to run CREATE TABLE AS (SELECT * FROM target_view), otherwise this would be trivial to solve. In other words, I want to retrieve and recreate the "composite" schema of target_view as if it were a table.
I do not want the output of SHOW CREATE VIEW, as this only shows a complex SELECT statement with joins to various tables on remote I have limited ability to access. And a problem I'm seeing in MySQL 8.x is when I run SHOW CREATE TABLE on the view, this command simply acts as an alias of SHOW CREATE VIEW (which is reasonable).
Frustratingly, I can run DESCRIBE and see the schema of these views as they were tables. I really just need to convert this information into a CREATE TABLE statement without actually being able to run CREATE TABLE.
In case it weren't obvious, the key is to avoid manual reconstruction of these views' tabular schemas (as they may change in the future). I also want to avoid the solution of reverse engineering a generic table construction of 20-30 generic VARCHAR or TEXT columns from a CSV dump.
I don't know of any way to display the metadata of a result set in CREATE TABLE syntax.
What I would do given your circumstance is first create on your local MySQL instance the base table and the view, then you can use the CREATE TABLE AS SELECT ... syntax to produce a concrete table to match the metadata of the view result set.

Mysql Query match to check if query has been updated

I am trying to match two MySQL Queries (for now, the target is "Create VIEW") to analyze if the result of execution would result in the same effect to Database.
The source of the queries is not the same, making the syntax across the queries inconsistent.
To further simplify the question, let me add more details:
Let's say there is an already existing View in the database.
This View was created using a Create VIEW ... SQL statement.
There is a possibility that the Create VIEW ... statement get's updated, hence to reflect the changes in the database currently this statement is executed at the time of migration.
But, I want to avoid this situation, if the statement Create VIEW ... will result in the same structure as of the existing View in the database, I want to avoid executing it.
To generate the CREATE VIEW from database I am using SHOW CREATE VIEW... (comparing this with the query originally used to create the VIEW).
The primary restriction is I need to make this decision only at the time of migration and cannot presume any conclusions (say, using git diff or commit history...).
I have already done some search to look for a solution for this:
Found no direct solution for this problem (like a SQL engine to which I can feed both queries and know if the result would be the same).
Decided to Parse the queries and to achieve that ended up looking into ANTLR (also used by MYSQL WorkBench)
ANTLR's approach looks promising but, this will require an extensive rule-based parsing and creating a query match program from scratch.
I realized that just parsing queries is not enough, I have to create my own POJOs to store the atomic lexers from queries and then compare the queries based on some rules.
Even if I could find predefined POJOs, that would allow to quickly create a solution for this problem.

Access query runs on table that does not exist in database

I would like to recreate a few existing Access queries in a new database so that I can tweak them a bit. The problem I am running into is that some of the tables being queried do not seem to exist in the current database. These tables all end with a 1.
For example, INV_MTL_ITEM_LOCATIONS is an imported table in the database, but
INV_MTL_ITEM_LOCATIONS_1 is being queried even though it does not show up in the tables panel on the left.
Is this some type of duplication functionality that I am not aware of? The query runs without any errors.
No, the query runs on an aliased table. It's actually just querying INV_MTL_ITEM_LOCATIONS
Using SQL, you can create an alias for a table. This is especially useful when querying the same table twice in one query, but also commonly used to shorten queries.
Your query will probably look something like this:
SELECT something
FROM INV_MTL_ITEM_LOCATIONS AS INV_MTL_ITEM_LOCATIONS_1
Access automatically creates these aliases when using the query builder and if you add the same table more than once. When removing the non-aliased table, the other one stays aliased.
This is entirely normal, and as far as I know, never a problem.
Erik's answer explains it perfectly.
But to be exhaustive, you CAN actually create a query on a table that is NOT in the current database (nor a linked table).
Here is an example:
SELECT *
FROM History IN 'c:\test\mySecretBackend.accdb'
You can also create that in design view, just by
setting the query's Source Database property to c:\test\mySecretBackend.accdb
click on Show table

What is the best way to filter a multi-tenant MySQL database?

In MySQL I have a single database with one schema. In Microsoft Sql Server it is recommended to use a "Tenant View Filter" so in Microsoft Sql Server this gives me exactly what I need.
CREATE VIEW TenantEmployees AS
SELECT * FROM Employees WHERE TenantID = SUSER_SID()
What is the best way to accomplish the same in MySQL? An equivalent to the "Tenant View Filter" will work if it is performs well.
Thanks!!
The query you suggest (that I could find in MSDN) has text afterwards that explains exactly what are its assumptions. In particular, it mentions that it assumes that the "owner" of a row in the Employees table is specified in the TenantID field that is populated according to the SID of the user(s) you are partitioning for.
What that means is that you can replicate the same idea whatever way you decide to implement your data as long as you have clearly defined partitions of the data and know exactly how to associate it with the table you are creating a view for.
In particular, if you configure your system so that each partition accesses the DB with its own credentials, you could use the CURRENT_USER or USER constructs of MySQL as the IDs defining your partitions and the query to create the view would be basically the same as the one suggested in MSDN replacing SUSER_ID with CURRENT_USER.
But if you use the same user to access from all the partitions, then the suggested method is irrelevant on either database server.
Since you need to use your tenantId value to perform filtering, a table valued user defined function would be ideal, as a view normally does not accept parameters. Unfortunately, unlike many other database products MySQL doesn't support table-valued functions. However, there are MySQL hacks that claim to emulate parametrized views. These could be useful for you.
It's a little tricky in MySQL, but it can be done:
CREATE OR REPLACE VIEW {viewName}
AS
SELECT {fieldListWithoutTenantID}
FROM {tableName}
WHERE (id_tenant = SUBSTRING_INDEX(USER( ),'#',1))
I wrote up a full blog post on how I converted a single-tenant MySQL application to multi-tenant in one weekend with minimal changes. https://opensource.io/it/mysql-multi-tenant/