Is it safe to use select * in views? - mysql

I've grown quite fond of the usefulness of CREATE VIEW. It for instance allows me to have global and specific values through COALESCE(post.publish, profile.publish) so that if publish is NULL, the global value gets fetched instead.
The part I'm a bit curious about from both perfomance and logical perspective, is how I should use this alongside the existing table. Lets say I have a table:
CREATE TABLE post (
id INT,
profile_id INT,
name VARCHAR,
publish ENUM('TRUE', 'FALSE') NULL
)
Would a CREATE VIEW be best to run like:
CREATE VIEW post_info AS
SELECT post.*, COALESCE(post.publish, profile.publish) AS publish
FROM post
INNER JOIN profile
ON post.profile_id = profile.id
And only use post_info in SELECT cases, or:
CREATE VIEW post_info AS
SELECT post.id, COALESCE(post.publish, profile.publish) AS publish
FROM post
INNER JOIN profile
ON post.profile_id = profile.id
And JOIN post_info with post in SELECT when extra values are needed?
Please share your insights and thoughs regarding this. I would like to hear your input to positives and drawbacks of each solution. Can also be one I haven't mentioned.

It really depends on how you will use the views. It should be worth mentioning that there are two methods MySQL can process a query that refers to a view, and the method used depends on the view declaration's ALGORITHM clause.
For the lack of a better phrasing, I will reproduce the manual:
For [ALGORITHM =] MERGE, the text of a statement that refers to the view and the
view definition are merged such that parts of the view definition
replace corresponding parts of the statement.
For TEMPTABLE, the results from the view are retrieved into a
temporary table, which then is used to execute the statement.
For UNDEFINED, MySQL chooses which algorithm to use.
The MERGE algorithm usually allows faster processing of the final query, however there are many cases where MySQL is unable to use it (see the linked manual page for more details).
So the answer is: if your view is not defined with ALGORITHM = TEMPTABLE and if the wrapping query does not prevent the use of the MERGE algorithm, the version with SELECT *, and without an extra JOIN, is better.
Otherwise, if MERGE is not used, the second solution could be better.
As a side note, to adress the use case you mention, a better option would be to have your application layer fill the post.publish with the value in profile.publish at insertion time, and get rid of the JOIN as well as the view. Alternatively, the same effect can be achieved by placing a suitable trigger on the table.

Related

How to give table an alternative name in MySQL?

I want to use a table that would be accessible under two names (something like e-mail address alias) i.e. I want queries:
select * from my_table_name
and
select * from my_alt_table_name
return records from the same table.
I know I can use a view and then run query on view, but wouldn't it be less efficient?
I know I can use a view and then run query on view, but wouldn't it be less efficient?
If the view is strictly SELECT * FROM table, without any additions (WHERE and so on), then there is no difference does you use the table or the view as an alias.
See small DEMO.
See SHOW WARNING outputs - they claims that the server is smart enough for to understand that it may/must use the table itself.
See EXPLAIN outputs - they claims that the server is smart enough for to understand that it may/must use the index which is present in the table structure.
expanded DEMO fiddle - analyse it by itself.
Also study CREATE VIEW Statement, ALGORITHM clause, and View Processing Algorithms. Try to add ALGORITHM = TEMPTABLE to DEMO and investigate the changes.
You can't have a table with multiple names, so yeah, just use views. There will be no impact on performance during the runtime, however during the compilation of the query, there will be just a small delay time for the compilation of the view to be transformed into a table in memory which is absolutely negligible
CREATE VIEW table_name_alias AS SELECT * FROM table_name;
SELECT * FROM table_name_alias;
Creating a view would look like this
CREATE VIEW my_alt_table_name AS SELECT * FROM my_table_name;
and next time you can use it like this
SELECT * FROM my_alt_table_name ;

SQL Filtering and Replacing

I have a few tables in SQL that require content filtering, primarily for profanity. I want to allow my application(s) to insert data they want and have the server replace any profanity with asterisks such that I do not need to implement filtering on a variety of platforms.
I know triggers could be used for future, however, I am trying to determine the most efficient way to complete this task.
Here are some details:
There are 2 tables I need to ensure has content filtering as they are public facing: feedback and users. Here are the particular fields:
Table -> Fields
Feedback -> Subject, Message
Users -> Firstname, Lastname, Alias
I am relatively new to MySQL and know that having a table of values to replace may be the easiest-to-modify option.
My question is:
How would I join 2 tables and replace particular chars with asterisks using key words located in a third table?
I have these queries so far to locate the columns of interest, just not sure how to incorporate the replacement function and the ability to check both at the same time:
SELECT u.firstname, u.lastname, u.username FROM users u, feedback f, terms t;
SELECT f.subject, f.message FROM feedback f;
You are better off creating a new column (named alias or similar) and storing values with asterisks in there than writing a SELECT query and performing find-replace. Following are the advantages:
Handling this scenario in trigger means you will only perform this operation when a record gets inserted or updated, whereas in SELECT query, each read will need replacing.
You can't really use join here because (a) each value of feedback and user table needs to be compared with all the values of terms table and (b) this needs to be performed for all the columns that might contain these words. So, it's more of a use case for cursor than join.

SQL Left/Inner/Normal Join vs Where while conditional statement

I am relatively new to the SQL programming, so please go easy on me.
I am currently writing a query, which would output the result based on the value from one of the outer parameters. The structure is currently looking like following:
#ShowEntireCategory bit = 0
select distinct
p.pk
p.name
--other columns
from dbo.Project P
--bunch of left joins
where p.Status = 'Open'
--other conditions
What I am trying to implement is: when the value of ShowEntireCategory is 1 (changed programmatically through radiobutton selection) it will show records of all subcategories, which are inside of the the category. When it is 0, it will only show records from the selected subcategory, while other subcategories in that category remains untouched.
I have been performing a research on the best approach, and it narrowed down to either WHERE statements or JOINs.
What I want to know is: which of these approaches I should use for my scenario? In my case the priority is optimization (minimum time to execute) and ease of implementation.
NOTE: My main goal here is not to receive a ready to use code here (though an example code snippets would be welcome), I just want to know a better approach, so I can continue researching in that direction.
Thank you in advance!
UPDATE
I have performed additional research on the database structure, and managed to narrow down to parameters relevant to the question
One is dbo.Project table, which contains: PK, CategoryKey (FK) (connected to the one in second table), Name, Description, and all other parameters which are irrelevant.
Second one is dbo.Area table, which contains: PK, AreaNumber, Name, CategoryKey (FK), IsCategory (1 = is category, 0 = not category).
Sorry, but I work in fast-paced environment, this is as much as I was able to squeeze. Please let me know if it is not enough.
With the information you provided the best solution would be to use a combination of WHERE clauses and JOINS. You would likely need to use a WHERE clause on the second table (described in the update) to select all rows which are categories. Then, you would JOIN this result with your other tables/data. Finally, you can use a CASE clause (details found here) to check your variable and determine if you need all categories or just some (which can be dealt with through an additional WHERE clause).
Not sure this entirely answers your question, but for a more detailed answer we would need a more detailed description of the database schema.

Mysql: query not giving accurate result with IN clause and inner query

I'm trying to get zip codes from zip_id's which are internally stored in companies service table below screens will give you clear idea
I have wrote this query
companies service table
Please suggest me your valuable views . Thanks in advance.
As already mentioned your database scheme is not very well designed, it violates even 1st normal form. You'd need another table where you'd store serv_area_id and zip_code (with possibly multiple rows for a signle serv_area_id) and search within this table and eventually join your original table.
Nevertheless, in order to get the result you describe you cannot use the IN operator as it operates on a value and multiple values in a form of table (either explicit via nested SELECT or enumeration literal (val1, ..., valN)). I would try some string matching as illustrated below. However, consider it rather an ugly hack than correct solution(!)
SELECT zip FROM cities_extended WHERE (
SELECT GROUP_CONCAT(',', serv_are_zipcodes)
FROM company_service_areas WHERE ...
) LIKE concat('%(', id, ')%')

MySql - Select * from 2 tables, but Prefix Table Names in the Resultset?

I'd like to select * from 2 tables, but have each table's column name be prefixed with a string, to avoid duplicate column name collissions.
For example, I'd like to have a view like so:
CREATE VIEW view_user_info as (
SELECT
u.*,
ux.*
FROM
user u,
user_ex ux
);
where the results all had each column prefixed with the name of the table:
e.g.
user_ID
user_EMAIL
user_ex_ID
user_ex_TITLE
user_ex_SIN
etc.
I've put a sql fiddle here that has the concept, but not the correct syntax of course (if it's even possible).
I'm using MySql, but would welcome generic solutions if they exist!
EDIT: I am aware that I could alias each of the fields, as mentioned in one of the comments. That's what I'm currently doing, but I find at the start of a project I keep having to sync up my tables and views as they change. I like the views to have everything in them from each table, and then I manually select out what I need. Kind of a lazy approach, but this would allow me to iterate quicker, and only optimize when it's needed.
I find at the start of a project I keep having to sync up my tables and views as they change.
Since the thing you're trying to do is not really supported by standard SQL, and you keep modifying database structures in development, I wonder if your best approach would be to write a little script that recreates that SELECT statement for you. Maybe wrap it in a method call in the development language of your choice?
Essentially you'd need to query INFORMATION_SCHEMA for the tables and columns of interest, probably via a join, and write the results out in SQL style.
Then just run the script every time you make database structural changes that are important to you, and watch your code magically keep up.